diff --git a/Makefile b/Makefile index 44e15a2db32d..1d9cd422c2cf 100644 --- a/Makefile +++ b/Makefile @@ -98,4 +98,4 @@ test: test-tools # $5 - output # It will generate targets {update,verify}-bindata-$(1) logically grouping them in unsuffixed versions of these targets # and also hooked into {update,verify}-generated for broader integration. -$(call add-bindata,bindata,-ignore ".*\.(go|md)$\" examples/db-templates examples/image-streams examples/sample-app examples/quickstarts/... examples/hello-openshift examples/jenkins/... examples/quickstarts/cakephp-mysql.json test/extended/testdata/... test/integration/testdata,testextended,testdata,test/extended/testdata/bindata.go) +$(call add-bindata,bindata,-ignore ".*\.(go|md)$\" examples/db-templates examples/image-streams examples/sample-app examples/quickstarts/... examples/hello-openshift examples/jenkins/... examples/quickstarts/cakephp-mysql.json test/extended/testdata/...,testextended,testdata,test/extended/testdata/bindata.go) diff --git a/OWNERS b/OWNERS index c16d49deb2c1..29b935156a6c 100644 --- a/OWNERS +++ b/OWNERS @@ -8,7 +8,6 @@ filters: - sjenning - smarterclayton - soltysh - - tbielawa approvers: - bparees - deads2k @@ -21,7 +20,6 @@ filters: - soltysh - sttts - smarterclayton - - tbielawa # also for build and automated release tooling changes "^\\.go.(mod|sum)$": labels: - "vendor-update" diff --git a/README.md b/README.md index 83b3748bee0b..a083e8b6411e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Origin Kubernetes This repo was previously the core Kubernetes tracking repo for [OKD](https://github.com/openshift/okd), and where OpenShift's `hyperkube` and `openshift-test` binaries were maintained. As of July -2020, the purpose and maintenance stratety of the repo varies by +2020, the purpose and maintenance strategy of the repo varies by branch. ## Maintenance of `master` and `release-x.x` branches for 4.6 and above diff --git a/cmd/openshift-tests/cni.go b/cmd/openshift-tests/cni.go new file mode 100644 index 000000000000..c0c61595a942 --- /dev/null +++ b/cmd/openshift-tests/cni.go @@ -0,0 +1,23 @@ +package main + +import ( + "strings" +) + +// Determines whether a test should be run for third-party network plugin conformance testing +func inCNISuite(name string) bool { + if strings.Contains(name, "[Suite:k8s]") && strings.Contains(name, "[sig-network]") { + // Run all upstream sig-network conformance tests + if strings.Contains(name, "[Conformance]") { + return true + } + // Run all upstream NetworkPolicy tests except named port tests. (Neither + // openshift-sdn nor ovn-kubernetes supports named ports in NetworkPolicy, + // so we don't require third party tests to support them either.) + if strings.Contains(name, "NetworkPolicy") && !strings.Contains(name, "named port") { + return true + } + } + + return false +} diff --git a/cmd/openshift-tests/csi.go b/cmd/openshift-tests/csi.go index dda4900f9173..79e512a054a8 100644 --- a/cmd/openshift-tests/csi.go +++ b/cmd/openshift-tests/csi.go @@ -8,39 +8,14 @@ import ( "k8s.io/kubernetes/test/e2e/framework/testfiles" "k8s.io/kubernetes/test/e2e/storage/external" - - "github.com/openshift/origin/test/extended/csi" ) const ( - manifestEnvVar = "TEST_CSI_DRIVER_FILES" - installDriversEnvVar = "TEST_INSTALL_CSI_DRIVERS" + manifestEnvVar = "TEST_CSI_DRIVER_FILES" ) // Initialize openshift/csi suite, i.e. define CSI tests from TEST_CSI_DRIVER_FILES. func initCSITests(dryRun bool) error { - driverList := os.Getenv(installDriversEnvVar) - if driverList != "" { - drivers := strings.Split(driverList, ",") - for _, driver := range drivers { - manifestFile, err := csi.InstallCSIDriver(driver, dryRun) - if err != nil { - return fmt.Errorf("failed to install CSI driver from %q: %s", driver, err) - } - // Children processes need to see the newly introduced manifest, - // store it in TEST_CSI_DRIVER_FILES env. var for them. - manifestList := os.Getenv(manifestEnvVar) - if len(manifestList) > 0 { - manifestList += "," - } - manifestList += manifestFile - os.Setenv(manifestEnvVar, manifestList) - } - } - - // Clear TEST_INSTALL_CSI_DRIVERS, we don't want the driver installed by children too. - os.Setenv(installDriversEnvVar, "") - manifestList := os.Getenv(manifestEnvVar) if manifestList != "" { manifests := strings.Split(manifestList, ",") diff --git a/cmd/openshift-tests/e2e.go b/cmd/openshift-tests/e2e.go index b969428c4068..111ab55a702c 100644 --- a/cmd/openshift-tests/e2e.go +++ b/cmd/openshift-tests/e2e.go @@ -1,193 +1,679 @@ package main import ( + "fmt" "strings" "time" "k8s.io/kubectl/pkg/util/templates" + "github.com/openshift/origin/pkg/monitor" "github.com/openshift/origin/pkg/test/ginkgo" _ "github.com/openshift/origin/test/extended" + exutil "github.com/openshift/origin/test/extended/util" _ "github.com/openshift/origin/test/extended/util/annotate/generated" + "github.com/openshift/origin/test/extended/util/disruption" ) +func isDisabled(name string) bool { + return strings.Contains(name, "[Disabled") +} + +type testSuite struct { + ginkgo.TestSuite + + PreSuite func(opt *runOptions) error + PostSuite func(opt *runOptions) + + PreTest func() error +} + +type testSuites []testSuite + +func (s testSuites) TestSuites() []*ginkgo.TestSuite { + copied := make([]*ginkgo.TestSuite, 0, len(s)) + for i := range s { + copied = append(copied, &s[i].TestSuite) + } + return copied +} + // staticSuites are all known test suites this binary should run -var staticSuites = []*ginkgo.TestSuite{ +var staticSuites = testSuites{ { - Name: "openshift/conformance", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "openshift/conformance", + Description: templates.LongDesc(` Tests that ensure an OpenShift cluster and components are working properly. `), - Matches: func(name string) bool { - return strings.Contains(name, "[Suite:openshift/conformance/") + Matches: func(name string) bool { + if isDisabled(name) { + return false + } + return strings.Contains(name, "[Suite:openshift/conformance/") + }, + Parallelism: 30, + SyntheticEventTests: ginkgo.JUnitForEventsFunc(stableSystemEventInvariants), }, - Parallelism: 30, + PreSuite: suiteWithProviderPreSuite, }, { - Name: "openshift/conformance/parallel", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "openshift/conformance/parallel", + Description: templates.LongDesc(` Only the portion of the openshift/conformance test suite that run in parallel. `), - Matches: func(name string) bool { - return strings.Contains(name, "[Suite:openshift/conformance/parallel") + Matches: func(name string) bool { + if isDisabled(name) { + return false + } + return strings.Contains(name, "[Suite:openshift/conformance/parallel") + }, + Parallelism: 30, + MaximumAllowedFlakes: 15, + SyntheticEventTests: ginkgo.JUnitForEventsFunc(stableSystemEventInvariants), }, - Parallelism: 30, - MaximumAllowedFlakes: 15, + PreSuite: suiteWithProviderPreSuite, }, { - Name: "openshift/conformance/serial", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "openshift/conformance/serial", + Description: templates.LongDesc(` Only the portion of the openshift/conformance test suite that run serially. `), - Matches: func(name string) bool { - return strings.Contains(name, "[Suite:openshift/conformance/serial") + Matches: func(name string) bool { + if isDisabled(name) { + return false + } + return strings.Contains(name, "[Suite:openshift/conformance/serial") || isStandardEarlyOrLateTest(name) + }, + SyntheticEventTests: ginkgo.JUnitForEventsFunc(stableSystemEventInvariants), }, + PreSuite: suiteWithProviderPreSuite, }, { - Name: "openshift/disruptive", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "openshift/disruptive", + Description: templates.LongDesc(` The disruptive test suite. `), - Matches: func(name string) bool { - return strings.Contains(name, "[Feature:EtcdRecovery]") || strings.Contains(name, "[Feature:NodeRecovery]") + Matches: func(name string) bool { + if isDisabled(name) { + return false + } + // excluded due to stopped instance handling until https://bugzilla.redhat.com/show_bug.cgi?id=1905709 is fixed + if strings.Contains(name, "Cluster should survive master and worker failure and recover with machine health checks") { + return false + } + return strings.Contains(name, "[Feature:EtcdRecovery]") || strings.Contains(name, "[Feature:NodeRecovery]") || isStandardEarlyTest(name) + + }, + TestTimeout: 60 * time.Minute, + SyntheticEventTests: ginkgo.JUnitForEventsFunc(systemEventInvariants), }, - TestTimeout: 60 * time.Minute, }, { - Name: "kubernetes/conformance", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "kubernetes/conformance", + Description: templates.LongDesc(` The default Kubernetes conformance suite. `), - Matches: func(name string) bool { - return strings.Contains(name, "[Suite:k8s]") && strings.Contains(name, "[Conformance]") + Matches: func(name string) bool { + if isDisabled(name) { + return false + } + return strings.Contains(name, "[Suite:k8s]") && strings.Contains(name, "[Conformance]") + }, + Parallelism: 30, + SyntheticEventTests: ginkgo.JUnitForEventsFunc(stableSystemEventInvariants), }, - Parallelism: 30, + PreSuite: suiteWithProviderPreSuite, }, { - Name: "openshift/build", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "openshift/build", + Description: templates.LongDesc(` Tests that exercise the OpenShift build functionality. `), - Matches: func(name string) bool { - return !strings.Contains(name, "[Disabled") && strings.Contains(name, "[Feature:Builds]") + Matches: func(name string) bool { + if isDisabled(name) { + return false + } + return strings.Contains(name, "[Feature:Builds]") || isStandardEarlyOrLateTest(name) + }, + Parallelism: 7, + // TODO: Builds are really flaky right now, remove when we land perf updates and fix io on workers + MaximumAllowedFlakes: 3, + // Jenkins tests can take a really long time + TestTimeout: 60 * time.Minute, + SyntheticEventTests: ginkgo.JUnitForEventsFunc(stableSystemEventInvariants), }, - Parallelism: 7, - // TODO: Builds are really flaky right now, remove when we land perf updates and fix io on workers - MaximumAllowedFlakes: 3, - // Jenkins tests can take a really long time - TestTimeout: 60 * time.Minute, }, { - Name: "openshift/templates", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "openshift/templates", + Description: templates.LongDesc(` Tests that exercise the OpenShift template functionality. `), - Matches: func(name string) bool { - return !strings.Contains(name, "[Disabled") && strings.Contains(name, "[Feature:Templates]") + Matches: func(name string) bool { + if isDisabled(name) { + return false + } + return strings.Contains(name, "[Feature:Templates]") || isStandardEarlyOrLateTest(name) + }, + Parallelism: 1, + SyntheticEventTests: ginkgo.JUnitForEventsFunc(stableSystemEventInvariants), }, - Parallelism: 1, }, { - Name: "openshift/image-registry", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "openshift/image-registry", + Description: templates.LongDesc(` Tests that exercise the OpenShift image-registry functionality. `), - Matches: func(name string) bool { - return strings.Contains(name, "[sig-imageregistry]") && !strings.Contains(name, "[Local]") + Matches: func(name string) bool { + if isDisabled(name) || strings.Contains(name, "[Local]") { + return false + } + return strings.Contains(name, "[sig-imageregistry]") || isStandardEarlyOrLateTest(name) + }, + SyntheticEventTests: ginkgo.JUnitForEventsFunc(stableSystemEventInvariants), }, }, { - Name: "openshift/image-ecosystem", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "openshift/image-ecosystem", + Description: templates.LongDesc(` Tests that exercise language and tooling images shipped as part of OpenShift. `), - Matches: func(name string) bool { - return strings.Contains(name, "[Feature:ImageEcosystem]") && !strings.Contains(name, "[Local]") + Matches: func(name string) bool { + if isDisabled(name) || strings.Contains(name, "[Local]") { + return false + } + return strings.Contains(name, "[Feature:ImageEcosystem]") || isStandardEarlyOrLateTest(name) + }, + Parallelism: 7, + TestTimeout: 20 * time.Minute, + SyntheticEventTests: ginkgo.JUnitForEventsFunc(stableSystemEventInvariants), }, - Parallelism: 7, - TestTimeout: 20 * time.Minute, }, { - Name: "openshift/jenkins-e2e", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "openshift/jenkins-e2e", + Description: templates.LongDesc(` Tests that exercise the OpenShift / Jenkins integrations provided by the OpenShift Jenkins image/plugins and the Pipeline Build Strategy. `), - Matches: func(name string) bool { - return strings.Contains(name, "[Feature:Jenkins]") + Matches: func(name string) bool { + if isDisabled(name) { + return false + } + return strings.Contains(name, "[Feature:Jenkins]") || isStandardEarlyOrLateTest(name) + }, + Parallelism: 4, + TestTimeout: 20 * time.Minute, + SyntheticEventTests: ginkgo.JUnitForEventsFunc(stableSystemEventInvariants), }, - Parallelism: 4, - TestTimeout: 20 * time.Minute, }, { - Name: "openshift/jenkins-e2e-rhel-only", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "openshift/jenkins-e2e-rhel-only", + Description: templates.LongDesc(` Tests that exercise the OpenShift / Jenkins integrations provided by the OpenShift Jenkins image/plugins and the Pipeline Build Strategy. `), - Matches: func(name string) bool { - return strings.Contains(name, "[Feature:JenkinsRHELImagesOnly]") + Matches: func(name string) bool { + if isDisabled(name) { + return false + } + return strings.Contains(name, "[Feature:JenkinsRHELImagesOnly]") || isStandardEarlyOrLateTest(name) + }, + Parallelism: 4, + TestTimeout: 20 * time.Minute, + SyntheticEventTests: ginkgo.JUnitForEventsFunc(stableSystemEventInvariants), }, - Parallelism: 4, - TestTimeout: 20 * time.Minute, - }, { - Name: "openshift/scalability", - Description: templates.LongDesc(` + PreSuite: suiteWithProviderPreSuite, + }, + { + TestSuite: ginkgo.TestSuite{ + Name: "openshift/scalability", + Description: templates.LongDesc(` Tests that verify the scalability characteristics of the cluster. Currently this is focused on core performance behaviors and preventing regressions. `), - Matches: func(name string) bool { - return strings.Contains(name, "[Suite:openshift/scalability]") + Matches: func(name string) bool { + if isDisabled(name) { + return false + } + return strings.Contains(name, "[Suite:openshift/scalability]") + }, + Parallelism: 1, + TestTimeout: 20 * time.Minute, }, - Parallelism: 1, - TestTimeout: 20 * time.Minute, + PreSuite: suiteWithProviderPreSuite, }, { - Name: "openshift/conformance-excluded", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "openshift/conformance-excluded", + Description: templates.LongDesc(` Run only tests that are excluded from conformance. Makes identifying omitted tests easier. `), - Matches: func(name string) bool { return !strings.Contains(name, "[Suite:openshift/conformance/") }, + Matches: func(name string) bool { + if isDisabled(name) { + return false + } + return !strings.Contains(name, "[Suite:openshift/conformance/") + }, + SyntheticEventTests: ginkgo.JUnitForEventsFunc(stableSystemEventInvariants), + }, + PreSuite: suiteWithProviderPreSuite, }, { - Name: "openshift/test-cmd", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "openshift/test-cmd", + Description: templates.LongDesc(` Run only tests for test-cmd. `), - Matches: func(name string) bool { return strings.Contains(name, "[Feature:LegacyCommandTests]") }, + Matches: func(name string) bool { + if isDisabled(name) { + return false + } + return strings.Contains(name, "[Feature:LegacyCommandTests]") || isStandardEarlyOrLateTest(name) + }, + SyntheticEventTests: ginkgo.JUnitForEventsFunc(stableSystemEventInvariants), + }, }, { - Name: "openshift/csi", - Description: templates.LongDesc(` - Run tests for an CSI driver. Set the TEST_INSTALL_CSI_DRIVERS environment variable to the name of the driver to load. - For example, TEST_INSTALL_CSI_DRIVERS=aws-ebs will test the AWS EBS CSI driver. To change the location of the images, - specify IMAGE_FORMAT=myregistry.com/myrepository/${component}:4.5 where ${component} will be substituted with the - names of required CSI component images: - - csi-external-attacher, csi-external-provisioner, csi-external-resizer, - csi-external-snapshotter, csi-node-driver-registrar, csi-livenessprobe - - See https://github.com/kubernetes/kubernetes/blob/master/test/e2e/storage/external/README.md for required format of the files. + TestSuite: ginkgo.TestSuite{ + Name: "openshift/csi", + Description: templates.LongDesc(` + Run tests for an CSI driver. Set the TEST_CSI_DRIVER_FILES environment variable to the name of file with + CSI driver test manifest. The manifest specifies Kubernetes + CSI features to test with the driver. + See https://github.com/kubernetes/kubernetes/blob/master/test/e2e/storage/external/README.md for required format of the file. `), - Matches: func(name string) bool { - return strings.Contains(name, "External Storage [Driver:") && !strings.Contains(name, "[Disruptive]") + Matches: func(name string) bool { + if isDisabled(name) { + return false + } + return strings.Contains(name, "External Storage [Driver:") && !strings.Contains(name, "[Disruptive]") + }, + SyntheticEventTests: ginkgo.JUnitForEventsFunc(stableSystemEventInvariants), + }, + PreSuite: suiteWithKubeTestInitializationPreSuite, + PostSuite: func(opt *runOptions) { + printStorageCapabilities(opt.Out) }, }, { - Name: "openshift/network/stress", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "openshift/network/stress", + Description: templates.LongDesc(` This test suite repeatedly verifies the networking function of the cluster in parallel to find flakes. `), - Matches: func(name string) bool { - return strings.Contains(name, "[Suite:openshift/conformance/") && strings.Contains(name, "[sig-network]") + Matches: func(name string) bool { + if isDisabled(name) { + return false + } + return (strings.Contains(name, "[Suite:openshift/conformance/") && strings.Contains(name, "[sig-network]")) || isStandardEarlyOrLateTest(name) + }, + Parallelism: 30, + Count: 15, + TestTimeout: 20 * time.Minute, + SyntheticEventTests: ginkgo.JUnitForEventsFunc(stableSystemEventInvariants), + }, + PreSuite: suiteWithProviderPreSuite, + }, + { + TestSuite: ginkgo.TestSuite{ + Name: "openshift/network/third-party", + Description: templates.LongDesc(` + The conformance testing suite for certified third-party CNI plugins. + `), + Matches: func(name string) bool { + if isDisabled(name) { + return false + } + return inCNISuite(name) + }, }, - Parallelism: 30, - Count: 15, - TestTimeout: 20 * time.Minute, + PreSuite: suiteWithProviderPreSuite, }, { - Name: "all", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "all", + Description: templates.LongDesc(` Run all tests. `), - Matches: func(name string) bool { return true }, + Matches: func(name string) bool { + return true + }, + }, }, } + +// isStandardEarlyTest returns true if a test is considered part of the normal +// pre or post condition tests. +func isStandardEarlyTest(name string) bool { + if !strings.Contains(name, "[Early]") { + return false + } + return strings.Contains(name, "[Suite:openshift/conformance/parallel") +} + +// isStandardEarlyOrLateTest returns true if a test is considered part of the normal +// pre or post condition tests. +func isStandardEarlyOrLateTest(name string) bool { + if !strings.Contains(name, "[Early]") && !strings.Contains(name, "[Late]") { + return false + } + return strings.Contains(name, "[Suite:openshift/conformance/parallel") +} + +// suiteWithProviderPreSuite ensures that the suite filters out tests from providers +// that aren't relevant (see getProviderMatchFn) by loading the provider info from the +// cluster or flags. +func suiteWithProviderPreSuite(opt *runOptions) error { + config, err := decodeProvider(opt.Provider, opt.DryRun, true) + if err != nil { + return err + } + opt.config = config + + opt.Provider = config.ToJSONString() + opt.MatchFn = getProviderMatchFn(config) + return nil +} + +// suiteWithKubeTestInitialization invokes the Kube suite in order to populate +// data from the environment for the CSI suite. Other suites should use +// suiteWithProviderPreSuite. +func suiteWithKubeTestInitializationPreSuite(opt *runOptions) error { + if err := suiteWithProviderPreSuite(opt); err != nil { + return err + } + return initializeTestFramework(exutil.TestContext, opt.config, opt.DryRun) +} + +const ( + // Max. duration of API server unreachability, in fraction of total test duration. + tolerateDisruptionPercent = 0.01 +) + +// stableSystemEventInvariants are invariants that should hold true when a cluster is in +// steady state (not being changed externally). Use these with suites that assume the +// cluster is under no adversarial change (config changes, induced disruption to nodes, +// etcd, or apis). +func stableSystemEventInvariants(events monitor.EventIntervals, duration time.Duration) (results []*ginkgo.JUnitTestCase, passed bool) { + tests, _ := systemEventInvariants(events, duration) + results = append(results, tests...) + results = append(results, testKubeAPIServerGracefulTermination(events)...) + results = append(results, testServerAvailability(monitor.LocatorKubeAPIServerNewConnection, events, duration)...) + results = append(results, testServerAvailability(monitor.LocatorOpenshiftAPIServerNewConnection, events, duration)...) + results = append(results, testServerAvailability(monitor.LocatorOAuthAPIServerNewConnection, events, duration)...) + results = append(results, testServerAvailability(monitor.LocatorKubeAPIServerReusedConnection, events, duration)...) + results = append(results, testServerAvailability(monitor.LocatorOpenshiftAPIServerReusedConnection, events, duration)...) + results = append(results, testServerAvailability(monitor.LocatorOAuthAPIServerReusedConnection, events, duration)...) + return results, true +} + +// systemEventInvariants are invariants tested against events that should hold true in any cluster, +// even one undergoing disruption. These are usually focused on things that must be true on a single +// machine, even if the machine crashes. +func systemEventInvariants(events monitor.EventIntervals, duration time.Duration) (results []*ginkgo.JUnitTestCase, passed bool) { + results = append(results, testPodTransitions(events)...) + results = append(results, testSystemDTimeout(events)...) + results = append(results, testPodSandboxCreation(events)...) + return results, true +} + +func testServerAvailability(locator string, events []*monitor.EventInterval, duration time.Duration) []*ginkgo.JUnitTestCase { + errDuration, errMessages := disruption.GetDisruption(events, locator) + + testName := fmt.Sprintf("[sig-api-machinery] %s should be available", locator) + successTest := &ginkgo.JUnitTestCase{ + Name: testName, + Duration: duration.Seconds(), + } + if percent := float64(errDuration) / float64(duration); percent > tolerateDisruptionPercent { + test := &ginkgo.JUnitTestCase{ + Name: testName, + Duration: duration.Seconds(), + FailureOutput: &ginkgo.FailureOutput{ + Output: fmt.Sprintf("%s was failing for %s seconds (%0.0f%% of the test duration)", locator, errDuration.Truncate(time.Second), 100*percent), + }, + SystemOut: strings.Join(errMessages, "\n"), + } + // Return *two* tests results to pretend this is a flake not to fail whole testsuite. + return []*ginkgo.JUnitTestCase{test, successTest} + } else { + successTest.SystemOut = fmt.Sprintf("%s was failing for %s seconds (%0.0f%% of the test duration)", locator, errDuration.Truncate(time.Second), 100*percent) + return []*ginkgo.JUnitTestCase{successTest} + } +} + +func testKubeAPIServerGracefulTermination(events []*monitor.EventInterval) []*ginkgo.JUnitTestCase { + const testName = "[sig-node] kubelet terminates kube-apiserver gracefully" + success := &ginkgo.JUnitTestCase{Name: testName} + + failures := []string{} + for _, event := range events { + // from https://github.com/openshift/kubernetes/blob/1f35e4f63be8fbb19e22c9ff1df31048f6b42ddf/cmd/watch-termination/main.go#L96 + if strings.Contains(event.Message, "did not terminate gracefully") { + failures = append(failures, fmt.Sprintf("%v - %v", event.Locator, event.Message)) + } + } + if len(failures) == 0 { + return []*ginkgo.JUnitTestCase{success} + } + + failure := &ginkgo.JUnitTestCase{ + Name: testName, + SystemOut: strings.Join(failures, "\n"), + FailureOutput: &ginkgo.FailureOutput{ + Output: fmt.Sprintf("%d kube-apiserver reports a non-graceful termination. Probably kubelet or CRI-O is not giving the time to cleanly shut down. This can lead to connection refused and network I/O timeout errors in other components.\n\n%v", len(failures), strings.Join(failures, "\n")), + }, + } + + // This should fail a CI run, not flake it. + return []*ginkgo.JUnitTestCase{failure} + +} + +func testPodTransitions(events []*monitor.EventInterval) []*ginkgo.JUnitTestCase { + const testName = "[sig-node] pods should never transition back to pending" + success := &ginkgo.JUnitTestCase{Name: testName} + + failures := []string{} + for _, event := range events { + if strings.Contains(event.Message, "pod should not transition") || strings.Contains(event.Message, "pod moved back to Pending") { + failures = append(failures, fmt.Sprintf("%v - %v", event.Locator, event.Message)) + } + } + if len(failures) == 0 { + return []*ginkgo.JUnitTestCase{success} + } + + failure := &ginkgo.JUnitTestCase{ + Name: testName, + SystemOut: strings.Join(failures, "\n"), + FailureOutput: &ginkgo.FailureOutput{ + Output: fmt.Sprintf("%d pods illegally transitioned to Pending\n\n%v", len(failures), strings.Join(failures, "\n")), + }, + } + + // TODO an upgrade job that starts before 4.6 may need to make this test flake instead of fail. This will depend on which `openshift-tests` + // is used to run that upgrade test. I recommend waiting to a flake until we know and even then find a way to constrain it. + return []*ginkgo.JUnitTestCase{failure} +} + +func testSystemDTimeout(events []*monitor.EventInterval) []*ginkgo.JUnitTestCase { + const testName = "[sig-node] pods should not fail on systemd timeouts" + success := &ginkgo.JUnitTestCase{Name: testName} + + failures := []string{} + for _, event := range events { + if strings.Contains(event.Message, "systemd timed out for pod") { + failures = append(failures, fmt.Sprintf("%v - %v", event.Locator, event.Message)) + } + } + if len(failures) == 0 { + return []*ginkgo.JUnitTestCase{success} + } + + failure := &ginkgo.JUnitTestCase{ + Name: testName, + SystemOut: strings.Join(failures, "\n"), + FailureOutput: &ginkgo.FailureOutput{ + Output: fmt.Sprintf("%d systemd timed out for pod occurrences\n\n%v", len(failures), strings.Join(failures, "\n")), + }, + } + + // write a passing test to trigger detection of this issue as a flake. Doing this first to try to see how frequent the issue actually is + return []*ginkgo.JUnitTestCase{failure, success} +} + +type testCategorizer struct { + by string + substring string +} + +func testPodSandboxCreation(events []*monitor.EventInterval) []*ginkgo.JUnitTestCase { + const testName = "[sig-network] pods should successfully create sandboxes" + // we can further refine this signal by subdividing different failure modes if it is pertinent. Right now I'm seeing + // 1. error reading container (probably exited) json message: EOF + // 2. dial tcp 10.0.76.225:6443: i/o timeout + // 3. error getting pod: pods "terminate-cmd-rpofb45fa14c-96bb-40f7-bd9e-346721740cac" not found + // 4. write child: broken pipe + bySubStrings := []testCategorizer{ + {by: " by reading container", substring: "error reading container (probably exited) json message: EOF"}, + {by: " by not timing out", substring: "i/o timeout"}, + {by: " by writing network status", substring: "error setting the networks status"}, + {by: " by getting pod", substring: " error getting pod: pods"}, + {by: " by writing child", substring: "write child: broken pipe"}, + {by: " by other", substring: " "}, // always matches + } + + failures := []string{} + flakes := []string{} + eventsForPods := getEventsByPod(events) + for _, event := range events { + if !strings.Contains(event.Message, "reason/FailedCreatePodSandBox Failed to create pod sandbox") { + continue + } + deletionTime := getPodDeletionTime(eventsForPods[event.Locator], event.Locator) + if deletionTime == nil { + // this indicates a failure to create the sandbox that should not happen + failures = append(failures, fmt.Sprintf("%v - never deleted - %v", event.Locator, event.Message)) + } else { + timeBetweenDeleteAndFailure := event.From.Sub(*deletionTime) + switch { + case timeBetweenDeleteAndFailure < 1*time.Second: + // nothing here, one second is close enough to be ok, the kubelet and CNI just didn't know + case timeBetweenDeleteAndFailure < 5*time.Second: + // withing five seconds, it ought to be long enough to know, but it's close enough to flake and not fail + flakes = append(failures, fmt.Sprintf("%v - %0.2f seconds after deletion - %v", event.Locator, timeBetweenDeleteAndFailure.Seconds(), event.Message)) + case deletionTime.Before(event.From): + // something went wrong. More than five seconds after the pod ws deleted, the CNI is trying to set up pod sandboxes and can't + failures = append(failures, fmt.Sprintf("%v - %0.2f seconds after deletion - %v", event.Locator, timeBetweenDeleteAndFailure.Seconds(), event.Message)) + default: + // something went wrong. deletion happend after we had a failure to create the pod sandbox + failures = append(failures, fmt.Sprintf("%v - deletion came AFTER sandbox failure - %v", event.Locator, event.Message)) + } + } + } + if len(failures) == 0 && len(flakes) == 0 { + successes := []*ginkgo.JUnitTestCase{} + for _, by := range bySubStrings { + successes = append(successes, &ginkgo.JUnitTestCase{Name: testName + by.by}) + } + return successes + } + + ret := []*ginkgo.JUnitTestCase{} + failuresBySubtest, flakesBySubtest := categorizeBySubset(bySubStrings, failures, flakes) + + // now iterate the individual failures to create failure entries + for by, subFailures := range failuresBySubtest { + failure := &ginkgo.JUnitTestCase{ + Name: testName + by, + SystemOut: strings.Join(subFailures, "\n"), + FailureOutput: &ginkgo.FailureOutput{ + Output: fmt.Sprintf("%d failures to create the sandbox\n\n%v", len(subFailures), strings.Join(subFailures, "\n")), + }, + } + ret = append(ret, failure) + } + for by, subFlakes := range flakesBySubtest { + flake := &ginkgo.JUnitTestCase{ + Name: testName + by, + SystemOut: strings.Join(subFlakes, "\n"), + FailureOutput: &ginkgo.FailureOutput{ + Output: fmt.Sprintf("%d failures to create the sandbox\n\n%v", len(subFlakes), strings.Join(subFlakes, "\n")), + }, + } + ret = append(ret, flake) + // write a passing test to trigger detection of this issue as a flake. Doing this first to try to see how frequent the issue actually is + success := &ginkgo.JUnitTestCase{ + Name: testName + by, + } + ret = append(ret, success) + } + + return append(ret) +} + +// categorizeBySubset returns a map keyed by category for failures and flakes. If a category is present in both failures and flakes, all are listed under failures. +func categorizeBySubset(categorizers []testCategorizer, failures, flakes []string) (map[string][]string, map[string][]string) { + failuresBySubtest := map[string][]string{} + flakesBySubtest := map[string][]string{} + for _, failure := range failures { + for _, by := range categorizers { + if strings.Contains(failure, by.substring) { + failuresBySubtest[by.by] = append(failuresBySubtest[by.by], failure) + break // break after first match so we only add each failure one bucket + } + } + } + + for _, flake := range flakes { + for _, by := range categorizers { + if strings.Contains(flake, by.substring) { + if _, isFailure := failuresBySubtest[by.by]; isFailure { + failuresBySubtest[by.by] = append(failuresBySubtest[by.by], flake) + } else { + flakesBySubtest[by.by] = append(flakesBySubtest[by.by], flake) + } + break // break after first match so we only add each failure one bucket + } + } + } + return failuresBySubtest, flakesBySubtest +} + +func getPodCreationTime(events []*monitor.EventInterval, podLocator string) *time.Time { + for _, event := range events { + if event.Locator == podLocator && event.Message == "reason/Created" { + return &event.From + } + } + return nil +} + +func getPodDeletionTime(events []*monitor.EventInterval, podLocator string) *time.Time { + for _, event := range events { + if event.Locator == podLocator && event.Message == "reason/Deleted" { + return &event.From + } + } + return nil +} + +// getEventsByPod returns map keyed by pod locator with all events associated with it. +func getEventsByPod(events []*monitor.EventInterval) map[string][]*monitor.EventInterval { + eventsByPods := map[string][]*monitor.EventInterval{} + for _, event := range events { + if !strings.Contains(event.Locator, "pod/") { + continue + } + eventsByPods[event.Locator] = append(eventsByPods[event.Locator], event) + } + return eventsByPods +} diff --git a/cmd/openshift-tests/images.go b/cmd/openshift-tests/images.go new file mode 100644 index 000000000000..2f5f7acae071 --- /dev/null +++ b/cmd/openshift-tests/images.go @@ -0,0 +1,327 @@ +package main + +import ( + "bytes" + "context" + "fmt" + "os" + "sort" + "strings" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/klog/v2" + + imagev1 "github.com/openshift/client-go/image/clientset/versioned/typed/image/v1" + "github.com/openshift/library-go/pkg/image/reference" + + "github.com/openshift/origin/pkg/monitor" + "github.com/openshift/origin/pkg/test/ginkgo" + "github.com/openshift/origin/test/extended/util/image" + + e2e "k8s.io/kubernetes/test/e2e/framework" + k8simage "k8s.io/kubernetes/test/utils/image" +) + +// OpenShift tests consume images from the cluster, from a number of vetted community locations, +// and from the upstream Kubernetes test suite which may reference images produced by a variety +// of build systems. To better organize and consolidate these images, the utility code within +// Kubernetes and OpenShift that is consulted to find image streams is made remappable - so that +// all images used by the test code can be located in one place. During normal operation the test +// images are read from the mirror, and administrators can choose to copy those images into +// restricted environment image registries and then run the tests against that subset. This also +// allows us to control the process whereby new images are introduced and review those in one spot. +// +// Test code utilizes helpers to get image strings throughout the code base, or is expected to use +// one or more of the images every OpenShift distribution includes in the 'openshift' namespace. +// +// See test/extended/util/image/README.md for a description of the process of adding a new image. + +// defaultTestImageMirrorLocation is where all Kube test inputs are sourced. +const defaultTestImageMirrorLocation = "quay.io/openshift/community-e2e-images" + +// createImageMirrorForInternalImages returns a list of 'oc image mirror' mappings from source to +// target or returns an error. If mirrored is true the images are assumed to have already been copied +// from their upstream location into our official mirror, in the REPO:TAG format where TAG is a hash +// of the original internal name and the index of the image in the array. Otherwise the mappings will +// be set to mirror the location as defined in the test code into our official mirror, where the target +// TAG is the hash described above. +func createImageMirrorForInternalImages(prefix string, ref reference.DockerImageReference, mirrored bool) ([]string, error) { + source := ref.Exact() + + defaults := k8simage.GetOriginalImageConfigs() + updated := k8simage.GetMappedImageConfigs(defaults, ref.Exact()) + + openshiftDefaults := image.OriginalImages() + openshiftUpdated := image.GetMappedImages(openshiftDefaults, defaultTestImageMirrorLocation) + + // if we've mirrored, then the source is going to be our repo, not upstream's + if mirrored { + baseRef, err := reference.Parse(defaultTestImageMirrorLocation) + if err != nil { + return nil, fmt.Errorf("invalid default mirror location: %v", err) + } + + // calculate the mapping of upstream images by setting defaults to baseRef + covered := sets.NewString() + for i, config := range updated { + defaultConfig := defaults[i] + pullSpec := config.GetE2EImage() + if pullSpec == defaultConfig.GetE2EImage() { + continue + } + if covered.Has(pullSpec) { + continue + } + covered.Insert(pullSpec) + e2eRef, err := reference.Parse(pullSpec) + if err != nil { + return nil, fmt.Errorf("invalid test image: %s: %v", pullSpec, err) + } + if len(e2eRef.Tag) == 0 { + return nil, fmt.Errorf("invalid test image: %s: no tag", pullSpec) + } + config.SetRegistry(baseRef.Registry) + config.SetName(baseRef.RepositoryName()) + config.SetVersion(e2eRef.Tag) + defaults[i] = config + } + + // calculate the mapping for openshift images by populating openshiftUpdated + openshiftUpdated = make(map[string]string) + sourceMappings := image.GetMappedImages(openshiftDefaults, defaultTestImageMirrorLocation) + targetMappings := image.GetMappedImages(openshiftDefaults, source) + + for from, to := range targetMappings { + if from == to { + continue + } + if covered.Has(to) { + continue + } + covered.Insert(to) + from := sourceMappings[from] + openshiftUpdated[from] = to + } + } + + covered := sets.NewString() + var lines []string + for i := range updated { + a, b := defaults[i], updated[i] + from, to := a.GetE2EImage(), b.GetE2EImage() + if from == to { + continue + } + if covered.Has(from) { + continue + } + covered.Insert(from) + lines = append(lines, fmt.Sprintf("%s %s%s", from, prefix, to)) + } + + for from, to := range openshiftUpdated { + if from == to { + continue + } + if covered.Has(from) { + continue + } + covered.Insert(from) + lines = append(lines, fmt.Sprintf("%s %s%s", from, prefix, to)) + } + + sort.Strings(lines) + return lines, nil +} + +func verifyImages() error { + if len(os.Getenv("KUBE_TEST_REPO")) > 0 { + return fmt.Errorf("KUBE_TEST_REPO may not be specified when this command is run") + } + return verifyImagesWithoutEnv() +} + +func verifyImagesWithoutEnv() error { + defaults := k8simage.GetOriginalImageConfigs() + + for originalPullSpec, index := range image.OriginalImages() { + if index == -1 { + continue + } + existing, ok := defaults[index] + if !ok { + return fmt.Errorf("image %q not found in upstream images, must be moved to test/extended/util/image", originalPullSpec) + } + if existing.GetE2EImage() != originalPullSpec { + return fmt.Errorf("image %q defines index %d but is defined upstream as %q, must be fixed in test/extended/util/image", originalPullSpec, index, existing.GetE2EImage()) + } + mirror := image.LocationFor(originalPullSpec) + upstreamMirror := k8simage.GetE2EImage(index) + if mirror != upstreamMirror { + return fmt.Errorf("image %q defines index %d and mirror %q but is mirrored upstream as %q, must be fixed in test/extended/util/image", originalPullSpec, index, mirror, upstreamMirror) + } + } + + return nil +} + +// pulledInvalidImages returns a function that checks whether the cluster pulled an image that is +// outside the allowed list of images. The list is defined as a set of static test case images, the +// local cluster registry, any repository referenced by the image streams in the cluster's 'openshift' +// namespace, or the location that input images are cloned from. Only namespaces prefixed with 'e2e-' +// are checked. +func pulledInvalidImages(fromRepository string) ginkgo.JUnitForEventsFunc { + // static allowed images + allowedImages := sets.NewString("image/webserver:404") + allowedPrefixes := sets.NewString( + "image-registry.openshift-image-registry.svc", + "gcr.io/k8s-authenticated-test/", + "gcr.io/authenticated-image-pulling/", + "invalid.com/", + + // installed alongside OLM and managed externally + "registry.redhat.io/redhat/community-operator-index", + "registry.redhat.io/redhat/certified-operator-index", + "registry.redhat.io/redhat/redhat-marketplace-index", + "registry.redhat.io/redhat/redhat-operator-index", + + // used by OLM tests + "registry.redhat.io/amq7/amq-streams-rhel7-operator", + "registry.redhat.io/amq7/amqstreams-rhel7-operator-metadata", + + // used to test pull secrets against an authenticated registry + // TODO: will not work for a disconnected test environment and should be emulated by launching + // an authenticated registry in a pod on cluster + "registry.redhat.io/rhscl/nodejs-10-rhel7:latest", + ) + if len(fromRepository) > 0 { + allowedPrefixes.Insert(fromRepository) + } + + // any image not in the allowed prefixes is considered a failure, as the user + // may have added a new test image without calling the appropriate helpers + return func(events monitor.EventIntervals, _ time.Duration) ([]*ginkgo.JUnitTestCase, bool) { + imageStreamPrefixes, err := imagePrefixesFromNamespaceImageStreams("openshift") + if err != nil { + klog.Errorf("Unable to identify image prefixes from the openshift namespace: %v", err) + } + allowedPrefixes.Insert(imageStreamPrefixes.UnsortedList()...) + + allowedPrefixes := allowedPrefixes.List() + + passed := true + var tests []*ginkgo.JUnitTestCase + + pulls := make(map[string]sets.String) + for _, event := range events { + // only messages that include a Pulled reason + if !strings.Contains(event.Message, " reason/Pulled ") { + continue + } + // only look at pull events from an e2e-* namespace + if !strings.Contains(event.Locator, " ns/e2e-") { + continue + } + + parts := strings.Split(event.Message, " ") + if len(parts) == 0 { + continue + } + image := strings.TrimPrefix(parts[len(parts)-1], "image/") + if hasAnyStringPrefix(image, allowedPrefixes) || allowedImages.Has(image) { + continue + } + byImage, ok := pulls[image] + if !ok { + byImage = sets.NewString() + pulls[image] = byImage + } + byImage.Insert(event.Locator) + } + if len(pulls) > 0 { + images := make([]string, 0, len(pulls)) + for image := range pulls { + images = append(images, image) + } + sort.Strings(images) + buf := &bytes.Buffer{} + for _, image := range images { + fmt.Fprintf(buf, "%s from pods:\n", image) + for _, locator := range pulls[image].List() { + fmt.Fprintf(buf, " %s\n", locator) + } + } + tests = append(tests, &ginkgo.JUnitTestCase{ + Name: "[sig-arch] Only known images used by tests", + SystemOut: buf.String(), + FailureOutput: &ginkgo.FailureOutput{ + Output: fmt.Sprintf("Cluster accessed images that were not mirrored to the testing repository or already part of the cluster, see test/extended/util/image/README.md in the openshift/origin repo:\n\n%s", buf.String()), + }, + }) + passed = false + } + + return tests, passed + } +} + +func hasAnyStringPrefix(s string, prefixes []string) bool { + for _, prefix := range prefixes { + if strings.HasPrefix(s, prefix) { + return true + } + } + return false +} + +// imagePrefixesFromNamespaceImageStreams identifies all image repositories referenced by +// image streams in the provided namespace and returns them as a set (for both tags and +// digests). This set of prefixes can be used to verify that image references are coming +// from a location the cluster knows about. +func imagePrefixesFromNamespaceImageStreams(ns string) (sets.String, error) { + clientConfig, err := e2e.LoadConfig(true) + if err != nil { + return nil, err + } + client, err := imagev1.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + streams, err := client.ImageStreams(ns).List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return nil, err + } + + allowedPrefixes := sets.NewString() + for _, stream := range streams.Items { + for _, tag := range stream.Spec.Tags { + if tag.From == nil || tag.From.Kind != "DockerImage" { + continue + } + ref, err := reference.Parse(tag.From.Name) + if err != nil { + continue + } + repo := ref.AsRepository().Exact() + allowedPrefixes.Insert(repo + ":") + allowedPrefixes.Insert(repo + "@") + } + for _, tag := range stream.Status.Tags { + for _, event := range tag.Items { + if len(event.DockerImageReference) == 0 { + continue + } + ref, err := reference.Parse(event.DockerImageReference) + if err != nil { + continue + } + repo := ref.AsRepository().Exact() + allowedPrefixes.Insert(repo + ":") + allowedPrefixes.Insert(repo + "@") + } + } + } + return allowedPrefixes, nil +} diff --git a/cmd/openshift-tests/openshift-tests.go b/cmd/openshift-tests/openshift-tests.go index f7a2af88f899..f612802cf45c 100644 --- a/cmd/openshift-tests/openshift-tests.go +++ b/cmd/openshift-tests/openshift-tests.go @@ -1,14 +1,16 @@ package main import ( + "encoding/json" "flag" - goflag "flag" "fmt" "io" "math/rand" "os" + "os/exec" "path/filepath" "strings" + "syscall" "time" "github.com/spf13/cobra" @@ -16,24 +18,40 @@ import ( utilflag "k8s.io/component-base/cli/flag" "k8s.io/component-base/logs" + "k8s.io/klog/v2" "k8s.io/kubectl/pkg/util/templates" + "github.com/openshift/library-go/pkg/image/reference" "github.com/openshift/library-go/pkg/serviceability" "github.com/openshift/origin/pkg/monitor" "github.com/openshift/origin/pkg/monitor/resourcewatch/cmd" testginkgo "github.com/openshift/origin/pkg/test/ginkgo" "github.com/openshift/origin/pkg/version" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/cloud" ) func main() { + // KUBE_TEST_REPO_LIST is calculated during package initialization and prevents + // proper mirroring of images referenced by tests. Clear the value and re-exec the + // current process to ensure we can verify from a known state. + if len(os.Getenv("KUBE_TEST_REPO_LIST")) > 0 { + fmt.Fprintln(os.Stderr, "warning: KUBE_TEST_REPO_LIST may not be set when using openshift-tests and will be ignored") + os.Setenv("KUBE_TEST_REPO_LIST", "") + // resolve the call to execute since Exec() does not do PATH resolution + if err := syscall.Exec(exec.Command(os.Args[0]).Path, os.Args, os.Environ()); err != nil { + panic(fmt.Sprintf("%s: %v", os.Args[0], err)) + } + return + } + logs.InitLogs() defer logs.FlushLogs() rand.Seed(time.Now().UTC().UnixNano()) pflag.CommandLine.SetNormalizeFunc(utilflag.WordSepNormalizeFunc) - pflag.CommandLine.AddGoFlagSet(goflag.CommandLine) + //pflag.CommandLine.AddGoFlagSet(goflag.CommandLine) root := &cobra.Command{ Long: templates.LongDesc(` @@ -48,11 +66,14 @@ func main() { root.AddCommand( newRunCommand(), newRunUpgradeCommand(), + newImagesCommand(), newRunTestCommand(), newRunMonitorCommand(), cmd.NewRunResourceWatchCommand(), ) + f := flag.CommandLine.Lookup("v") + root.PersistentFlags().AddGoFlag(f) pflag.CommandLine = pflag.NewFlagSet("empty", pflag.ExitOnError) flag.CommandLine = flag.NewFlagSet("empty", flag.ExitOnError) exutil.InitStandardFlags() @@ -91,9 +112,146 @@ func newRunMonitorCommand() *cobra.Command { return cmd } +type imagesOptions struct { + Repository string + Upstream bool + Verify bool +} + +func newImagesCommand() *cobra.Command { + opt := &imagesOptions{} + cmd := &cobra.Command{ + Use: "images", + Short: "Gather images required for testing", + Long: templates.LongDesc(fmt.Sprintf(` + Creates a mapping to mirror test images to a private registry + + This command identifies the locations of all test images referenced by the test + suite and outputs a mirror list for use with 'oc image mirror' to copy those images + to a private registry. The list may be passed via file or standard input. + + $ openshift-tests images --to-repository private.com/test/repository > /tmp/mirror + $ oc image mirror -f /tmp/mirror + + The 'run' and 'run-upgrade' subcommands accept '--from-repository' which will source + required test images from your mirror. + + See the help for 'oc image mirror' for more about mirroring to disk or consult the docs + for mirroring offline. You may use a file:// prefix in your '--to-repository', but when + mirroring from disk to your offline repository you will have to construct the appropriate + disk to internal registry statements yourself. + + By default, the test images are sourced from a public container image repository at + %[1]s and are provided as-is for testing purposes only. Images are mirrored by the project + to the public repository periodically. + `, defaultTestImageMirrorLocation)), + + SilenceUsage: true, + SilenceErrors: true, + RunE: func(cmd *cobra.Command, args []string) error { + if opt.Verify { + return verifyImages() + } + + repository := opt.Repository + var prefix string + for _, validPrefix := range []string{"file://", "s3://"} { + if strings.HasPrefix(repository, validPrefix) { + repository = strings.TrimPrefix(repository, validPrefix) + prefix = validPrefix + break + } + } + ref, err := reference.Parse(repository) + if err != nil { + return fmt.Errorf("--to-repository is not valid: %v", err) + } + if len(ref.Tag) > 0 || len(ref.ID) > 0 { + return fmt.Errorf("--to-repository may not include a tag or image digest") + } + + if err := verifyImages(); err != nil { + return err + } + lines, err := createImageMirrorForInternalImages(prefix, ref, !opt.Upstream) + if err != nil { + return err + } + for _, line := range lines { + fmt.Fprintln(os.Stdout, line) + } + return nil + }, + } + cmd.Flags().BoolVar(&opt.Upstream, "upstream", opt.Upstream, "Retrieve images from the default upstream location") + cmd.Flags().StringVar(&opt.Repository, "to-repository", opt.Repository, "A container image repository to mirror to.") + // this is a private flag for debugging only + cmd.Flags().BoolVar(&opt.Verify, "verify", opt.Verify, "Verify the contents of the image mappings") + cmd.Flags().MarkHidden("verify") + return cmd +} + +type runOptions struct { + testginkgo.Options + + FromRepository string + Provider string + + // Passed to the test process if set + UpgradeSuite string + ToImage string + TestOptions []string + + // Shared by initialization code + config *cloud.ClusterConfiguration +} + +func (opt *runOptions) AsEnv() []string { + var args []string + args = append(args, "KUBE_TEST_REPO_LIST=") // explicitly prevent selective override + args = append(args, fmt.Sprintf("KUBE_TEST_REPO=%s", opt.FromRepository)) + args = append(args, fmt.Sprintf("TEST_PROVIDER=%s", opt.Provider)) + args = append(args, fmt.Sprintf("TEST_JUNIT_DIR=%s", opt.JUnitDir)) + for i := 10; i > 0; i-- { + if klog.V(klog.Level(i)).Enabled() { + args = append(args, fmt.Sprintf("TEST_LOG_LEVEL=%d", i)) + break + } + } + + if len(opt.UpgradeSuite) > 0 { + data, err := json.Marshal(UpgradeOptions{ + Suite: opt.UpgradeSuite, + ToImage: opt.ToImage, + TestOptions: opt.TestOptions, + }) + if err != nil { + panic(err) + } + args = append(args, fmt.Sprintf("TEST_UPGRADE_OPTIONS=%s", string(data))) + } else { + args = append(args, "TEST_UPGRADE_OPTIONS=") + } + + return args +} + +func (opt *runOptions) SelectSuite(suites testSuites, args []string) (*testSuite, error) { + suite, err := opt.Options.SelectSuite(suites.TestSuites(), args) + if err != nil { + return nil, err + } + for i := range suites { + if &suites[i].TestSuite == suite { + return &suites[i], nil + } + } + return &testSuite{TestSuite: *suite}, nil +} + func newRunCommand() *cobra.Command { - opt := &testginkgo.Options{ - Suites: staticSuites, + opt := &runOptions{ + FromRepository: defaultTestImageMirrorLocation, } cmd := &cobra.Command{ @@ -110,28 +268,33 @@ func newRunCommand() *cobra.Command { command with the --file argument. You may also pipe a list of test names, one per line, on standard input by passing "-f -". - `) + testginkgo.SuitesString(opt.Suites, "\n\nAvailable test suites:\n\n"), + `) + testginkgo.SuitesString(staticSuites.TestSuites(), "\n\nAvailable test suites:\n\n"), SilenceUsage: true, SilenceErrors: true, RunE: func(cmd *cobra.Command, args []string) error { - return mirrorToFile(opt, func() error { - if !opt.DryRun { - fmt.Fprintf(os.Stderr, "%s version: %s\n", filepath.Base(os.Args[0]), version.Get().String()) - } - config, err := decodeProvider(opt.Provider, opt.DryRun, true) - if err != nil { + return mirrorToFile(&opt.Options, func() error { + if err := verifyImages(); err != nil { return err } - opt.Provider = config.ToJSONString() - matchFn, err := initializeTestFramework(exutil.TestContext, config, opt.DryRun) + opt.SyntheticEventTests = pulledInvalidImages(opt.FromRepository) + + suite, err := opt.SelectSuite(staticSuites, args) if err != nil { return err } - opt.MatchFn = matchFn - err = opt.Run(args) - if !opt.DryRun && len(args) > 0 && strings.HasPrefix(args[0], "openshift/csi") { - printStorageCapabilities(opt.Out) + if suite.PreSuite != nil { + if err := suite.PreSuite(opt); err != nil { + return err + } + } + opt.CommandEnv = opt.AsEnv() + if !opt.DryRun { + fmt.Fprintf(os.Stderr, "%s version: %s\n", filepath.Base(os.Args[0]), version.Get().String()) + } + err = opt.Run(&suite.TestSuite) + if suite.PostSuite != nil { + suite.PostSuite(opt) } return err }) @@ -142,8 +305,9 @@ func newRunCommand() *cobra.Command { } func newRunUpgradeCommand() *cobra.Command { - opt := &testginkgo.Options{Suites: upgradeSuites} - upgradeOpt := &UpgradeOptions{} + opt := &runOptions{ + FromRepository: defaultTestImageMirrorLocation, + } cmd := &cobra.Command{ Use: "run-upgrade SUITE", @@ -165,48 +329,45 @@ func newRunUpgradeCommand() *cobra.Command { the reboot will allow the node to shut down services in an orderly fashion. If set to 'force' the machine will terminate immediately without clean shutdown. - `) + testginkgo.SuitesString(opt.Suites, "\n\nAvailable upgrade suites:\n\n"), + `) + testginkgo.SuitesString(upgradeSuites.TestSuites(), "\n\nAvailable upgrade suites:\n\n"), SilenceUsage: true, SilenceErrors: true, RunE: func(cmd *cobra.Command, args []string) error { - return mirrorToFile(opt, func() error { - if len(upgradeOpt.ToImage) == 0 { + return mirrorToFile(&opt.Options, func() error { + if len(opt.ToImage) == 0 { return fmt.Errorf("--to-image must be specified to run an upgrade test") } - - if len(args) > 0 { - for _, suite := range opt.Suites { - if suite.Name == args[0] { - upgradeOpt.Suite = suite.Name - upgradeOpt.JUnitDir = opt.JUnitDir - value := upgradeOpt.ToEnv() - if _, err := initUpgrade(value); err != nil { - return err - } - opt.SuiteOptions = value - break - } - } + if err := verifyImages(); err != nil { + return err } + opt.SyntheticEventTests = pulledInvalidImages(opt.FromRepository) - config, err := decodeProvider(opt.Provider, opt.DryRun, true) + suite, err := opt.SelectSuite(upgradeSuites, args) if err != nil { return err } - opt.Provider = config.ToJSONString() - matchFn, err := initializeTestFramework(exutil.TestContext, config, opt.DryRun) - if err != nil { - return err + opt.UpgradeSuite = suite.Name + if suite.PreSuite != nil { + if err := suite.PreSuite(opt); err != nil { + return err + } } - opt.MatchFn = matchFn - return opt.Run(args) + opt.CommandEnv = opt.AsEnv() + if !opt.DryRun { + fmt.Fprintf(os.Stderr, "%s version: %s\n", filepath.Base(os.Args[0]), version.Get().String()) + } + err = opt.Run(&suite.TestSuite) + if suite.PostSuite != nil { + suite.PostSuite(opt) + } + return err }) }, } bindOptions(opt, cmd.Flags()) - bindUpgradeOptions(upgradeOpt, cmd.Flags()) + bindUpgradeOptions(opt, cmd.Flags()) return cmd } @@ -220,7 +381,7 @@ func newRunTestCommand() *cobra.Command { Use: "run-test NAME", Short: "Run a single test by name", Long: templates.LongDesc(` - Execute a single test + Execute a single test This executes a single test by name. It is used by the run command during suite execution but may also be used to test in isolation while developing new tests. @@ -229,18 +390,31 @@ func newRunTestCommand() *cobra.Command { SilenceUsage: true, SilenceErrors: true, RunE: func(cmd *cobra.Command, args []string) error { - upgradeOpts, err := initUpgrade(os.Getenv("TEST_SUITE_OPTIONS")) - if err != nil { + if v := os.Getenv("TEST_LOG_LEVEL"); len(v) > 0 { + cmd.Flags().Lookup("v").Value.Set(v) + } + + if err := verifyImagesWithoutEnv(); err != nil { return err } + config, err := decodeProvider(os.Getenv("TEST_PROVIDER"), testOpt.DryRun, false) if err != nil { return err } - if _, err := initializeTestFramework(exutil.TestContext, config, testOpt.DryRun); err != nil { + if err := initializeTestFramework(exutil.TestContext, config, testOpt.DryRun); err != nil { + return err + } + klog.V(4).Infof("Loaded test configuration: %#v", exutil.TestContext) + + exutil.TestContext.ReportDir = os.Getenv("TEST_JUNIT_DIR") + + // allow upgrade test to pass some parameters here, although this may be + // better handled as an env var within the test itself in the future + if err := upgradeTestPreTest(); err != nil { return err } - exutil.TestContext.ReportDir = upgradeOpts.JUnitDir + exutil.WithCleanup(func() { err = testOpt.Run(args) }) return err }, @@ -279,15 +453,21 @@ func mirrorToFile(opt *testginkgo.Options, fn func() error) error { return exitErr } -func bindOptions(opt *testginkgo.Options, flags *pflag.FlagSet) { +func bindOptions(opt *runOptions, flags *pflag.FlagSet) { + flags.StringVar(&opt.FromRepository, "from-repository", opt.FromRepository, "A container image repository to retrieve test images from.") + flags.StringVar(&opt.Provider, "provider", opt.Provider, "The cluster infrastructure provider. Will automatically default to the correct value.") + bindTestOptions(&opt.Options, flags) +} + +func bindTestOptions(opt *testginkgo.Options, flags *pflag.FlagSet) { flags.BoolVar(&opt.DryRun, "dry-run", opt.DryRun, "Print the tests to run without executing them.") flags.BoolVar(&opt.PrintCommands, "print-commands", opt.PrintCommands, "Print the sub-commands that would be executed instead.") flags.StringVar(&opt.JUnitDir, "junit-dir", opt.JUnitDir, "The directory to write test reports to.") - flags.StringVar(&opt.Provider, "provider", opt.Provider, "The cluster infrastructure provider. Will automatically default to the correct value.") flags.StringVarP(&opt.TestFile, "file", "f", opt.TestFile, "Create a suite from the newline-delimited test names in this file.") flags.StringVar(&opt.Regex, "run", opt.Regex, "Regular expression of tests to run.") flags.StringVarP(&opt.OutFile, "output-file", "o", opt.OutFile, "Write all test output to this file.") - flags.IntVar(&opt.Count, "count", opt.Count, "Run each test a specified number of times. Defaults to 1 or the suite's preferred value.") + flags.IntVar(&opt.Count, "count", opt.Count, "Run each test a specified number of times. Defaults to 1 or the suite's preferred value. -1 will run forever.") + flags.BoolVar(&opt.FailFast, "fail-fast", opt.FailFast, "If a test fails, exit immediately.") flags.DurationVar(&opt.Timeout, "timeout", opt.Timeout, "Set the maximum time a test can run before being aborted. This is read from the suite by default, but will be 10 minutes otherwise.") flags.BoolVar(&opt.IncludeSuccessOutput, "include-success", opt.IncludeSuccessOutput, "Print output from successful tests.") flags.IntVar(&opt.Parallelism, "max-parallel-tests", opt.Parallelism, "Maximum number of tests running in parallel. 0 defaults to test suite recommended value, which is different in each suite.") diff --git a/cmd/openshift-tests/provider.go b/cmd/openshift-tests/provider.go index 6dac7d136a29..5ec172a2f5d4 100644 --- a/cmd/openshift-tests/provider.go +++ b/cmd/openshift-tests/provider.go @@ -18,6 +18,9 @@ import ( // Initialize ovirt as a provider _ "github.com/openshift/origin/test/extended/util/ovirt" + // Initialize kubevirt as a provider + _ "github.com/openshift/origin/test/extended/util/kubevirt" + // these are loading important global flags that we need to get and set _ "k8s.io/kubernetes/test/e2e" _ "k8s.io/kubernetes/test/e2e/lifecycle" @@ -25,7 +28,7 @@ import ( type TestNameMatchesFunc func(name string) bool -func initializeTestFramework(context *e2e.TestContextType, config *exutilcloud.ClusterConfiguration, dryRun bool) (TestNameMatchesFunc, error) { +func initializeTestFramework(context *e2e.TestContextType, config *exutilcloud.ClusterConfiguration, dryRun bool) error { // update context with loaded config context.Provider = config.ProviderName context.CloudConfig = e2e.CloudConfig{ @@ -46,17 +49,20 @@ func initializeTestFramework(context *e2e.TestContextType, config *exutilcloud.C var err error exutil.WithCleanup(func() { err = initCSITests(dryRun) }) if err != nil { - return nil, err + return err } if err := exutil.InitTest(dryRun); err != nil { - return nil, err + return err } gomega.RegisterFailHandler(ginkgo.Fail) e2e.AfterReadingAllFlags(context) context.DumpLogsOnFailure = true + return nil +} +func getProviderMatchFn(config *exutilcloud.ClusterConfiguration) TestNameMatchesFunc { // given the configuration we have loaded, skip tests that our provider should exclude // or our network plugin should exclude var skips []string @@ -72,7 +78,7 @@ func initializeTestFramework(context *e2e.TestContextType, config *exutilcloud.C } return true } - return matchFn, nil + return matchFn } func decodeProvider(provider string, dryRun, discover bool) (*exutilcloud.ClusterConfiguration, error) { diff --git a/cmd/openshift-tests/storagecaps.go b/cmd/openshift-tests/storagecaps.go index 8394141e3b37..951d9fb410d9 100644 --- a/cmd/openshift-tests/storagecaps.go +++ b/cmd/openshift-tests/storagecaps.go @@ -87,7 +87,7 @@ func printStorageCapabilities(out io.Writer) { fmt.Fprintln(out, " Volume limits: ", yamlManifest.DriverInfo.Capabilities.VolumeLimits) fmt.Fprintln(out, " Volume can run on single node: ", yamlManifest.DriverInfo.Capabilities.SingleNodeVolume) fmt.Fprintln(out, " Topology: ", yamlManifest.DriverInfo.Capabilities.Topology) - fmt.Fprintln(out, "Supported CNV features:") + fmt.Fprintln(out, "Supported OpenShift Virtualization features:") fmt.Fprintln(out, " Raw block VM disks: ", yamlManifest.DriverInfo.Capabilities.Block) fmt.Fprintln(out, " Live migration: ", yamlManifest.DriverInfo.Capabilities.RWX) fmt.Fprintln(out, " VM snapshots: ", yamlManifest.DriverInfo.Capabilities.SnapshotDataSource) diff --git a/cmd/openshift-tests/upgrade.go b/cmd/openshift-tests/upgrade.go index d198e02c0484..3c389899d28f 100644 --- a/cmd/openshift-tests/upgrade.go +++ b/cmd/openshift-tests/upgrade.go @@ -3,6 +3,7 @@ package main import ( "encoding/json" "fmt" + "os" "strings" "time" @@ -17,82 +18,92 @@ import ( ) // upgradeSuites are all known upgade test suites this binary should run -var upgradeSuites = []*ginkgo.TestSuite{ +var upgradeSuites = testSuites{ { - Name: "all", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "all", + Description: templates.LongDesc(` Run all tests. `), - Matches: func(name string) bool { - return strings.Contains(name, "[Feature:ClusterUpgrade]") && !strings.Contains(name, "[Suite:k8s]") + Matches: func(name string) bool { + return strings.Contains(name, "[Feature:ClusterUpgrade]") && !strings.Contains(name, "[Suite:k8s]") + }, + TestTimeout: 240 * time.Minute, }, - Init: func(opt map[string]string) error { - return upgradeInitArguments(opt, func(string) bool { return true }) - }, - TestTimeout: 240 * time.Minute, + PreSuite: upgradeTestPreSuite, }, { - Name: "platform", - Description: templates.LongDesc(` + TestSuite: ginkgo.TestSuite{ + Name: "platform", + Description: templates.LongDesc(` Run only the tests that verify the platform remains available. `), - Matches: func(name string) bool { - return strings.Contains(name, "[Feature:ClusterUpgrade]") && !strings.Contains(name, "[Suite:k8s]") - }, - Init: func(opt map[string]string) error { - return upgradeInitArguments(opt, func(name string) bool { - return name == controlplane.NewKubeAvailableTest().Name() || name == controlplane.NewKubeAvailableTest().Name() - }) + Matches: func(name string) bool { + return strings.Contains(name, "[Feature:ClusterUpgrade]") && !strings.Contains(name, "[Suite:k8s]") + }, + TestTimeout: 240 * time.Minute, }, - TestTimeout: 240 * time.Minute, + PreSuite: upgradeTestPreSuite, }, } -func upgradeInitArguments(opt map[string]string, filterFn func(name string) bool) error { - for k, v := range opt { - switch k { +// upgradeTestPreSuite validates the test options. +func upgradeTestPreSuite(opt *runOptions) error { + return parseUpgradeOptions(opt.TestOptions) +} + +// upgradeTestPreTest uses variables set at suite execution time to prepare the upgrade +// test environment in process (setting constants in the upgrade packages). +func upgradeTestPreTest() error { + value := os.Getenv("TEST_UPGRADE_OPTIONS") + if len(value) == 0 { + return nil + } + + var opt UpgradeOptions + if err := json.Unmarshal([]byte(value), &opt); err != nil { + return err + } + parseUpgradeOptions(opt.TestOptions) + upgrade.SetToImage(opt.ToImage) + switch opt.Suite { + case "platform": + return filterUpgrade(upgrade.AllTests(), func(name string) bool { + return name == controlplane.NewKubeAvailableWithNewConnectionsTest().Name() || name == controlplane.NewKubeAvailableWithNewConnectionsTest().Name() + }) + default: + return filterUpgrade(upgrade.AllTests(), func(string) bool { return true }) + } +} + +func parseUpgradeOptions(options []string) error { + for _, opt := range options { + parts := strings.SplitN(opt, "=", 2) + if len(parts) != 2 { + return fmt.Errorf("expected option of the form KEY=VALUE instead of %q", opt) + } + switch parts[0] { case "abort-at": - if err := upgrade.SetUpgradeAbortAt(v); err != nil { + if err := upgrade.SetUpgradeAbortAt(parts[1]); err != nil { return err } case "disrupt-reboot": - if err := upgrade.SetUpgradeDisruptReboot(v); err != nil { + if err := upgrade.SetUpgradeDisruptReboot(parts[1]); err != nil { return err } default: - return fmt.Errorf("unrecognized upgrade option: %s", k) + return fmt.Errorf("unrecognized upgrade option: %s", parts[0]) } } - return filterUpgrade(upgrade.AllTests(), filterFn) + return nil } type UpgradeOptions struct { - Suite string - ToImage string - JUnitDir string - + Suite string + ToImage string TestOptions []string } -func (o *UpgradeOptions) OptionsMap() (map[string]string, error) { - options := make(map[string]string) - for _, option := range o.TestOptions { - parts := strings.SplitN(option, "=", 2) - if len(parts) != 2 { - return nil, fmt.Errorf("test option %q is not valid, must be KEY=VALUE", option) - } - if len(parts[0]) == 0 { - return nil, fmt.Errorf("test option %q is not valid, must be KEY=VALUE", option) - } - _, exists := options[parts[0]] - if exists { - return nil, fmt.Errorf("option %q declared twice", parts[0]) - } - options[parts[0]] = parts[1] - } - return options, nil -} - func (o *UpgradeOptions) ToEnv() string { out, err := json.Marshal(o) if err != nil { @@ -101,32 +112,6 @@ func (o *UpgradeOptions) ToEnv() string { return string(out) } -func initUpgrade(value string) (*UpgradeOptions, error) { - var opt UpgradeOptions - if len(value) == 0 { - return &opt, nil - } - if err := json.Unmarshal([]byte(value), &opt); err != nil { - return nil, err - } - for _, suite := range upgradeSuites { - if suite.Name == opt.Suite { - o, err := opt.OptionsMap() - if err != nil { - return nil, err - } - if suite.Init != nil { - if err := suite.Init(o); err != nil { - return nil, err - } - } - upgrade.SetToImage(opt.ToImage) - return &opt, nil - } - } - return nil, fmt.Errorf("unrecognized upgrade info") -} - func filterUpgrade(tests []upgrades.Test, match func(string) bool) error { var scope []upgrades.Test for _, test := range tests { @@ -138,7 +123,7 @@ func filterUpgrade(tests []upgrades.Test, match func(string) bool) error { return nil } -func bindUpgradeOptions(opt *UpgradeOptions, flags *pflag.FlagSet) { +func bindUpgradeOptions(opt *runOptions, flags *pflag.FlagSet) { flags.StringVar(&opt.ToImage, "to-image", opt.ToImage, "Specify the image to test an upgrade to.") flags.StringSliceVar(&opt.TestOptions, "options", opt.TestOptions, "A set of KEY=VALUE options to control the test. See the help text.") } diff --git a/examples/examples_test.go b/examples/examples_test.go index 909843097b19..5040e5593815 100644 --- a/examples/examples_test.go +++ b/examples/examples_test.go @@ -11,7 +11,7 @@ import ( "k8s.io/apimachinery/pkg/api/apitesting" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/yaml" - "k8s.io/klog" + "k8s.io/klog/v2" appsv1 "github.com/openshift/api/apps/v1" buildv1 "github.com/openshift/api/build/v1" diff --git a/examples/hello-openshift/OWNERS b/examples/hello-openshift/OWNERS index 4f784ddc2f51..0fe48113d231 100644 --- a/examples/hello-openshift/OWNERS +++ b/examples/hello-openshift/OWNERS @@ -7,9 +7,11 @@ reviewers: - bparees - knobunc - adambkaplan + - sgreene570 approvers: - mfojtik - smarterclayton - pweil- - jwforres - derekwaynecarr + - sgreene570 diff --git a/examples/hello-openshift/hello_openshift.go b/examples/hello-openshift/hello_openshift.go index 911ac655b333..a9ff66af5224 100644 --- a/examples/hello-openshift/hello_openshift.go +++ b/examples/hello-openshift/hello_openshift.go @@ -2,8 +2,10 @@ package main import ( "fmt" + "net" "net/http" "os" + "strconv" ) func helloHandler(w http.ResponseWriter, r *http.Request) { @@ -12,6 +14,13 @@ func helloHandler(w http.ResponseWriter, r *http.Request) { response = "Hello OpenShift!" } + // Echo back the port the request was received on + // via a "request-port" header. + addr := r.Context().Value(http.LocalAddrContextKey).(net.Addr) + if tcpAddr, ok := addr.(*net.TCPAddr); ok { + w.Header().Set("x-request-port", strconv.Itoa(tcpAddr.Port)) + } + fmt.Fprintln(w, response) fmt.Println("Servicing request.") } diff --git a/examples/image-streams/image-streams-centos7.json b/examples/image-streams/image-streams-centos7.json index 2d61c4a45277..267939d92740 100644 --- a/examples/image-streams/image-streams-centos7.json +++ b/examples/image-streams/image-streams-centos7.json @@ -15,56 +15,59 @@ "tags": [ { "annotations": { - "description": "Build and run .NET Core applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.1/build/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of .NET Core available on OpenShift, including major versions updates.", + "description": "Build and run .NET Core applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of .NET Core available on OpenShift, including major versions updates.", "iconClass": "icon-dotnet", "openshift.io/display-name": ".NET Core (Latest)", "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.1", + "sampleRef": "dotnetcore-3.1", "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", "supports": "dotnet", "tags": "builder,.net,dotnet,dotnetcore" }, "from": { "kind": "ImageStreamTag", - "name": "2.1" + "name": "3.1" }, - "name": "latest" + "name": "latest", + "referencePolicy": { + "type": "Local" + } }, { "annotations": { - "description": "Build and run .NET Core 2.1 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.0/build/README.md.", + "description": "Build and run .NET Core 2.2 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/blob/master/2.2/build/README.md.", "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 2.1", + "openshift.io/display-name": ".NET Core 2.2", "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.1", + "sampleRef": "dotnetcore-2.2", "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:2.1,dotnet", + "supports": "dotnet:2.2,dotnet", "tags": "builder,.net,dotnet,dotnetcore,rh-dotnet21", - "version": "2.1" + "version": "2.2" }, "from": { "kind": "DockerImage", - "name": "registry.centos.org/dotnet/dotnet-21-centos7:latest" + "name": "registry.centos.org/dotnet/dotnet-22-centos7:latest" }, - "name": "2.1" + "name": "2.2" }, { "annotations": { - "description": "RETIRED: Build and run .NET Core 2.0 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.0/build/README.md.", + "description": "Build and run .NET Core 3.1 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/blob/master/3.1/build/README.md.", "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 2.0", + "openshift.io/display-name": ".NET Core 3.1", "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.0", + "sampleRef": "dotnetcore-3.1", "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:2.0,dotnet", - "tags": "hidden,builder,.net,dotnet,dotnetcore,rh-dotnet20", - "version": "2.0" + "supports": "dotnet:3.1,dotnet", + "tags": "builder,.net,dotnet,dotnetcore,rh-dotnet21", + "version": "3.1" }, "from": { "kind": "DockerImage", - "name": "registry.centos.org/dotnet/dotnet-20-centos7:latest" + "name": "registry.centos.org/dotnet/dotnet-31-centos7:latest" }, - "name": "2.0" + "name": "3.1" } ] } @@ -82,7 +85,7 @@ "tags": [ { "annotations": { - "description": "Build and serve static content via Apache HTTP Server (httpd) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/httpd-container/blob/master/2.4/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Httpd available on OpenShift, including major versions updates.", + "description": "Build and serve static content via Apache HTTP Server (httpd) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/httpd-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Httpd available on OpenShift, including major versions updates.", "iconClass": "icon-apache", "openshift.io/display-name": "Apache HTTP Server (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -112,7 +115,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/httpd-24-centos7:latest" + "name": "registry.centos.org/centos/httpd-24-centos7:latest" }, "name": "2.4", "referencePolicy": { @@ -184,7 +187,7 @@ "tags": [ { "annotations": { - "description": "Provides a MariaDB database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.2/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MariaDB available on OpenShift, including major versions updates.", + "description": "Provides a MariaDB database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/blob/master/10.2/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MariaDB available on OpenShift, including major versions updates.", "iconClass": "icon-mariadb", "openshift.io/display-name": "MariaDB (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -201,7 +204,7 @@ }, { "annotations": { - "description": "Provides a MariaDB 10.1 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.1/README.md.", + "description": "Provides a MariaDB 10.1 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/blob/master/10.1/README.md.", "iconClass": "icon-mariadb", "openshift.io/display-name": "MariaDB 10.1", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -210,7 +213,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mariadb-101-centos7:latest" + "name": "registry.centos.org/centos/mariadb-101-centos7:latest" }, "name": "10.1", "referencePolicy": { @@ -219,7 +222,7 @@ }, { "annotations": { - "description": "Provides a MariaDB 10.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.2/README.md.", + "description": "Provides a MariaDB 10.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/blob/master/10.2/README.md.", "iconClass": "icon-mariadb", "openshift.io/display-name": "MariaDB 10.2", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -228,7 +231,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mariadb-102-centos7:latest" + "name": "registry.centos.org/centos/mariadb-102-centos7:latest" }, "name": "10.2", "referencePolicy": { @@ -251,7 +254,7 @@ "tags": [ { "annotations": { - "description": "Provides a MongoDB database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.4/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MongoDB available on OpenShift, including major versions updates.", + "description": "Provides a MongoDB database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MongoDB available on OpenShift, including major versions updates.", "iconClass": "icon-mongodb", "openshift.io/display-name": "MongoDB (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -259,7 +262,7 @@ }, "from": { "kind": "ImageStreamTag", - "name": "3.6" + "name": "3.4" }, "name": "latest", "referencePolicy": { @@ -268,25 +271,7 @@ }, { "annotations": { - "description": "Provides a MongoDB 2.4 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/2.4/README.md.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB 2.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,mongodb", - "version": "2.4" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/mongodb-24-centos7:latest" - }, - "name": "2.4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a MongoDB 2.6 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/2.6/README.md.", + "description": "Provides a MongoDB 2.6 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/blob/master/2.6/README.md.", "iconClass": "icon-mongodb", "openshift.io/display-name": "MongoDB 2.6", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -295,7 +280,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mongodb-26-centos7:latest" + "name": "registry.centos.org/centos/mongodb-26-centos7:latest" }, "name": "2.6", "referencePolicy": { @@ -304,7 +289,7 @@ }, { "annotations": { - "description": "Provides a MongoDB 3.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.2/README.md.", + "description": "Provides a MongoDB 3.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/blob/master/3.2/README.md.", "iconClass": "icon-mongodb", "openshift.io/display-name": "MongoDB 3.2", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -313,7 +298,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mongodb-32-centos7:latest" + "name": "registry.centos.org/centos/mongodb-32-centos7:latest" }, "name": "3.2", "referencePolicy": { @@ -322,7 +307,7 @@ }, { "annotations": { - "description": "Provides a MongoDB 3.4 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.4/README.md.", + "description": "Provides a MongoDB 3.4 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/blob/master/3.4/README.md.", "iconClass": "icon-mongodb", "openshift.io/display-name": "MongoDB 3.4", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -331,30 +316,12 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mongodb-34-centos7:latest" + "name": "registry.centos.org/centos/mongodb-34-centos7:latest" }, "name": "3.4", "referencePolicy": { "type": "Local" } - }, - { - "annotations": { - "description": "Provides a MongoDB 3.6 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.6/README.md.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB 3.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,mongodb", - "version": "3.6" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/mongodb-36-centos7:latest" - }, - "name": "3.6", - "referencePolicy": { - "type": "Local" - } } ] } @@ -387,24 +354,6 @@ "type": "Local" } }, - { - "annotations": { - "description": "Provides a MySQL 5.5 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/README.md.", - "iconClass": "icon-mysql-database", - "openshift.io/display-name": "MySQL 5.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,mysql", - "version": "5.5" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/mysql-55-centos7:latest" - }, - "name": "5.5", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Provides a MySQL 5.6 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/README.md.", @@ -416,7 +365,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mysql-56-centos7:latest" + "name": "registry.centos.org/centos/mysql-56-centos7:latest" }, "name": "5.6", "referencePolicy": { @@ -434,7 +383,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mysql-57-centos7:latest" + "name": "registry.centos.org/centos/mysql-57-centos7:latest" }, "name": "5.7", "referencePolicy": { @@ -457,60 +406,40 @@ "tags": [ { "annotations": { - "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.8/README.md.", + "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.14/README.md.", "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.8", + "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.14", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/sclorg/nginx-ex.git", "supports": "nginx", "tags": "builder,nginx", - "version": "1.8" + "version": "1.14" }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/nginx-18-centos7:latest" + "name": "registry.centos.org/centos/nginx-114-centos7:latest" }, - "name": "1.8", + "name": "1.14", "referencePolicy": { "type": "Local" } }, { "annotations": { - "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.10/README.md.", + "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.16/README.md.", "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.10", + "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.16", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/sclorg/nginx-ex.git", "supports": "nginx", "tags": "builder,nginx", - "version": "1.10" + "version": "1.16" }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/nginx-110-centos7:latest" + "name": "registry.centos.org/centos/nginx-116-centos7:latest" }, - "name": "1.10", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.12/README.md.", - "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.12", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nginx-ex.git", - "supports": "nginx", - "tags": "builder,nginx", - "version": "1.12" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/nginx-112-centos7:latest" - }, - "name": "1.12", + "name": "1.16", "referencePolicy": { "type": "Local" } @@ -527,7 +456,7 @@ }, "from": { "kind": "ImageStreamTag", - "name": "1.12" + "name": "1.16" }, "name": "latest", "referencePolicy": { @@ -560,7 +489,7 @@ }, "from": { "kind": "ImageStreamTag", - "name": "11" + "name": "12" }, "name": "latest", "referencePolicy": { @@ -569,105 +498,7 @@ }, { "annotations": { - "description": "DEPRECATED: Build and run Node.js 0.10 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/0.10/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 0.10", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:0.10,nodejs:0.1,nodejs", - "tags": "hidden,nodejs", - "version": "0.10" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/nodejs-010-centos7:latest" - }, - "name": "0.10", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 4 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/4/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:4,nodejs", - "tags": "hidden,builder,nodejs", - "version": "4" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/nodejs-4-centos7:latest" - }, - "name": "4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 6 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/6/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:6,nodejs", - "tags": "builder,nodejs", - "version": "6" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/nodejs-6-centos7:latest" - }, - "name": "6", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 8 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/8/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 8", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "tags": "builder,nodejs", - "version": "8" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/nodejs-8-centos7:latest" - }, - "name": "8", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 8 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 8 (RHOAR)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "tags": "builder,nodejs", - "version": "8" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/nodeshift/centos7-s2i-nodejs:8.x" - }, - "name": "8-RHOAR", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 10 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.", + "description": "Build and run Node.js 10 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/10/README.md.", "iconClass": "icon-nodejs", "openshift.io/display-name": "Node.js 10", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -677,7 +508,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/nodeshift/centos7-s2i-nodejs:10.x" + "name": "registry.centos.org/centos/nodejs-10-centos7:latest" }, "name": "10", "referencePolicy": { @@ -686,19 +517,19 @@ }, { "annotations": { - "description": "Build and run Node.js 11 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.", + "description": "Build and run Node.js 12 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/12/README.md.", "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 11", + "openshift.io/display-name": "Node.js 12", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", "tags": "builder,nodejs", - "version": "11" + "version": "12" }, "from": { "kind": "DockerImage", - "name": "docker.io/nodeshift/centos7-s2i-nodejs:11.x" + "name": "registry.centos.org/centos/nodejs-12-centos7:latest" }, - "name": "11", + "name": "12", "referencePolicy": { "type": "Local" } @@ -736,46 +567,6 @@ "type": "Local" } }, - { - "annotations": { - "description": "Build and run Perl 5.16 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.16/README.md.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl 5.16", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl:5.16,perl", - "tags": "hidden,builder,perl", - "version": "5.16" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/perl-516-centos7:latest" - }, - "name": "5.16", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Perl 5.20 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.20/README.md.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl 5.20", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl:5.20,perl", - "tags": "hidden,builder,perl", - "version": "5.20" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/perl-520-centos7:latest" - }, - "name": "5.20", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Build and run Perl 5.24 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.24/README.md.", @@ -789,7 +580,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/perl-524-centos7:latest" + "name": "registry.centos.org/centos/perl-524-centos7:latest" }, "name": "5.24", "referencePolicy": { @@ -809,7 +600,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/perl-526-centos7:latest" + "name": "registry.centos.org/centos/perl-526-centos7:latest" }, "name": "5.26", "referencePolicy": { @@ -849,46 +640,6 @@ "type": "Local" } }, - { - "annotations": { - "description": "Build and run PHP 5.5 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/5.5/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP 5.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php:5.5,php", - "tags": "hidden,builder,php", - "version": "5.5" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/php-55-centos7:latest" - }, - "name": "5.5", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run PHP 5.6 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/5.6/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP 5.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php:5.6,php", - "tags": "hidden,builder,php", - "version": "5.6" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/php-56-centos7:latest" - }, - "name": "5.6", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Build and run PHP 7.0 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/7.0/README.md.", @@ -902,7 +653,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/php-70-centos7:latest" + "name": "registry.centos.org/centos/php-70-centos7:latest" }, "name": "7.0", "referencePolicy": { @@ -922,7 +673,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/php-71-centos7:latest" + "name": "registry.centos.org/centos/php-71-centos7:latest" }, "name": "7.1", "referencePolicy": { @@ -953,49 +704,13 @@ }, "from": { "kind": "ImageStreamTag", - "name": "10" + "name": "9.6" }, "name": "latest", "referencePolicy": { "type": "Local" } }, - { - "annotations": { - "description": "Provides a PostgreSQL 9.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 9.2", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,postgresql", - "version": "9.2" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/postgresql-92-centos7:latest" - }, - "name": "9.2", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 9.4 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 9.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,database,postgresql", - "version": "9.4" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/postgresql-94-centos7:latest" - }, - "name": "9.4", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Provides a PostgreSQL 9.5 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", @@ -1007,7 +722,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/postgresql-95-centos7:latest" + "name": "registry.centos.org/centos/postgresql-95-centos7:latest" }, "name": "9.5", "referencePolicy": { @@ -1025,30 +740,12 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/postgresql-96-centos7:latest" + "name": "registry.centos.org/centos/postgresql-96-centos7:latest" }, "name": "9.6", "referencePolicy": { "type": "Local" } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 10 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 10", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,postgresql", - "version": "10" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/postgresql-10-centos7:latest" - }, - "name": "10", - "referencePolicy": { - "type": "Local" - } } ] } @@ -1083,26 +780,6 @@ "type": "Local" } }, - { - "annotations": { - "description": "Build and run Python 3.3 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.3/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.3", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.3,python", - "tags": "hidden,builder,python", - "version": "3.3" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/python-33-centos7:latest" - }, - "name": "3.3", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Build and run Python 2.7 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/2.7/README.md.", @@ -1116,53 +793,13 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/python-27-centos7:latest" + "name": "registry.centos.org/centos/python-27-centos7:latest" }, "name": "2.7", "referencePolicy": { "type": "Local" } }, - { - "annotations": { - "description": "Build and run Python 3.4 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.4/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.4,python", - "tags": "hidden,builder,python", - "version": "3.4" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/python-34-centos7:latest" - }, - "name": "3.4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Python 3.5 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.5/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.5,python", - "tags": "builder,python", - "version": "3.5" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/python-35-centos7:latest" - }, - "name": "3.5", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Build and run Python 3.6 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.6/README.md.", @@ -1176,7 +813,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/python-36-centos7:latest" + "name": "registry.centos.org/centos/python-36-centos7:latest" }, "name": "3.6", "referencePolicy": { @@ -1199,7 +836,7 @@ "tags": [ { "annotations": { - "description": "Provides a Redis database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/tree/master/3.2/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Redis available on OpenShift, including major versions updates.", + "description": "Provides a Redis database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Redis available on OpenShift, including major versions updates.", "iconClass": "icon-redis", "openshift.io/display-name": "Redis (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -1207,7 +844,7 @@ }, "from": { "kind": "ImageStreamTag", - "name": "3.2" + "name": "5" }, "name": "latest", "referencePolicy": { @@ -1216,18 +853,18 @@ }, { "annotations": { - "description": "Provides a Redis 3.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/tree/master/3.2/README.md.", + "description": "Provides a Redis 5 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/blob/master/5/README.md.", "iconClass": "icon-redis", - "openshift.io/display-name": "Redis 3.2", + "openshift.io/display-name": "Redis 5", "openshift.io/provider-display-name": "Red Hat, Inc.", "tags": "redis", - "version": "3.2" + "version": "5" }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/redis-32-centos7:latest" + "name": "registry.centos.org/centos/redis-5-centos7:latest" }, - "name": "3.2", + "name": "5", "referencePolicy": { "type": "Local" } @@ -1248,7 +885,7 @@ "tags": [ { "annotations": { - "description": "Build and run Ruby applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/tree/master/2.3/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Ruby available on OpenShift, including major versions updates.", + "description": "Build and run Ruby applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Ruby available on OpenShift, including major versions updates.", "iconClass": "icon-ruby", "openshift.io/display-name": "Ruby (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -1284,6 +921,26 @@ "referencePolicy": { "type": "Local" } + }, + { + "annotations": { + "description": "Build and run Ruby 2.6 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/blob/master/2.6/README.md.", + "iconClass": "icon-ruby", + "openshift.io/display-name": "Ruby 2.6", + "openshift.io/provider-display-name": "Red Hat, Inc.", + "sampleRepo": "https://github.com/sclorg/ruby-ex.git", + "supports": "ruby:2.6,ruby", + "tags": "builder,ruby", + "version": "2.6" + }, + "from": { + "kind": "DockerImage", + "name": "registry.centos.org/centos/ruby-26-centos7:latest" + }, + "name": "2.6", + "referencePolicy": { + "type": "Local" + } } ] } @@ -1311,7 +968,7 @@ }, "from": { "kind": "ImageStreamTag", - "name": "15.0" + "name": "21.0" }, "name": "latest", "referencePolicy": { @@ -1320,180 +977,40 @@ }, { "annotations": { - "description": "Build and run WildFly 8.1 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 8.1", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:8.1,jee,java", - "tags": "builder,wildfly,java", - "version": "8.1" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-81-centos7:latest" - }, - "name": "8.1", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 9.0 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 9.0", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:9.0,jee,java", - "tags": "builder,wildfly,java", - "version": "9.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-90-centos7:latest" - }, - "name": "9.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 10.0 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 10.0", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:10.0,jee,java", - "tags": "builder,wildfly,java", - "version": "10.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-100-centos7:latest" - }, - "name": "10.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 10.1 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 10.1", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:10.1,jee,java", - "tags": "builder,wildfly,java", - "version": "10.1" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-101-centos7:latest" - }, - "name": "10.1", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 11 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 11", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:11,jee,java", - "tags": "builder,wildfly,java", - "version": "11.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-110-centos7:latest" - }, - "name": "11.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 12 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 12", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:12,jee,java", - "tags": "builder,wildfly,java", - "version": "12.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-120-centos7:latest" - }, - "name": "12.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 13 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 13", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:13,jee,java", - "tags": "builder,wildfly,java", - "version": "13.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-130-centos7:latest" - }, - "name": "13.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 14 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", + "description": "Build and run WildFly 20 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 14", + "openshift.io/display-name": "WildFly 20", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:14,jee,java", + "supports": "wildfly:20,jee,java", "tags": "builder,wildfly,java", - "version": "14.0" + "version": "20.0" }, "from": { "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-140-centos7:latest" + "name": "quay.io/wildfly/wildfly-centos7:20.0" }, - "name": "14.0", + "name": "20.0", "referencePolicy": { "type": "Local" } }, { "annotations": { - "description": "Build and run WildFly 15 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", + "description": "Build and run WildFly 21 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 15", + "openshift.io/display-name": "WildFly 21", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:15,jee,java", + "supports": "wildfly:21,jee,java", "tags": "builder,wildfly,java", - "version": "15.0" + "version": "21.0" }, "from": { "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-150-centos7:latest" + "name": "quay.io/wildfly/wildfly-centos7:21.0.0" }, - "name": "15.0", + "name": "21.0", "referencePolicy": { "type": "Local" } diff --git a/examples/image-streams/image-streams-rhel7.json b/examples/image-streams/image-streams-rhel7.json deleted file mode 100644 index e53cacd63f60..000000000000 --- a/examples/image-streams/image-streams-rhel7.json +++ /dev/null @@ -1,1425 +0,0 @@ -{ - "kind": "ImageStreamList", - "apiVersion": "v1", - "items": [ - { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": ".NET Core" - }, - "name": "dotnet" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Build and run .NET Core applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.2/build/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of .NET Core available on OpenShift, including major versions updates.", - "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core (Latest)", - "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.2", - "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet", - "tags": "builder,.net,dotnet,dotnetcore" - }, - "from": { - "kind": "ImageStreamTag", - "name": "2.2" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run .NET Core 2.2 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.2/build/README.md.", - "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 2.2", - "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.2", - "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:2.2,dotnet", - "tags": "builder,.net,dotnet,dotnetcore,rh-dotnet22", - "version": "2.2" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/dotnet/dotnet-22-rhel7:2.2" - }, - "name": "2.2", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run .NET Core 2.1 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.1/build/README.md.", - "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 2.1", - "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.1", - "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:2.1,dotnet", - "tags": "builder,.net,dotnet,dotnetcore,rh-dotnet21", - "version": "2.1" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/dotnet/dotnet-21-rhel7:2.1" - }, - "name": "2.1", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "RETIRED: Build and run .NET Core 2.0 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.0/build/README.md.", - "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 2.0", - "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.0", - "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:2.0,dotnet", - "tags": "hidden,builder,.net,dotnet,dotnetcore,rh-dotnet20", - "version": "2.0" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/dotnet/dotnet-20-rhel7:2.0" - }, - "name": "2.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run .NET Core 1.1 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/1.1/README.md.", - "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 1.1", - "sampleContextDir": "app", - "sampleRef": "dotnetcore-1.1", - "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:1.1,dotnet", - "tags": "builder,.net,dotnet,dotnetcore,rh-dotnetcore11", - "version": "1.1" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/dotnet/dotnetcore-11-rhel7:1.1" - }, - "name": "1.1", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run .NET Core 1.0 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/1.0/README.md.", - "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 1.0", - "sampleContextDir": "app", - "sampleRef": "dotnetcore-1.0", - "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:1.0,dotnet", - "tags": "builder,.net,dotnet,dotnetcore,rh-dotnetcore10", - "version": "1.0" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/dotnet/dotnetcore-10-rhel7:1.0" - }, - "name": "1.0", - "referencePolicy": { - "type": "Local" - } - } - ] - } - }, - { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "Apache HTTP Server (httpd)" - }, - "name": "httpd" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Build and serve static content via Apache HTTP Server (httpd) on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/httpd-container/blob/master/2.4/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Httpd available on OpenShift, including major versions updates.", - "iconClass": "icon-apache", - "openshift.io/display-name": "Apache HTTP Server (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/httpd-ex.git", - "supports": "httpd", - "tags": "builder,httpd" - }, - "from": { - "kind": "ImageStreamTag", - "name": "2.4" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and serve static content via Apache HTTP Server (httpd) 2.4 on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/httpd-container/blob/master/2.4/README.md.", - "iconClass": "icon-apache", - "openshift.io/display-name": "Apache HTTP Server 2.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/httpd-ex.git", - "supports": "httpd", - "tags": "builder,httpd", - "version": "2.4" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/httpd-24-rhel7" - }, - "name": "2.4", - "referencePolicy": { - "type": "Local" - } - } - ] - } - }, - { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "Jenkins" - }, - "name": "jenkins" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Provides a Jenkins server on RHEL 7. For more information about using this container image, including OpenShift considerations, see https://github.com/openshift/jenkins/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Jenkins available on OpenShift, including major versions updates.", - "iconClass": "icon-jenkins", - "openshift.io/display-name": "Jenkins (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "jenkins" - }, - "from": { - "kind": "ImageStreamTag", - "name": "2" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a Jenkins 2.X server on RHEL 7. For more information about using this container image, including OpenShift considerations, see https://github.com/openshift/jenkins/blob/master/README.md.", - "iconClass": "icon-jenkins", - "openshift.io/display-name": "Jenkins 2.X", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "jenkins", - "version": "2.x" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift/jenkins-2-rhel7:v4.0" - }, - "name": "2", - "referencePolicy": { - "type": "Local" - } - } - ] - } - }, - { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "MariaDB" - }, - "name": "mariadb" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Provides a MariaDB database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.2/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MariaDB available on OpenShift, including major versions updates.", - "iconClass": "icon-mariadb", - "openshift.io/display-name": "MariaDB (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,mariadb" - }, - "from": { - "kind": "ImageStreamTag", - "name": "10.2" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a MariaDB 10.1 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.1/README.md.", - "iconClass": "icon-mariadb", - "openshift.io/display-name": "MariaDB 10.1", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,mariadb", - "version": "10.1" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/mariadb-101-rhel7:latest" - }, - "name": "10.1", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a MariaDB 10.2 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.2/README.md.", - "iconClass": "icon-mariadb", - "openshift.io/display-name": "MariaDB 10.2", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,mariadb", - "version": "10.2" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/mariadb-102-rhel7:latest" - }, - "name": "10.2", - "referencePolicy": { - "type": "Local" - } - } - ] - } - }, - { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "MongoDB" - }, - "name": "mongodb" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Provides a MongoDB database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.4/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MongoDB available on OpenShift, including major versions updates.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "mongodb" - }, - "from": { - "kind": "ImageStreamTag", - "name": "3.6" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a MongoDB 2.4 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/2.4/README.md.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB 2.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,mongodb", - "version": "2.4" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift3/mongodb-24-rhel7:latest" - }, - "name": "2.4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a MongoDB 2.6 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/2.6/README.md.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB 2.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,database,mongodb", - "version": "2.6" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/mongodb-26-rhel7:latest" - }, - "name": "2.6", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a MongoDB 3.2 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.2/README.md.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB 3.2", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,mongodb", - "version": "3.2" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/mongodb-32-rhel7:latest" - }, - "name": "3.2", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a MongoDB 3.4 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.4/README.md.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB 3.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,mongodb", - "version": "3.4" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/mongodb-34-rhel7:latest" - }, - "name": "3.4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a MongoDB 3.6 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.6/README.md.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB 3.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,mongodb", - "version": "3.6" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/mongodb-36-rhel7:latest" - }, - "name": "3.6", - "referencePolicy": { - "type": "Local" - } - } - ] - } - }, - { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "MySQL" - }, - "name": "mysql" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Provides a MySQL database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MySQL available on OpenShift, including major versions updates.", - "iconClass": "icon-mysql-database", - "openshift.io/display-name": "MySQL (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "mysql" - }, - "from": { - "kind": "ImageStreamTag", - "name": "5.7" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a MySQL 5.5 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/README.md.", - "iconClass": "icon-mysql-database", - "openshift.io/display-name": "MySQL 5.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,mysql", - "version": "5.5" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift3/mysql-55-rhel7:latest" - }, - "name": "5.5", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a MySQL 5.6 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/README.md.", - "iconClass": "icon-mysql-database", - "openshift.io/display-name": "MySQL 5.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,mysql", - "version": "5.6" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/mysql-56-rhel7:latest" - }, - "name": "5.6", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a MySQL 5.7 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/README.md.", - "iconClass": "icon-mysql-database", - "openshift.io/display-name": "MySQL 5.7", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "mysql", - "version": "5.7" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/mysql-57-rhel7:latest" - }, - "name": "5.7", - "referencePolicy": { - "type": "Local" - } - } - ] - } - }, - { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy (nginx)" - }, - "name": "nginx" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Build and serve static content via Nginx HTTP server and a reverse proxy (nginx) on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.8/README.md.", - "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.8", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nginx-ex.git", - "supports": "nginx", - "tags": "builder,nginx", - "version": "1.8" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/nginx-18-rhel7:latest" - }, - "name": "1.8", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and serve static content via Nginx HTTP server and a reverse proxy (nginx) on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.10/README.md.", - "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.10", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nginx-ex.git", - "supports": "nginx", - "tags": "builder,nginx", - "version": "1.10" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/nginx-110-rhel7:latest" - }, - "name": "1.10", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and serve static content via Nginx HTTP server and a reverse proxy (nginx) on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.12/README.md.", - "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.12", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nginx-ex.git", - "supports": "nginx", - "tags": "builder,nginx", - "version": "1.12" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/nginx-112-rhel7:latest" - }, - "name": "1.12", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and serve static content via Nginx HTTP server and a reverse proxy (nginx) on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.12/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Nginx available on OpenShift, including major versions updates.", - "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nginx-ex.git", - "supports": "nginx", - "tags": "builder,nginx" - }, - "from": { - "kind": "ImageStreamTag", - "name": "1.12" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - } - ] - } - }, - { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "Node.js" - }, - "name": "nodejs" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Build and run Node.js 10 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Node.js available on OpenShift, including major versions updates.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs", - "tags": "builder,nodejs" - }, - "from": { - "kind": "ImageStreamTag", - "name": "10" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "DEPRECATED: Build and run Node.js 0.10 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/0.10/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 0.10", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:0.10,nodejs:0.1,nodejs", - "tags": "hidden,nodejs", - "version": "0.10" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift3/nodejs-010-rhel7:latest" - }, - "name": "0.10", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 4 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/4/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:4,nodejs", - "tags": "hidden,builder,nodejs", - "version": "4" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/nodejs-4-rhel7:latest" - }, - "name": "4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 6 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:6,nodejs", - "tags": "builder,nodejs", - "version": "6" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/nodejs-6-rhel7:latest" - }, - "name": "6", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 8 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 8", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "tags": "builder,nodejs", - "version": "8" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/nodejs-8-rhel7:latest" - }, - "name": "8", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 8 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "OpenShift Application Runtimes Node.js 8", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "tags": "builder,nodejs", - "version": "8" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhoar-nodejs/nodejs-8" - }, - "name": "8-RHOAR", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 10 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "OpenShift Application Runtimes Node.js 10", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "tags": "builder,nodejs", - "version": "10" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhoar-nodejs/nodejs-10" - }, - "name": "10", - "referencePolicy": { - "type": "Local" - } - } - ] - } - }, - { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "Perl" - }, - "name": "perl" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Build and run Perl applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.20/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Perl available on OpenShift, including major versions updates.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl", - "tags": "builder,perl" - }, - "from": { - "kind": "ImageStreamTag", - "name": "5.26" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Perl 5.16 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.16/README.md.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl 5.16", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl:5.16,perl", - "tags": "hidden,builder,perl", - "version": "5.16" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift3/perl-516-rhel7:latest" - }, - "name": "5.16", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Perl 5.20 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.20/README.md.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl 5.20", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl:5.20,perl", - "tags": "hidden,builder,perl", - "version": "5.20" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/perl-520-rhel7:latest" - }, - "name": "5.20", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Perl 5.24 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.24/README.md.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl 5.24", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl:5.24,perl", - "tags": "builder,perl", - "version": "5.24" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/perl-524-rhel7:latest" - }, - "name": "5.24", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Perl 5.26 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.26/README.md.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl 5.26", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl:5.26,perl", - "tags": "builder,perl", - "version": "5.26" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/perl-526-rhel7:latest" - }, - "name": "5.26", - "referencePolicy": { - "type": "Local" - } - } - ] - } - }, - { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "PHP" - }, - "name": "php" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Build and run PHP applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/7.1/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of PHP available on OpenShift, including major versions updates.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php", - "tags": "builder,php" - }, - "from": { - "kind": "ImageStreamTag", - "name": "7.1" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run PHP 5.5 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/5.5/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP 5.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php:5.5,php", - "tags": "hidden,builder,php", - "version": "5.5" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift3/php-55-rhel7:latest" - }, - "name": "5.5", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run PHP 5.6 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/5.6/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP 5.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php:5.6,php", - "tags": "hidden,builder,php", - "version": "5.6" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/php-56-rhel7:latest" - }, - "name": "5.6", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run PHP 7.0 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/7.0/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP 7.0", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php:7.0,php", - "tags": "builder,php", - "version": "7.0" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/php-70-rhel7:latest" - }, - "name": "7.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run PHP 7.1 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/7.1/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP 7.1", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php:7.1,php", - "tags": "builder,php", - "version": "7.1" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/php-71-rhel7:latest" - }, - "name": "7.1", - "referencePolicy": { - "type": "Local" - } - } - ] - } - }, - { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "PostgreSQL" - }, - "name": "postgresql" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Provides a PostgreSQL database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of PostgreSQL available on OpenShift, including major versions updates.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,postgresql" - }, - "from": { - "kind": "ImageStreamTag", - "name": "10" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 9.2 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 9.2", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,postgresql", - "version": "9.2" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift3/postgresql-92-rhel7:latest" - }, - "name": "9.2", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 9.4 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 9.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,database,postgresql", - "version": "9.4" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/postgresql-94-rhel7:latest" - }, - "name": "9.4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 9.5 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 9.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,postgresql", - "version": "9.5" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/postgresql-95-rhel7:latest" - }, - "name": "9.5", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 9.6 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL (Ephemeral) 9.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,postgresql", - "version": "9.6" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/postgresql-96-rhel7:latest" - }, - "name": "9.6", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 10 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL (Ephemeral) 10", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,postgresql", - "version": "10" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/postgresql-10-rhel7:latest" - }, - "name": "10", - "referencePolicy": { - "type": "Local" - } - } - ] - } - }, - { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "Python" - }, - "name": "python" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Build and run Python applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.6/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Python available on OpenShift, including major versions updates.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python", - "tags": "builder,python" - }, - "from": { - "kind": "ImageStreamTag", - "name": "3.6" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Python 3.3 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.3/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.3", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.3,python", - "tags": "hidden,builder,python", - "version": "3.3" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift3/python-33-rhel7:latest" - }, - "name": "3.3", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Python 2.7 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/2.7/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 2.7", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:2.7,python", - "tags": "builder,python", - "version": "2.7" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/python-27-rhel7:latest" - }, - "name": "2.7", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Python 3.4 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.4/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.4,python", - "tags": "hidden,builder,python", - "version": "3.4" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/python-34-rhel7:latest" - }, - "name": "3.4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Python 3.5 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.5/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.5,python", - "tags": "builder,python", - "version": "3.5" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/python-35-rhel7:latest" - }, - "name": "3.5", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Python 3.6 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.6/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.6,python", - "tags": "builder,python", - "version": "3.6" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/python-36-rhel7:latest" - }, - "name": "3.6", - "referencePolicy": { - "type": "Local" - } - } - ] - } - }, - { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "Redis" - }, - "name": "redis" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Provides a Redis database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/tree/master/3.2/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Redis available on OpenShift, including major versions updates.", - "iconClass": "icon-redis", - "openshift.io/display-name": "Redis (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "redis" - }, - "from": { - "kind": "ImageStreamTag", - "name": "3.2" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a Redis 3.2 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/tree/master/3.2/README.md.", - "iconClass": "icon-redis", - "openshift.io/display-name": "Redis 3.2", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "redis", - "version": "3.2" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/redis-32-rhel7:latest" - }, - "name": "3.2", - "referencePolicy": { - "type": "Local" - } - } - ] - } - }, - { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "Ruby" - }, - "name": "ruby" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Build and run Ruby applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/tree/master/2.3/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Ruby available on OpenShift, including major versions updates.", - "iconClass": "icon-ruby", - "openshift.io/display-name": "Ruby (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/ruby-ex.git", - "supports": "ruby", - "tags": "builder,ruby" - }, - "from": { - "kind": "ImageStreamTag", - "name": "2.5" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Ruby 2.0 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/tree/master/2.0/README.md.", - "iconClass": "icon-ruby", - "openshift.io/display-name": "Ruby 2.0", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/ruby-ex.git", - "supports": "ruby:2.0,ruby", - "tags": "hidden,builder,ruby", - "version": "2.0" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift3/ruby-20-rhel7:latest" - }, - "name": "2.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Ruby 2.2 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/tree/master/2.2/README.md.", - "iconClass": "icon-ruby", - "openshift.io/display-name": "Ruby 2.2", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/ruby-ex.git", - "supports": "ruby:2.2,ruby", - "tags": "hidden,builder,ruby", - "version": "2.2" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/ruby-22-rhel7:latest" - }, - "name": "2.2", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Ruby 2.3 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/blob/master/2.3/README.md.", - "iconClass": "icon-ruby", - "openshift.io/display-name": "Ruby 2.3", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/ruby-ex.git", - "supports": "ruby:2.3,ruby", - "tags": "builder,ruby", - "version": "2.3" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/ruby-23-rhel7:latest" - }, - "name": "2.3", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Ruby 2.4 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/blob/master/2.4/README.md.", - "iconClass": "icon-ruby", - "openshift.io/display-name": "Ruby 2.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/ruby-ex.git", - "supports": "ruby:2.4,ruby", - "tags": "builder,ruby", - "version": "2.4" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/ruby-24-rhel7:latest" - }, - "name": "2.4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Ruby 2.5 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/blob/master/2.5/README.md.", - "iconClass": "icon-ruby", - "openshift.io/display-name": "Ruby 2.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/ruby-ex.git", - "supports": "ruby:2.5,ruby", - "tags": "builder,ruby", - "version": "2.5" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/ruby-25-rhel7:latest" - }, - "name": "2.5", - "referencePolicy": { - "type": "Local" - } - } - ] - } - } - ] -} diff --git a/examples/pruner/README.md b/examples/pruner/README.md index 8b8884de9029..3c80b3446992 100644 --- a/examples/pruner/README.md +++ b/examples/pruner/README.md @@ -22,7 +22,7 @@ them in, if it is the one you desire. ## Creating the CronJob -2. `oc create -f examples/pruner/cronjob.yaml -n default --config=admin.kubeconfig` +2. `oc create -f examples/pruner/cronjob.yaml -n default --kubeconfig=admin.kubeconfig` This command creates the CronJob resource that runs the pruning job every 1 hour. diff --git a/examples/sample-app/README.md b/examples/sample-app/README.md index 938e0591a0fa..77ff0126df16 100644 --- a/examples/sample-app/README.md +++ b/examples/sample-app/README.md @@ -102,7 +102,7 @@ This section covers how to perform all the steps of building, deploying, and upd 1. For the sake of this demo, grant a `cluster-admin` role to the `test-admin` user and login as that user using any password you want (note that in a real world scenario, as an OpenShift user you would be granted roles from a cluster admin and you might not be able to do most of the following things - depending on your granted roles). - $ oc adm policy add-cluster-role-to-user cluster-admin test-admin --config=openshift.local.config/master/admin.kubeconfig + $ oc adm policy add-cluster-role-to-user cluster-admin test-admin --kubeconfig=openshift.local.config/master/admin.kubeconfig $ oc login --certificate-authority=openshift.local.config/master/ca.crt -u test-admin diff --git a/examples/sample-app/application-template-dockerbuild.json b/examples/sample-app/application-template-dockerbuild.json index 6b82ea7bdb2e..f2067d262bae 100644 --- a/examples/sample-app/application-template-dockerbuild.json +++ b/examples/sample-app/application-template-dockerbuild.json @@ -293,8 +293,7 @@ "dnsPolicy": "ClusterFirst" } } - }, - "status": {} + } }, { "kind": "Service", @@ -413,8 +412,7 @@ "dnsPolicy": "ClusterFirst" } } - }, - "status": {} + } } ], "parameters": [ diff --git a/examples/sample-app/application-template-pullspecbuild.json b/examples/sample-app/application-template-pullspecbuild.json index 10ebc4c90aa6..964263682be5 100644 --- a/examples/sample-app/application-template-pullspecbuild.json +++ b/examples/sample-app/application-template-pullspecbuild.json @@ -278,8 +278,7 @@ "dnsPolicy": "ClusterFirst" } } - }, - "status": {} + } }, { "kind": "Service", @@ -448,8 +447,7 @@ "dnsPolicy": "ClusterFirst" } } - }, - "status": {} + } } ], "parameters": [ diff --git a/examples/sample-app/application-template-stibuild.json b/examples/sample-app/application-template-stibuild.json index 76c98b37d051..e7c8b220eb6f 100644 --- a/examples/sample-app/application-template-stibuild.json +++ b/examples/sample-app/application-template-stibuild.json @@ -288,8 +288,7 @@ "dnsPolicy": "ClusterFirst" } } - }, - "status": {} + } }, { "kind": "Service", @@ -458,8 +457,7 @@ "dnsPolicy": "ClusterFirst" } } - }, - "status": {} + } } ], "parameters": [ diff --git a/examples/sample-app/github-webhook-example.json b/examples/sample-app/github-webhook-example.json index df46ac0768b6..5bc2c956ffab 100644 --- a/examples/sample-app/github-webhook-example.json +++ b/examples/sample-app/github-webhook-example.json @@ -77,7 +77,7 @@ "git_commits_url": "https://api.github.com/repos/anonUser/anonRepo/git/commits{/sha}", "git_refs_url": "https://api.github.com/repos/anonUser/anonRepo/git/refs{/sha}", "git_tags_url": "https://api.github.com/repos/anonUser/anonRepo/git/tags{/sha}", - "git_url": "git://github.com/anonUser/anonRepo.git", + "git_url": "https://github.com/anonUser/anonRepo.git", "has_downloads": true, "has_issues": true, "has_wiki": true, diff --git a/go.mod b/go.mod index fc4a34344e4c..9a46749160c8 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require ( github.com/openshift/apiserver-library-go v0.0.0-20200901140731-1236dc23c728 github.com/openshift/build-machinery-go v0.0.0-20200819073603-48aa266c95f7 github.com/openshift/client-go v0.0.0-20200827190008-3062137373b5 - github.com/openshift/library-go v0.0.0-20200902112127-a4e32e339219 + github.com/openshift/library-go v0.0.0-20201123125610-83d6d67a1e98 github.com/pborman/uuid v1.2.0 github.com/pquerna/cachecontrol v0.0.0-00010101000000-000000000000 // indirect github.com/prometheus/client_golang v1.7.1 @@ -66,7 +66,7 @@ require ( k8s.io/cli-runtime v0.19.0-rc.2 k8s.io/client-go v0.19.0 k8s.io/component-base v0.19.0 - k8s.io/klog v1.0.0 + k8s.io/klog/v2 v2.3.0 k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6 k8s.io/kubectl v0.0.0 k8s.io/kubelet v0.0.0 @@ -421,26 +421,26 @@ replace ( k8s.io/api => k8s.io/api v0.19.0-rc.2 k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.19.0-rc.2 k8s.io/apimachinery => k8s.io/apimachinery v0.19.0-rc.2 - k8s.io/apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20201002011447-1fc699e9f6be + k8s.io/apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20210219020830-8d1242094f14 k8s.io/cli-runtime => k8s.io/cli-runtime v0.19.0-rc.2 - k8s.io/client-go => github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20201002011447-1fc699e9f6be - k8s.io/cloud-provider => github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20201002011447-1fc699e9f6be + k8s.io/client-go => github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20210219020830-8d1242094f14 + k8s.io/cloud-provider => github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20210219020830-8d1242094f14 k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.19.0-rc.2 k8s.io/code-generator => k8s.io/code-generator v0.19.0-rc.2 - k8s.io/component-base => k8s.io/component-base v0.19.0-rc.2 + k8s.io/component-base => github.com/openshift/kubernetes/staging/src/k8s.io/component-base v0.0.0-20210219020830-8d1242094f14 k8s.io/cri-api => k8s.io/cri-api v0.19.0-rc.2 k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.19.0-rc.2 k8s.io/gengo => k8s.io/gengo v0.0.0-20200114144118-36b2048a9120 k8s.io/heapster => k8s.io/heapster v1.2.0-beta.1 k8s.io/klog => k8s.io/klog v1.0.0 - k8s.io/kube-aggregator => github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20201002011447-1fc699e9f6be + k8s.io/kube-aggregator => github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20210219020830-8d1242094f14 k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.19.0-rc.2 k8s.io/kube-proxy => k8s.io/kube-proxy v0.19.0-rc.2 k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.19.0-rc.2 k8s.io/kubectl => k8s.io/kubectl v0.19.0-rc.2 k8s.io/kubelet => k8s.io/kubelet v0.19.0-rc.2 - k8s.io/kubernetes => github.com/openshift/kubernetes v1.20.0-alpha.0.0.20201002011447-1fc699e9f6be - k8s.io/legacy-cloud-providers => github.com/openshift/kubernetes/staging/src/k8s.io/legacy-cloud-providers v0.0.0-20201002011447-1fc699e9f6be + k8s.io/kubernetes => github.com/openshift/kubernetes v1.20.0-alpha.0.0.20210219020830-8d1242094f14 + k8s.io/legacy-cloud-providers => github.com/openshift/kubernetes/staging/src/k8s.io/legacy-cloud-providers v0.0.0-20210219020830-8d1242094f14 k8s.io/metrics => k8s.io/metrics v0.19.0-rc.2 k8s.io/repo-infra => k8s.io/repo-infra v0.0.1-alpha.1 k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.19.0-rc.2 diff --git a/go.sum b/go.sum index 12c6b72867bd..01767f9b150b 100644 --- a/go.sum +++ b/go.sum @@ -221,6 +221,7 @@ github.com/go-ozzo/ozzo-validation v3.5.0+incompatible h1:sUy/in/P6askYr16XJgTKq github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= @@ -436,21 +437,23 @@ github.com/openshift/client-go v0.0.0-20200827190008-3062137373b5 h1:E6WhVL5p3rf github.com/openshift/client-go v0.0.0-20200827190008-3062137373b5/go.mod h1:5rGmrkQ8DJEUXA+AR3rEjfH+HFyg4/apY9iCQFgvPfE= github.com/openshift/golang-glog v0.0.0-20190322123450-3c92600d7533 h1:A5VovyRu3JFIPmC20HHrsOOny0PIdHuzDdNMULru48k= github.com/openshift/golang-glog v0.0.0-20190322123450-3c92600d7533/go.mod h1:3sa6LKKRDnR1xy4Kn8htvPwqIOVwXh8fIU3LRY22q3U= -github.com/openshift/kubernetes v1.20.0-alpha.0.0.20201002011447-1fc699e9f6be h1:AOXLm2cA17JnS8UDqF8hL3uW7nVAAJr21Kje3uHWISI= -github.com/openshift/kubernetes v1.20.0-alpha.0.0.20201002011447-1fc699e9f6be/go.mod h1:thZ+fVBomGpLqnFpgVP7zLoR1cZr5ceY0Ccrrw5DUPc= -github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20201002011447-1fc699e9f6be h1:8+EK1TjARQtEjw4QSzPxbUU2fmDj7QIoON4nYyAEgk0= -github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20201002011447-1fc699e9f6be/go.mod h1:wR/2WpnpEiQEhbGJyD7pRwxVsSEW4H3QKgvH4LBr97I= -github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20201002011447-1fc699e9f6be h1:2tDz7W+3hZWVzVVYGGqP1EWplf6NI2PSChkX1Xr9aGA= -github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20201002011447-1fc699e9f6be/go.mod h1:PKE732z15ZBntzuIso4UituryF6ls1srirW354KG/ag= -github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20201002011447-1fc699e9f6be h1:CJVA3R0uVJLFR50rWRjepxGghetcSOqZP91ueZe96wQ= -github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20201002011447-1fc699e9f6be/go.mod h1:xzTMREjOlgHSSvy4fYZPWLzPkYSn7Y0QmDpP2v3KQ24= -github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20201002011447-1fc699e9f6be h1:K0wVWVtdy+6+nenvhGlg8RNobVtTadlTZoACjI1k0uI= -github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20201002011447-1fc699e9f6be/go.mod h1:DaF/5oFo8hXpqC477u574XitO+uLNInMmaSkNYJiDSU= -github.com/openshift/kubernetes/staging/src/k8s.io/legacy-cloud-providers v0.0.0-20201002011447-1fc699e9f6be h1:tuqODuCoQ2XLOzF3yHQsTBhuR5mnhSa3OQPEJYvo7ME= -github.com/openshift/kubernetes/staging/src/k8s.io/legacy-cloud-providers v0.0.0-20201002011447-1fc699e9f6be/go.mod h1:Jsv6Huoke+fYBJz8CGV1m3A1EL3tOzSvQKiC0O6ohTQ= +github.com/openshift/kubernetes v1.20.0-alpha.0.0.20210219020830-8d1242094f14 h1:C1z8TeVUvmztaARJqcg0MU1r/10fiRZRV8sCh/biJQ8= +github.com/openshift/kubernetes v1.20.0-alpha.0.0.20210219020830-8d1242094f14/go.mod h1:6bzo36obLh8nXae3LNYt9uCdZDvOibNW5sIuCobbGT4= +github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20210219020830-8d1242094f14 h1:d80DYMWbiSLpv/CzB5nq5VLFHRBGw4zd9UvGqmv2k5U= +github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20210219020830-8d1242094f14/go.mod h1:xTtiDCrZ1GDAfd7WV+/8m/zO5TiWGkieMSCVIgg/APg= +github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20210219020830-8d1242094f14 h1:b5VM7Llt8HS0/TetiZF6DXO0esw2/rYVl5fXyeI5VuA= +github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20210219020830-8d1242094f14/go.mod h1:D25RgOItuGsiEWFEgaDKX58QISdSQBhOtBWcJVm+U3g= +github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20210219020830-8d1242094f14 h1:08GthrVY3WWMBk81CMqiN+A6p6PqG+wzV8sR96Dgc4w= +github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20210219020830-8d1242094f14/go.mod h1:VaeYDNR/CqsJz58fvIiBXfegSqrVKFxctZr11a64kKQ= +github.com/openshift/kubernetes/staging/src/k8s.io/component-base v0.0.0-20210219020830-8d1242094f14 h1:uGospZf71+6iLacZhD3esUJElLaErA2FeeZ2XNqCnZs= +github.com/openshift/kubernetes/staging/src/k8s.io/component-base v0.0.0-20210219020830-8d1242094f14/go.mod h1:S8FkSBJ+iRrM06QZf8BxEmEfkOlM16YroMRdnaq5PZQ= +github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20210219020830-8d1242094f14 h1:Vumzvo4hhvr8ihLxAqteJHSW3v+ZvzCxDLjnoJW3ZdQ= +github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20210219020830-8d1242094f14/go.mod h1:CwQ6pbiXqSxXDwIYb5Ic+4MhJGDj5ppxR14BbHRsxX0= +github.com/openshift/kubernetes/staging/src/k8s.io/legacy-cloud-providers v0.0.0-20210219020830-8d1242094f14 h1:rU9b7e+9dTQtKwcIUOXfx5KLQpvVJxYDj+1TTPGAVk0= +github.com/openshift/kubernetes/staging/src/k8s.io/legacy-cloud-providers v0.0.0-20210219020830-8d1242094f14/go.mod h1:iRAPalDX9PqT2K+CId1sPqyqv7KHba7bKdEZcWpGy5I= github.com/openshift/library-go v0.0.0-20200831114015-2ab0c61c15de/go.mod h1:6vwp+YhYOIlj8MpkQKkebTTSn2TuYyvgiAFQ206jIEQ= -github.com/openshift/library-go v0.0.0-20200902112127-a4e32e339219 h1:dhz1PgLYnWYpfXad452f/5P0wMU6MZvOlPIkPRzK7ro= -github.com/openshift/library-go v0.0.0-20200902112127-a4e32e339219/go.mod h1:6vwp+YhYOIlj8MpkQKkebTTSn2TuYyvgiAFQ206jIEQ= +github.com/openshift/library-go v0.0.0-20201123125610-83d6d67a1e98 h1:JYwa3H00larjMVZXmh7L4FHDhNlKdWSgYi0kLdav9BY= +github.com/openshift/library-go v0.0.0-20201123125610-83d6d67a1e98/go.mod h1:KNfLGf4dIRJ+QB2aGy67AOy1k+DV783cMCuJf0d4Zik= github.com/openshift/onsi-ginkgo v4.5.0-origin.1+incompatible h1:GtzyDU5vBFU40hz4GWd1qU5FJByNljWdgkM2LtdelGk= github.com/openshift/onsi-ginkgo v4.5.0-origin.1+incompatible/go.mod h1:azqkkH4Vpp9A579CC26hicol/wViXag9rOwElif6v9E= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= @@ -657,6 +660,7 @@ gopkg.in/warnings.v0 v0.1.1 h1:XM28wIgFzaBmeZ5dNHIpWLQpt/9DGKxk+rCg/22nnYE= gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= @@ -673,8 +677,6 @@ k8s.io/cli-runtime v0.19.0-rc.2/go.mod h1:AeERvBzh6NuhN5I3D3gJhjzMBjmZKfuyV4cIB0 k8s.io/cluster-bootstrap v0.19.0-rc.2 h1:xE7k984EcuimERJQWUSnojf/WzK5X2ZLmtf8+staa/k= k8s.io/cluster-bootstrap v0.19.0-rc.2/go.mod h1:kqyPgehF+Ml9acW1xOYrwzR7DdVRqSCPWIJSvM4K+iQ= k8s.io/code-generator v0.19.0-rc.2/go.mod h1:uR3gwQvtcOjBrvwXhFF1lw5kq9BOOAfSKl/pZZ1zW3I= -k8s.io/component-base v0.19.0-rc.2 h1:pJponI+sSso1sx+frQqJYWn/QhxoqpufVbQp+SOazRg= -k8s.io/component-base v0.19.0-rc.2/go.mod h1:aqXtywSxbTRUXnC1+1+DFIT1GXBxb6SogGhsHXmEbyc= k8s.io/cri-api v0.19.0-rc.2 h1:PissGgjQNgEN34/PTwzfjej40ugly6Xto83nua48fQI= k8s.io/cri-api v0.19.0-rc.2/go.mod h1:LozU4L5cHf6HgPPmSyYNb4m+yr6aokNcqmpuyTt02/Y= k8s.io/csi-translation-lib v0.19.0-rc.2 h1:bQQGrBWdA6m1E2jC+N7H74/EPEedfCrzpMPV6NZLPn4= @@ -716,6 +718,8 @@ modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.9 h1:rusRLrDhjBp6aYtl9sGEvQJr6faoHoDLd0YcUBTZguI= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.9/go.mod h1:dzAXnQbTRyDlZPJX2SUPEqvnB+j7AJjtlox7PEwigU0= +sigs.k8s.io/controller-tools v0.2.8/go.mod h1:9VKHPszmf2DHz/QmHkcfZoewO6BL7pPs9uAiBVsaJSE= +sigs.k8s.io/kube-storage-version-migrator v0.0.3/go.mod h1:mXfSLkx9xbJHQsgNDDUZK/iQTs2tMbx/hsJlWe6Fthw= sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= diff --git a/hack/lib/cleanup.sh b/hack/lib/cleanup.sh index 9efc2722ff49..ded6a39ca114 100644 --- a/hack/lib/cleanup.sh +++ b/hack/lib/cleanup.sh @@ -256,7 +256,7 @@ function os::cleanup::dump_events() { os::log::info "[CLEANUP] Dumping cluster events to $( os::util::repository_relative_path "${ARTIFACT_DIR}/events.txt" )" local kubeconfig if [[ -n "${ADMIN_KUBECONFIG:-}" ]]; then - kubeconfig="--config=${ADMIN_KUBECONFIG}" + kubeconfig="--kubeconfig=${ADMIN_KUBECONFIG}" fi oc login -u system:admin ${kubeconfig:-} oc get events --all-namespaces ${kubeconfig:-} > "${ARTIFACT_DIR}/events.txt" 2>&1 diff --git a/hack/lib/start.sh b/hack/lib/start.sh index cba1efef00e5..c7fad1efd8c4 100644 --- a/hack/lib/start.sh +++ b/hack/lib/start.sh @@ -130,21 +130,21 @@ function os::start::internal::patch_master_config() { # Make oc use ${MASTER_CONFIG_DIR}/admin.kubeconfig, and ignore anything in the running user's $HOME dir export ADMIN_KUBECONFIG="${MASTER_CONFIG_DIR}/admin.kubeconfig" - CLUSTER_ADMIN_CONTEXT=$(oc config view --config="${ADMIN_KUBECONFIG}" --flatten -o template --template='{{index . "current-context"}}'); export CLUSTER_ADMIN_CONTEXT + CLUSTER_ADMIN_CONTEXT=$(oc config view --kubeconfig="${ADMIN_KUBECONFIG}" --flatten -o template --template='{{index . "current-context"}}'); export CLUSTER_ADMIN_CONTEXT ${sudo} chmod -R a+rwX "${ADMIN_KUBECONFIG}" os::log::debug "To debug: export KUBECONFIG=$ADMIN_KUBECONFIG" cp "${SERVER_CONFIG_DIR}/master/master-config.yaml" "${SERVER_CONFIG_DIR}/master/master-config.orig.yaml" - oc patch --config="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f "${SERVER_CONFIG_DIR}/master/master-config.orig.yaml" --patch="[{\"op\": "replace", \"path\": \"/etcdConfig/address\", \"value\": \"${API_HOST}:${ETCD_PORT}\"}]" | \ - oc patch --config="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f - --patch="[{\"op\": \"add\", \"path\": \"/admissionConfig/pluginConfig\", \"value\": {\"openshift.io/ImagePolicy\": {\"configuration\": {\"apiVersion\": \"v1\", \"executionRules\": [{\"matchImageAnnotations\": [{\"key\": \"images.openshift.io/deny-execution\", \"value\": \"true\"}], \"name\": \"execution-denied\", \"onResources\": [{\"resource\": \"pods\"}, {\"resource\": \"builds\"}], \"reject\": true, \"skipOnResolutionFailure\": true }], \"kind\": \"ImagePolicyConfig\" }, \"location\": \"\"}}}]" | \ - oc patch --config="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f - --patch="[{\"op\": \"replace\", \"path\": \"/etcdConfig/servingInfo/bindAddress\", \"value\": \"${API_HOST}:${ETCD_PORT}\"}]" | \ - oc patch --config="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f - --patch="[{\"op\": \"replace\", \"path\": \"/etcdClientInfo/urls\", \"value\": [\"${API_SCHEME}://${API_HOST}:${ETCD_PORT}\"]}]" | \ - oc patch --config="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f - --patch="[{\"op\": \"replace\", \"path\": \"/etcdConfig/peerAddress\", \"value\": \"${API_HOST}:${ETCD_PEER_PORT}\"}]" | \ - oc patch --config="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f - --patch="[{\"op\": \"replace\", \"path\": \"/etcdConfig/peerServingInfo/bindAddress\", \"value\": \"${API_HOST}:${ETCD_PEER_PORT}\"}]" | \ - oc patch --config="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f - --patch="[{\"op\": \"replace\", \"path\": \"/auditConfig/enabled\", \"value\": true}]" | \ - oc patch --config="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f - --patch="[{\"op\": \"replace\", \"path\": \"/imagePolicyConfig/maxImagesBulkImportedPerRepository\", \"value\": ${MAX_IMAGES_BULK_IMPORTED_PER_REPOSITORY:-5}}]" > "${SERVER_CONFIG_DIR}/master/master-config.yaml" + oc patch --kubeconfig="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f "${SERVER_CONFIG_DIR}/master/master-config.orig.yaml" --patch="[{\"op\": "replace", \"path\": \"/etcdConfig/address\", \"value\": \"${API_HOST}:${ETCD_PORT}\"}]" | \ + oc patch --kubeconfig="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f - --patch="[{\"op\": \"add\", \"path\": \"/admissionConfig/pluginConfig\", \"value\": {\"openshift.io/ImagePolicy\": {\"configuration\": {\"apiVersion\": \"v1\", \"executionRules\": [{\"matchImageAnnotations\": [{\"key\": \"images.openshift.io/deny-execution\", \"value\": \"true\"}], \"name\": \"execution-denied\", \"onResources\": [{\"resource\": \"pods\"}, {\"resource\": \"builds\"}], \"reject\": true, \"skipOnResolutionFailure\": true }], \"kind\": \"ImagePolicyConfig\" }, \"location\": \"\"}}}]" | \ + oc patch --kubeconfig="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f - --patch="[{\"op\": \"replace\", \"path\": \"/etcdConfig/servingInfo/bindAddress\", \"value\": \"${API_HOST}:${ETCD_PORT}\"}]" | \ + oc patch --kubeconfig="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f - --patch="[{\"op\": \"replace\", \"path\": \"/etcdClientInfo/urls\", \"value\": [\"${API_SCHEME}://${API_HOST}:${ETCD_PORT}\"]}]" | \ + oc patch --kubeconfig="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f - --patch="[{\"op\": \"replace\", \"path\": \"/etcdConfig/peerAddress\", \"value\": \"${API_HOST}:${ETCD_PEER_PORT}\"}]" | \ + oc patch --kubeconfig="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f - --patch="[{\"op\": \"replace\", \"path\": \"/etcdConfig/peerServingInfo/bindAddress\", \"value\": \"${API_HOST}:${ETCD_PEER_PORT}\"}]" | \ + oc patch --kubeconfig="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f - --patch="[{\"op\": \"replace\", \"path\": \"/auditConfig/enabled\", \"value\": true}]" | \ + oc patch --kubeconfig="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f - --patch="[{\"op\": \"replace\", \"path\": \"/imagePolicyConfig/maxImagesBulkImportedPerRepository\", \"value\": ${MAX_IMAGES_BULK_IMPORTED_PER_REPOSITORY:-5}}]" > "${SERVER_CONFIG_DIR}/master/master-config.yaml" if [[ -n "${ALLOWED_REGISTRIES-}" ]]; then - oc patch --config="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f "${SERVER_CONFIG_DIR}/master/master-config.yaml" --patch="[{\"op\": \"add\", \"path\": \"/imagePolicyConfig/allowedRegistriesForImport\", \"value\": ${ALLOWED_REGISTRIES}}]" > "${SERVER_CONFIG_DIR}/master/master-config.yaml.patch" + oc patch --kubeconfig="${ADMIN_KUBECONFIG}" --local --type=json -o yaml -f "${SERVER_CONFIG_DIR}/master/master-config.yaml" --patch="[{\"op\": \"add\", \"path\": \"/imagePolicyConfig/allowedRegistriesForImport\", \"value\": ${ALLOWED_REGISTRIES}}]" > "${SERVER_CONFIG_DIR}/master/master-config.yaml.patch" mv -f "${SERVER_CONFIG_DIR}/master/master-config.yaml.patch" "${SERVER_CONFIG_DIR}/master/master-config.yaml" fi } @@ -247,14 +247,14 @@ function os::start::master() { os::log::debug "OpenShift server start at: $( date )" os::test::junit::declare_suite_start "setup/start-master" - os::cmd::try_until_text "oc get --raw /healthz --as system:unauthenticated --config='${ADMIN_KUBECONFIG}'" 'ok' $(( 160 * second )) 0.25 - os::cmd::try_until_text "oc get --raw /healthz/ready --as system:unauthenticated --config='${ADMIN_KUBECONFIG}'" 'ok' $(( 160 * second )) 0.25 - os::cmd::try_until_success "oc get service kubernetes --namespace default --config='${ADMIN_KUBECONFIG}'" $(( 160 * second )) 0.25 + os::cmd::try_until_text "oc get --raw /healthz --as system:unauthenticated --kubeconfig='${ADMIN_KUBECONFIG}'" 'ok' $(( 160 * second )) 0.25 + os::cmd::try_until_text "oc get --raw /healthz/ready --as system:unauthenticated --kubeconfig='${ADMIN_KUBECONFIG}'" 'ok' $(( 160 * second )) 0.25 + os::cmd::try_until_success "oc get service kubernetes --namespace default --kubeconfig='${ADMIN_KUBECONFIG}'" $(( 160 * second )) 0.25 # wait for lease acquisition that indicates the controllers and scheduler have successfully started - os::cmd::try_until_success "oc get configmap kube-controller-manager --namespace kube-system --config='${ADMIN_KUBECONFIG}'" $(( 160 * second )) 0.25 - os::cmd::try_until_success "oc get configmap openshift-master-controllers --namespace kube-system --config='${ADMIN_KUBECONFIG}'" $(( 160 * second )) 0.25 - os::cmd::try_until_success "oc get configmap kube-scheduler --namespace kube-system --config='${ADMIN_KUBECONFIG}'" $(( 160 * second )) 0.25 + os::cmd::try_until_success "oc get configmap kube-controller-manager --namespace kube-system --kubeconfig='${ADMIN_KUBECONFIG}'" $(( 160 * second )) 0.25 + os::cmd::try_until_success "oc get configmap openshift-master-controllers --namespace kube-system --kubeconfig='${ADMIN_KUBECONFIG}'" $(( 160 * second )) 0.25 + os::cmd::try_until_success "oc get configmap kube-scheduler --namespace kube-system --kubeconfig='${ADMIN_KUBECONFIG}'" $(( 160 * second )) 0.25 os::test::junit::declare_suite_end os::log::debug "OpenShift server health checks done at: $( date )" @@ -306,11 +306,11 @@ function os::start::all_in_one() { os::log::debug "OpenShift server start at: $( date )" os::test::junit::declare_suite_start "setup/start-all_in_one" - os::cmd::try_until_text "oc get --raw /healthz --as system:unauthenticated --config='${ADMIN_KUBECONFIG}'" 'ok' $(( 80 * second )) 0.25 - os::cmd::try_until_text "oc get --raw ${KUBELET_SCHEME}://${KUBELET_HOST}:${KUBELET_PORT}/healthz --as system:unauthenticated --config='${ADMIN_KUBECONFIG}'" 'ok' $(( 2 * minute )) 0.5 - os::cmd::try_until_text "oc get --raw /healthz/ready --as system:unauthenticated --config='${ADMIN_KUBECONFIG}'" 'ok' $(( 80 * second )) 0.25 - os::cmd::try_until_success "oc get service kubernetes --namespace default --config='${ADMIN_KUBECONFIG}'" $(( 160 * second )) 0.25 - os::cmd::try_until_success "oc get --raw /api/v1/nodes/${KUBELET_HOST} --config='${ADMIN_KUBECONFIG}'" $(( 80 * second )) 0.25 + os::cmd::try_until_text "oc get --raw /healthz --as system:unauthenticated --kubeconfig='${ADMIN_KUBECONFIG}'" 'ok' $(( 80 * second )) 0.25 + os::cmd::try_until_text "oc get --raw ${KUBELET_SCHEME}://${KUBELET_HOST}:${KUBELET_PORT}/healthz --as system:unauthenticated --kubeconfig='${ADMIN_KUBECONFIG}'" 'ok' $(( 2 * minute )) 0.5 + os::cmd::try_until_text "oc get --raw /healthz/ready --as system:unauthenticated --kubeconfig='${ADMIN_KUBECONFIG}'" 'ok' $(( 80 * second )) 0.25 + os::cmd::try_until_success "oc get service kubernetes --namespace default --kubeconfig='${ADMIN_KUBECONFIG}'" $(( 160 * second )) 0.25 + os::cmd::try_until_success "oc get --raw /api/v1/nodes/${KUBELET_HOST} --kubeconfig='${ADMIN_KUBECONFIG}'" $(( 80 * second )) 0.25 os::test::junit::declare_suite_end os::log::debug "OpenShift server health checks done at: $( date )" @@ -380,8 +380,8 @@ function os::start::api_server() { os::log::debug "OpenShift API server start at: $( date )" os::test::junit::declare_suite_start "setup/start-api_server" - os::cmd::try_until_text "oc get --raw /healthz --as system:unauthenticated --config='${ADMIN_KUBECONFIG}'" 'ok' $(( 80 * second )) 0.25 - os::cmd::try_until_text "oc get --raw /healthz/ready --as system:unauthenticated --config='${ADMIN_KUBECONFIG}'" 'ok' $(( 160 * second )) 0.25 + os::cmd::try_until_text "oc get --raw /healthz --as system:unauthenticated --kubeconfig='${ADMIN_KUBECONFIG}'" 'ok' $(( 80 * second )) 0.25 + os::cmd::try_until_text "oc get --raw /healthz/ready --as system:unauthenticated --kubeconfig='${ADMIN_KUBECONFIG}'" 'ok' $(( 160 * second )) 0.25 os::test::junit::declare_suite_end os::log::debug "OpenShift API server health checks done at: $( date )" @@ -446,7 +446,7 @@ function os::start::internal::start_node() { os::log::debug "OpenShift node start at: $( date )" os::test::junit::declare_suite_start "setup/start-node" - os::cmd::try_until_text "oc get --raw ${KUBELET_SCHEME}://${KUBELET_HOST}:${KUBELET_PORT}/healthz --as system:unauthenticated --config='${ADMIN_KUBECONFIG}'" 'ok' $(( 80 * second )) 0.25 + os::cmd::try_until_text "oc get --raw ${KUBELET_SCHEME}://${KUBELET_HOST}:${KUBELET_PORT}/healthz --as system:unauthenticated --kubeconfig='${ADMIN_KUBECONFIG}'" 'ok' $(( 80 * second )) 0.25 os::test::junit::declare_suite_end os::log::debug "OpenShift node health checks done at: $( date )" diff --git a/hack/update-generated.sh b/hack/update-generated.sh index 065c3db4b948..280c89cc1684 100755 --- a/hack/update-generated.sh +++ b/hack/update-generated.sh @@ -5,6 +5,10 @@ source "$(dirname "${BASH_SOURCE}")/lib/init.sh" # Update test names go generate -mod vendor ./test/extended +# Update mirror mapping from upstream to quay +echo "# This file is generated by hack/update-generated-bindata.sh" > test/extended/util/image/zz_generated.txt +go run -mod vendor ./cmd/openshift-tests images --upstream --to-repository quay.io/openshift/community-e2e-images >> test/extended/util/image/zz_generated.txt + os::build::setup_env OUTPUT_PARENT=${OUTPUT_ROOT:-$OS_ROOT} diff --git a/hack/verify-generated.sh b/hack/verify-generated.sh index 2089cf69254f..7c3428dd068f 100755 --- a/hack/verify-generated.sh +++ b/hack/verify-generated.sh @@ -12,5 +12,6 @@ trap "cleanup" EXIT os::test::junit::declare_suite_start "verify/generated" os::cmd::expect_success "${OS_ROOT}/hack/update-generated.sh" os::cmd::expect_success "git diff --quiet ${OS_ROOT}/test/extended/util/annotate/generated/" +os::cmd::expect_success "git diff --quiet ${OS_ROOT}/test/extended/util/image/zz_generated.txt" os::test::junit::declare_suite_end diff --git a/images/hello-openshift/Dockerfile.rhel b/images/hello-openshift/Dockerfile.rhel index d714a9fd43a5..f21d8aff3c9c 100644 --- a/images/hello-openshift/Dockerfile.rhel +++ b/images/hello-openshift/Dockerfile.rhel @@ -1,11 +1,9 @@ -#FROM registry.svc.ci.openshift.org/ocp/builder:rhel-8-golang-openshift-4.6 AS builder -FROM registry-proxy.engineering.redhat.com/rh-osbs/openshift-golang-builder:rhel_8_golang_1.14 AS builder +FROM registry.ci.openshift.org/ocp/builder:rhel-8-golang-1.15-openshift-4.7 AS builder WORKDIR /go/src/github.com/openshift/hello-openshift COPY examples/hello-openshift . RUN go build -o /hello-openshift -#FROM registry.svc.ci.openshift.org/ocp/builder:rhel-8-base-openshift-4.6 -FROM ubi8 +FROM registry.ci.openshift.org/ocp/4.7:base COPY --from=builder /hello-openshift /hello-openshift EXPOSE 8080 8888 USER 1001 diff --git a/images/hello-openshift/OWNERS b/images/hello-openshift/OWNERS new file mode 100644 index 000000000000..1f2b358a1040 --- /dev/null +++ b/images/hello-openshift/OWNERS @@ -0,0 +1,18 @@ +reviewers: + - mfojtik + - smarterclayton + - pweil- + - jwforres + - derekwaynecarr + - bparees + - knobunc + - adambkaplan + - sgreene570 +approvers: + - mfojtik + - smarterclayton + - pweil- + - jwforres + - derekwaynecarr + - sgreene570 +component: Routing diff --git a/pkg/monitor/api.go b/pkg/monitor/api.go index babb7b84123f..c9a9e1514eb0 100644 --- a/pkg/monitor/api.go +++ b/pkg/monitor/api.go @@ -3,30 +3,40 @@ package monitor import ( "context" "fmt" + "io/ioutil" + "net" + "net/http" "strings" "sync" "time" + "k8s.io/client-go/transport" + corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" - clientcorev1 "k8s.io/client-go/kubernetes/typed/core/v1" "k8s.io/client-go/rest" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" configclientset "github.com/openshift/client-go/config/clientset/versioned" - clientimagev1 "github.com/openshift/client-go/image/clientset/versioned/typed/image/v1" - clientoauthv1 "github.com/openshift/client-go/oauth/clientset/versioned/typed/oauth/v1" +) + +const ( + LocatorKubeAPIServerNewConnection = "kube-apiserver-new-connection" + LocatorOpenshiftAPIServerNewConnection = "openshift-apiserver-new-connection" + LocatorOAuthAPIServerNewConnection = "oauth-apiserver-new-connection" + LocatorKubeAPIServerReusedConnection = "kube-apiserver-reused-connection" + LocatorOpenshiftAPIServerReusedConnection = "openshift-apiserver-reused-connection" + LocatorOAuthAPIServerReusedConnection = "oauth-apiserver-reused-connection" ) // Start begins monitoring the cluster referenced by the default kube configuration until // context is finished. func Start(ctx context.Context) (*Monitor, error) { - m := NewMonitor() + m := NewMonitorWithInterval(time.Second) cfg := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(clientcmd.NewDefaultClientConfigLoadingRules(), &clientcmd.ConfigOverrides{}) clusterConfig, err := cfg.ClientConfig() if err != nil { @@ -41,13 +51,22 @@ func Start(ctx context.Context) (*Monitor, error) { return nil, err } - if err := StartKubeAPIMonitoring(ctx, m, clusterConfig, 5*time.Second); err != nil { + if err := StartKubeAPIMonitoringWithNewConnections(ctx, m, clusterConfig, 5*time.Second); err != nil { return nil, err } - if err := StartOpenShiftAPIMonitoring(ctx, m, clusterConfig, 5*time.Second); err != nil { + if err := StartOpenShiftAPIMonitoringWithNewConnections(ctx, m, clusterConfig, 5*time.Second); err != nil { return nil, err } - if err := StartOAuthAPIMonitoring(ctx, m, clusterConfig, 5*time.Second); err != nil { + if err := StartOAuthAPIMonitoringWithNewConnections(ctx, m, clusterConfig, 5*time.Second); err != nil { + return nil, err + } + if err := StartKubeAPIMonitoringWithConnectionReuse(ctx, m, clusterConfig, 5*time.Second); err != nil { + return nil, err + } + if err := StartOpenShiftAPIMonitoringWithConnectionReuse(ctx, m, clusterConfig, 5*time.Second); err != nil { + return nil, err + } + if err := StartOAuthAPIMonitoringWithConnectionReuse(ctx, m, clusterConfig, 5*time.Second); err != nil { return nil, err } startPodMonitoring(ctx, m, client) @@ -59,117 +78,131 @@ func Start(ctx context.Context) (*Monitor, error) { return m, nil } -func StartKubeAPIMonitoring(ctx context.Context, m *Monitor, clusterConfig *rest.Config, timeout time.Duration) error { - pollingConfig := *clusterConfig - pollingConfig.Timeout = timeout - pollingClient, err := clientcorev1.NewForConfig(&pollingConfig) - if err != nil { - return err - } +func StartServerMonitoringWithNewConnections(ctx context.Context, m *Monitor, clusterConfig *rest.Config, timeout time.Duration, resourceLocator, url string) error { + return startServerMonitoring(ctx, m, clusterConfig, timeout, resourceLocator, url, true) +} - m.AddSampler( - StartSampling(ctx, m, time.Second, func(previous bool) (condition *Condition, next bool) { - _, err := pollingClient.Namespaces().Get(ctx, "kube-system", metav1.GetOptions{}) - switch { - case err == nil && !previous: - condition = &Condition{ - Level: Info, - Locator: "kube-apiserver", - Message: "Kube API started responding to GET requests", - } - case err != nil && previous: - condition = &Condition{ - Level: Error, - Locator: "kube-apiserver", - Message: fmt.Sprintf("Kube API started failing: %v", err), - } - } - return condition, err == nil - }).ConditionWhenFailing(&Condition{ - Level: Error, - Locator: "kube-apiserver", - Message: fmt.Sprintf("Kube API is not responding to GET requests"), - }), - ) - return nil +func StartServerMonitoringWithConnectionReuse(ctx context.Context, m *Monitor, clusterConfig *rest.Config, timeout time.Duration, resourceLocator, url string) error { + return startServerMonitoring(ctx, m, clusterConfig, timeout, resourceLocator, url, false) } -func StartOpenShiftAPIMonitoring(ctx context.Context, m *Monitor, clusterConfig *rest.Config, timeout time.Duration) error { - pollingConfig := *clusterConfig - pollingConfig.Timeout = timeout - pollingClient, err := clientimagev1.NewForConfig(&pollingConfig) +func startServerMonitoring(ctx context.Context, m *Monitor, clusterConfig *rest.Config, timeout time.Duration, resourceLocator, url string, disableConnectionReuse bool) error { + kubeTransportConfig, err := clusterConfig.TransportConfig() if err != nil { return err } - - m.AddSampler( - StartSampling(ctx, m, time.Second, func(previous bool) (condition *Condition, next bool) { - _, err := pollingClient.ImageStreams("openshift-apiserver").Get(ctx, "missing", metav1.GetOptions{}) - if !errors.IsUnexpectedServerError(err) && errors.IsNotFound(err) { - err = nil - } - switch { - case err == nil && !previous: - condition = &Condition{ - Level: Info, - Locator: "openshift-apiserver", - Message: "OpenShift API started responding to GET requests", - } - case err != nil && previous: - condition = &Condition{ - Level: Info, - Locator: "openshift-apiserver", - Message: fmt.Sprintf("OpenShift API stopped responding to GET requests: %v", err), - } - } - return condition, err == nil - }).ConditionWhenFailing(&Condition{ - Level: Error, - Locator: "openshift-apiserver", - Message: fmt.Sprintf("OpenShift API is not responding to GET requests"), - }), - ) - return nil -} - -func StartOAuthAPIMonitoring(ctx context.Context, m *Monitor, clusterConfig *rest.Config, timeout time.Duration) error { - pollingConfig := *clusterConfig - pollingConfig.Timeout = timeout - pollingClient, err := clientoauthv1.NewForConfig(&pollingConfig) + tlsConfig, err := transport.TLSConfigFor(kubeTransportConfig) if err != nil { return err } + var httpTransport *http.Transport + + if disableConnectionReuse { + httpTransport = &http.Transport{ + Dial: (&net.Dialer{ + Timeout: timeout, + KeepAlive: -1, // this looks unnecessary to me, but it was set in other code. + }).Dial, + TLSClientConfig: tlsConfig, + TLSHandshakeTimeout: timeout, + DisableKeepAlives: true, // this prevents connections from being reused + IdleConnTimeout: timeout, + } + } else { + httpTransport = &http.Transport{ + Dial: (&net.Dialer{ + Timeout: timeout, + }).Dial, + TLSClientConfig: tlsConfig, + TLSHandshakeTimeout: timeout, + IdleConnTimeout: timeout, + } + } + + roundTripper := http.RoundTripper(httpTransport) + if kubeTransportConfig.HasTokenAuth() { + roundTripper, err = transport.NewBearerAuthWithRefreshRoundTripper(kubeTransportConfig.BearerToken, kubeTransportConfig.BearerTokenFile, httpTransport) + if err != nil { + return err + } + + } + + httpClient := http.Client{ + Transport: roundTripper, + } m.AddSampler( StartSampling(ctx, m, time.Second, func(previous bool) (condition *Condition, next bool) { - _, err := pollingClient.OAuthAccessTokens().Get(ctx, "missing", metav1.GetOptions{}) - if !errors.IsUnexpectedServerError(err) && errors.IsNotFound(err) { - err = nil + resp, err := httpClient.Get(clusterConfig.Host + url) + + // we don't have an error, but the response code was an error, then we have to set an artificial error for the logic below to work. + if err == nil && (resp.StatusCode < 200 || resp.StatusCode > 399) { + body, err := ioutil.ReadAll(resp.Body) + if err == nil { + err = fmt.Errorf("error running request: %v: %v", resp.Status, string(body)) + } else { + err = fmt.Errorf("error running request: %v", resp.Status) + } + } + if resp != nil && resp.Body != nil { + defer resp.Body.Close() } + switch { case err == nil && !previous: condition = &Condition{ Level: Info, - Locator: "oauth-apiserver", - Message: "OAuth API started responding to GET requests", + Locator: resourceLocator, + Message: fmt.Sprintf("%s started responding to GET requests", resourceLocator), } case err != nil && previous: condition = &Condition{ - Level: Info, - Locator: "oauth-apiserver", - Message: fmt.Sprintf("OAuth API stopped responding to GET requests: %v", err), + Level: Error, + Locator: resourceLocator, + Message: fmt.Sprintf("%s started failing: %v", resourceLocator, err), } } return condition, err == nil }).ConditionWhenFailing(&Condition{ Level: Error, - Locator: "oauth-apiserver", - Message: fmt.Sprintf("OAuth API is not responding to GET requests"), + Locator: resourceLocator, + Message: fmt.Sprintf("%s is not responding to GET requests", resourceLocator), }), ) return nil } +func StartKubeAPIMonitoringWithNewConnections(ctx context.Context, m *Monitor, clusterConfig *rest.Config, timeout time.Duration) error { + // default gets auto-created, so this should always exist + return StartServerMonitoringWithNewConnections(ctx, m, clusterConfig, timeout, LocatorKubeAPIServerNewConnection, "/api/v1/namespaces/default") +} + +func StartOpenShiftAPIMonitoringWithNewConnections(ctx context.Context, m *Monitor, clusterConfig *rest.Config, timeout time.Duration) error { + // this request should never 404, but should be empty/small + return StartServerMonitoringWithNewConnections(ctx, m, clusterConfig, timeout, LocatorOpenshiftAPIServerNewConnection, "/apis/image.openshift.io/v1/namespaces/default/imagestreams") +} + +func StartOAuthAPIMonitoringWithNewConnections(ctx context.Context, m *Monitor, clusterConfig *rest.Config, timeout time.Duration) error { + // this should be relatively small and should not ever 404 + return StartServerMonitoringWithNewConnections(ctx, m, clusterConfig, timeout, LocatorOAuthAPIServerNewConnection, "/apis/oauth.openshift.io/v1/oauthclients") +} + +func StartKubeAPIMonitoringWithConnectionReuse(ctx context.Context, m *Monitor, clusterConfig *rest.Config, timeout time.Duration) error { + // default gets auto-created, so this should always exist + return StartServerMonitoringWithConnectionReuse(ctx, m, clusterConfig, timeout, LocatorKubeAPIServerReusedConnection, "/api/v1/namespaces/default") +} + +func StartOpenShiftAPIMonitoringWithConnectionReuse(ctx context.Context, m *Monitor, clusterConfig *rest.Config, timeout time.Duration) error { + // this request should never 404, but should be empty/small + return StartServerMonitoringWithConnectionReuse(ctx, m, clusterConfig, timeout, LocatorOpenshiftAPIServerReusedConnection, "/apis/image.openshift.io/v1/namespaces/default/imagestreams") +} + +func StartOAuthAPIMonitoringWithConnectionReuse(ctx context.Context, m *Monitor, clusterConfig *rest.Config, timeout time.Duration) error { + // this should be relatively small and should not ever 404 + return StartServerMonitoringWithConnectionReuse(ctx, m, clusterConfig, timeout, LocatorOAuthAPIServerReusedConnection, "/apis/oauth.openshift.io/v1/oauthclients") +} + func findContainerStatus(status []corev1.ContainerStatus, name string, position int) *corev1.ContainerStatus { if position < len(status) { if status[position].Name == name { diff --git a/pkg/monitor/resourcewatch/controller/configmonitor/crd_controller.go b/pkg/monitor/resourcewatch/controller/configmonitor/crd_controller.go index fba8701750a8..9323f222cb31 100644 --- a/pkg/monitor/resourcewatch/controller/configmonitor/crd_controller.go +++ b/pkg/monitor/resourcewatch/controller/configmonitor/crd_controller.go @@ -15,7 +15,7 @@ import ( "k8s.io/client-go/dynamic" "k8s.io/client-go/restmapper" "k8s.io/client-go/tools/cache" - "k8s.io/klog" + "k8s.io/klog/v2" "github.com/openshift/library-go/pkg/controller/factory" "github.com/openshift/library-go/pkg/operator/events" diff --git a/pkg/monitor/resourcewatch/storage/git_store.go b/pkg/monitor/resourcewatch/storage/git_store.go index 0499895aef2a..2166dda36187 100644 --- a/pkg/monitor/resourcewatch/storage/git_store.go +++ b/pkg/monitor/resourcewatch/storage/git_store.go @@ -18,7 +18,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/tools/cache" - "k8s.io/klog" + "k8s.io/klog/v2" "sigs.k8s.io/yaml" ) diff --git a/pkg/monitor/sampler.go b/pkg/monitor/sampler.go index 3e30e198eb90..fa07d22bf10a 100644 --- a/pkg/monitor/sampler.go +++ b/pkg/monitor/sampler.go @@ -24,17 +24,18 @@ func StartSampling(ctx context.Context, recorder Recorder, interval time.Duratio ticker := time.NewTicker(interval) defer ticker.Stop() for { - select { - case <-ticker.C: - case <-ctx.Done(): - return - } success := s.isAvailable() condition, ok := sampleFn(success) if condition != nil { recorder.Record(*condition) } s.setAvailable(ok) + + select { + case <-ticker.C: + case <-ctx.Done(): + return + } } }() diff --git a/pkg/test/ginkgo/cmd_runsuite.go b/pkg/test/ginkgo/cmd_runsuite.go index 61fe96a803a4..1a253e252850 100644 --- a/pkg/test/ginkgo/cmd_runsuite.go +++ b/pkg/test/ginkgo/cmd_runsuite.go @@ -15,6 +15,7 @@ import ( "time" "github.com/openshift/origin/pkg/monitor" + "k8s.io/apimachinery/pkg/util/sets" "github.com/onsi/ginkgo/config" ) @@ -24,6 +25,7 @@ import ( type Options struct { Parallelism int Count int + FailFast bool Timeout time.Duration JUnitDir string TestFile string @@ -34,30 +36,29 @@ type Options struct { // MatchFn if set is also used to filter the suite contents MatchFn func(name string) bool - // AdditionalJUnitsFn allows the caller to translate events or outside + // SyntheticEventTests allows the caller to translate events or outside // context into a failure. - AdditionalJUnitsFn func(events monitor.EventIntervals) (results []*JUnitTestCase, passed bool) + SyntheticEventTests JUnitsForEvents IncludeSuccessOutput bool - Provider string - SuiteOptions string - - Suites []*TestSuite + CommandEnv []string DryRun bool PrintCommands bool Out, ErrOut io.Writer + + StartTime time.Time } func (opt *Options) AsEnv() []string { var args []string - args = append(args, fmt.Sprintf("TEST_PROVIDER=%s", opt.Provider)) - args = append(args, fmt.Sprintf("TEST_SUITE_OPTIONS=%s", opt.SuiteOptions)) + args = append(args, fmt.Sprintf("TEST_SUITE_START_TIME=%d", opt.StartTime.Unix())) + args = append(args, opt.CommandEnv...) return args } -func (opt *Options) Run(args []string) error { +func (opt *Options) SelectSuite(suites []*TestSuite, args []string) (*TestSuite, error) { var suite *TestSuite if len(opt.TestFile) > 0 { @@ -66,26 +67,26 @@ func (opt *Options) Run(args []string) error { if opt.TestFile == "-" { in, err = ioutil.ReadAll(os.Stdin) if err != nil { - return err + return nil, err } } else { in, err = ioutil.ReadFile(opt.TestFile) } if err != nil { - return err + return nil, err } suite, err = newSuiteFromFile("files", in) if err != nil { - return fmt.Errorf("could not read test suite from input: %v", err) + return nil, fmt.Errorf("could not read test suite from input: %v", err) } } if suite == nil && len(args) == 0 { - fmt.Fprintf(opt.ErrOut, SuitesString(opt.Suites, "Select a test suite to run against the server:\n\n")) - return fmt.Errorf("specify a test suite to run, for example: %s run %s", filepath.Base(os.Args[0]), opt.Suites[0].Name) + fmt.Fprintf(opt.ErrOut, SuitesString(suites, "Select a test suite to run against the server:\n\n")) + return nil, fmt.Errorf("specify a test suite to run, for example: %s run %s", filepath.Base(os.Args[0]), suites[0].Name) } if suite == nil && len(args) > 0 { - for _, s := range opt.Suites { + for _, s := range suites { if s.Name == args[0] { suite = s break @@ -93,10 +94,13 @@ func (opt *Options) Run(args []string) error { } } if suite == nil { - fmt.Fprintf(opt.ErrOut, SuitesString(opt.Suites, "Select a test suite to run against the server:\n\n")) - return fmt.Errorf("suite %q does not exist", args[0]) + fmt.Fprintf(opt.ErrOut, SuitesString(suites, "Select a test suite to run against the server:\n\n")) + return nil, fmt.Errorf("suite %q does not exist", args[0]) } + return suite, nil +} +func (opt *Options) Run(suite *TestSuite) error { if len(opt.Regex) > 0 { if err := filterWithRegex(suite, opt.Regex); err != nil { return err @@ -109,6 +113,11 @@ func (opt *Options) Run(args []string) error { } } + syntheticEventTests := JUnitsForAllEvents{ + opt.SyntheticEventTests, + suite.SyntheticEventTests, + } + tests, err := testsForSuite(config.GinkgoConfig) if err != nil { return err @@ -139,17 +148,15 @@ func (opt *Options) Run(args []string) error { if count == 0 { count = suite.Count } - if count > 1 { - var newTests []*testCase - for i := 0; i < count; i++ { - newTests = append(newTests, tests...) - } - tests = newTests + + start := time.Now() + if opt.StartTime.IsZero() { + opt.StartTime = start } if opt.PrintCommands { status := newTestStatus(opt.Out, true, len(tests), time.Minute, &monitor.Monitor{}, opt.AsEnv()) - newParallelTestQueue(tests).Execute(context.Background(), 1, status.OutputCommand) + newParallelTestQueue().Execute(context.Background(), tests, 1, status.OutputCommand) return nil } if opt.DryRun { @@ -209,10 +216,9 @@ func (opt *Options) Run(args []string) error { } // if we run a single test, always include success output includeSuccess := opt.IncludeSuccessOutput - if len(tests) == 1 { + if len(tests) == 1 && count == 1 { includeSuccess = true } - status := newTestStatus(opt.Out, includeSuccess, len(tests), timeout, m, opt.AsEnv()) early, normal := splitTests(tests, func(t *testCase) bool { return strings.Contains(t.name, "[Early]") @@ -222,20 +228,47 @@ func (opt *Options) Run(args []string) error { return strings.Contains(t.name, "[Late]") }) - // run the tests - start := time.Now() + expectedTestCount := len(early) + len(late) + if count != -1 { + original := normal + for i := 1; i < count; i++ { + normal = append(normal, copyTests(original)...) + } + } + expectedTestCount += len(normal) + + status := newTestStatus(opt.Out, includeSuccess, expectedTestCount, timeout, m, opt.AsEnv()) + testCtx := ctx + if opt.FailFast { + var cancelFn context.CancelFunc + testCtx, cancelFn = context.WithCancel(testCtx) + status.AfterTest(func(t *testCase) { + if t.failed { + cancelFn() + } + }) + } + + tests = nil - // run our Early tests first - q := newParallelTestQueue(early) - q.Execute(ctx, parallelism, status.Run) + // run our Early tests + q := newParallelTestQueue() + q.Execute(testCtx, early, parallelism, status.Run) + tests = append(tests, early...) - // run other tests next - q = newParallelTestQueue(normal) - q.Execute(ctx, parallelism, status.Run) + // repeat the normal suite until context cancel when in the forever loop + for i := 0; (i < 1 || count == -1) && testCtx.Err() == nil; i++ { + copied := copyTests(normal) + q.Execute(testCtx, copied, parallelism, status.Run) + tests = append(tests, copied...) + } // run Late test suits after everything else - q = newParallelTestQueue(late) - q.Execute(ctx, parallelism, status.Run) + q.Execute(testCtx, late, parallelism, status.Run) + tests = append(tests, late...) + + // calculate the effective test set we ran, excluding any incompletes + tests, _ = splitTests(tests, func(t *testCase) bool { return t.success || t.failed || t.skipped }) duration := time.Now().Sub(start).Round(time.Second / 10) if duration > time.Minute { @@ -248,15 +281,39 @@ func (opt *Options) Run(args []string) error { var syntheticTestResults []*JUnitTestCase var syntheticFailure bool if events := m.Events(time.Time{}, time.Time{}); len(events) > 0 { - var buf *bytes.Buffer eventsForTests := createEventsForTests(tests) + + var buf *bytes.Buffer syntheticTestResults, buf, _ = createSyntheticTestsFromMonitor(m, eventsForTests, duration) + testCases, passed := syntheticEventTests.JUnitsForEvents(events, duration) + syntheticTestResults = append(syntheticTestResults, testCases...) + if !passed { + syntheticFailure = true + } - if opt.AdditionalJUnitsFn != nil { - testCases, passed := opt.AdditionalJUnitsFn(events) - syntheticTestResults = append(syntheticTestResults, testCases...) - if !passed { - syntheticFailure = true + if len(syntheticTestResults) > 0 { + // mark any failures by name + failing, flaky := sets.NewString(), sets.NewString() + for _, test := range syntheticTestResults { + if test.FailureOutput != nil { + failing.Insert(test.Name) + } + } + // if a test has both a pass and a failure, flag it + // as a flake + for _, test := range syntheticTestResults { + if test.FailureOutput == nil { + if failing.Has(test.Name) { + flaky.Insert(test.Name) + } + } + } + failing = failing.Difference(flaky) + if failing.Len() > 0 { + fmt.Fprintf(buf, "Failing invariants:\n\n%s\n\n", strings.Join(failing.List(), "\n")) + } + if flaky.Len() > 0 { + fmt.Fprintf(buf, "Flaky invariants:\n\n%s\n\n", strings.Join(flaky.List(), "\n")) } } @@ -275,9 +332,9 @@ func (opt *Options) Run(args []string) error { } } - q := newParallelTestQueue(retries) + q := newParallelTestQueue() status := newTestStatus(ioutil.Discard, opt.IncludeSuccessOutput, len(retries), timeout, m, opt.AsEnv()) - q.Execute(ctx, parallelism, status.Run) + q.Execute(testCtx, retries, parallelism, status.Run) var flaky []string var repeatFailures []*testCase for _, test := range retries { @@ -294,9 +351,9 @@ func (opt *Options) Run(args []string) error { } } + // report the outcome of the test if len(failing) > 0 { - names := testNames(failing) - sort.Strings(names) + names := sets.NewString(testNames(failing)...).List() fmt.Fprintf(opt.Out, "Failing tests:\n\n%s\n\n", strings.Join(names, "\n")) } diff --git a/pkg/test/ginkgo/queue.go b/pkg/test/ginkgo/queue.go index c6f9a6a2ee5d..6f3d93b2d5dd 100644 --- a/pkg/test/ginkgo/queue.go +++ b/pkg/test/ginkgo/queue.go @@ -25,18 +25,11 @@ func (nopLock) Unlock() {} type TestFunc func(ctx context.Context, test *testCase) -func newParallelTestQueue(tests []*testCase) *parallelByFileTestQueue { - r := ring.New(len(tests)) - for _, test := range tests { - r.Value = test - r = r.Next() - } - q := ¶llelByFileTestQueue{ +func newParallelTestQueue() *parallelByFileTestQueue { + return ¶llelByFileTestQueue{ cond: sync.NewCond(nopLock{}), - queue: r, active: make(map[string]struct{}), } - return q } func (q *parallelByFileTestQueue) pop() (*testCase, bool) { @@ -99,39 +92,41 @@ func (q *parallelByFileTestQueue) Take(ctx context.Context, fn TestFunc) bool { } } -func (q *parallelByFileTestQueue) Execute(parentCtx context.Context, parallelism int, fn TestFunc) { - go func() { - <-parentCtx.Done() - q.Close() - }() - var serial []*testCase - var lock sync.Mutex +func (q *parallelByFileTestQueue) Execute(ctx context.Context, tests []*testCase, parallelism int, fn TestFunc) { + defer q.Close() + + if ctx.Err() != nil { + return + } + + serial, parallel := splitTests(tests, func(t *testCase) bool { return strings.Contains(t.name, "[Serial]") }) + + r := ring.New(len(parallel)) + for _, test := range parallel { + r.Value = test + r = r.Next() + } + q.queue = r + var wg sync.WaitGroup wg.Add(parallelism) for i := 0; i < parallelism; i++ { go func(i int) { - for q.Take(parentCtx, func(ctx context.Context, test *testCase) { - if strings.Contains(test.name, "[Serial]") { - lock.Lock() - defer lock.Unlock() - serial = append(serial, test) + defer wg.Done() + for q.Take(ctx, func(ctx context.Context, test *testCase) { fn(ctx, test) }) { + if ctx.Err() != nil { return } - fn(ctx, test) - }) { - // no-op } - wg.Done() }(i) } wg.Wait() + for _, test := range serial { - select { - case <-parentCtx.Done(): + if ctx.Err() != nil { return - default: } - fn(parentCtx, test) + fn(ctx, test) } } @@ -152,6 +147,15 @@ func setTestExclusion(tests []*testCase, fn func(suitePath string, t *testCase) } } +func copyTests(tests []*testCase) []*testCase { + copied := make([]*testCase, 0, len(tests)) + for _, t := range tests { + c := *t + copied = append(copied, &c) + } + return copied +} + func splitTests(tests []*testCase, fn func(*testCase) bool) (a, b []*testCase) { for _, t := range tests { if fn(t) { diff --git a/pkg/test/ginkgo/status.go b/pkg/test/ginkgo/status.go index 906721a08efd..cfb48d2ec01f 100644 --- a/pkg/test/ginkgo/status.go +++ b/pkg/test/ginkgo/status.go @@ -22,6 +22,8 @@ type testStatus struct { monitor monitor.Interface env []string + afterTestFn func(t *testCase) + includeSuccessfulOutput bool lock sync.Mutex @@ -42,21 +44,67 @@ func newTestStatus(out io.Writer, includeSuccessfulOutput bool, total int, timeo } } -func (s *testStatus) Failure() { - s.lock.Lock() - defer s.lock.Unlock() - s.failures++ +// AfterTest registers a function to be invoked after each test completes. +func (s *testStatus) AfterTest(fn func(t *testCase)) { + s.afterTestFn = fn } -func (s *testStatus) Fprintf(format string) { +// fprintf formats the provided string with the status of the test with arguments failures, index, and total +func (s *testStatus) fprintf(format string) { s.lock.Lock() defer s.lock.Unlock() if s.index < s.total { s.index++ + } else { + s.index++ + s.total++ } fmt.Fprintf(s.out, format, s.failures, s.index, s.total) } +// finalizeTest outputs the result of the test to s.out, increments s.failures if necessary, +// and invokes afterTestFn if registered. +func (s *testStatus) finalizeTest(test *testCase) { + s.lock.Lock() + defer s.lock.Unlock() + + // executed under the lock deliberately to prevent races in client code + if s.afterTestFn != nil { + defer s.afterTestFn(test) + } + + // output the status of the test + switch { + case test.flake: + s.out.Write(test.out) + fmt.Fprintln(s.out) + fmt.Fprintf(s.out, "flaked: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name) + case test.success: + if s.includeSuccessfulOutput { + s.out.Write(test.out) + fmt.Fprintln(s.out) + } + fmt.Fprintf(s.out, "passed: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name) + case test.skipped: + if s.includeSuccessfulOutput { + s.out.Write(test.out) + fmt.Fprintln(s.out) + } else { + message := lastLinesUntil(string(test.out), 100, "skip [") + if len(message) > 0 { + fmt.Fprintln(s.out, message) + fmt.Fprintln(s.out) + } + } + fmt.Fprintf(s.out, "skipped: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name) + case test.failed: + s.failures++ + s.out.Write(test.out) + fmt.Fprintln(s.out) + fmt.Fprintf(s.out, "failed: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name) + } +} + // OutputCommand prints to stdout what would have been executed. func (s *testStatus) OutputCommand(ctx context.Context, test *testCase) { buf := &bytes.Buffer{} @@ -69,52 +117,12 @@ func (s *testStatus) OutputCommand(ctx context.Context, test *testCase) { } func (s *testStatus) Run(ctx context.Context, test *testCase) { - defer func() { - switch { - case test.flake: - s.out.Write(test.out) - fmt.Fprintln(s.out) - fmt.Fprintf(s.out, "flaked: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name) - case test.success: - if s.includeSuccessfulOutput { - s.out.Write(test.out) - fmt.Fprintln(s.out) - } - fmt.Fprintf(s.out, "passed: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name) - case test.skipped: - if s.includeSuccessfulOutput { - s.out.Write(test.out) - fmt.Fprintln(s.out) - } else { - message := lastLinesUntil(string(test.out), 100, "skip [") - if len(message) > 0 { - fmt.Fprintln(s.out, message) - fmt.Fprintln(s.out) - } - } - fmt.Fprintf(s.out, "skipped: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name) - case test.failed: - s.out.Write(test.out) - fmt.Fprintln(s.out) - // only write the monitor output for a test if there is more than two tests being run (otherwise it's redundant) - if s.monitor != nil && s.total > 2 { - events := s.monitor.Events(test.start, test.end) - if len(events) > 0 { - for _, event := range events { - fmt.Fprintln(s.out, event.String()) - } - fmt.Fprintln(s.out) - } - } - fmt.Fprintf(s.out, "failed: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name) - s.Failure() - } - }() + defer s.finalizeTest(test) test.start = time.Now() c := exec.Command(os.Args[0], "run-test", test.name) c.Env = append(os.Environ(), s.env...) - s.Fprintf(fmt.Sprintf("started: (%s) %q\n\n", "%d/%d/%d", test.name)) + s.fprintf(fmt.Sprintf("started: (%s) %q\n\n", "%d/%d/%d", test.name)) out, err := runWithTimeout(ctx, c, s.timeout) test.end = time.Now() @@ -128,6 +136,15 @@ func (s *testStatus) Run(ctx context.Context, test *testCase) { test.success = true return } + + if ctx.Err() != nil { + test.skipped = true + test.flake = false + test.failed = false + test.success = false + return + } + if exitErr, ok := err.(*exec.ExitError); ok { switch exitErr.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() { case 1: diff --git a/pkg/test/ginkgo/synthentic_tests.go b/pkg/test/ginkgo/synthentic_tests.go index 203865390c80..933297941674 100644 --- a/pkg/test/ginkgo/synthentic_tests.go +++ b/pkg/test/ginkgo/synthentic_tests.go @@ -4,12 +4,46 @@ import ( "bytes" "fmt" "sort" - "strings" "time" "github.com/openshift/origin/pkg/monitor" ) +// JUnitsForEvents returns a set of JUnit results for the provided events encountered +// during a test suite run. +type JUnitsForEvents interface { + // JUnitsForEvents returns a set of additional test passes or failures implied by the + // events sent during the test suite run. If passed is false, the entire suite is failed. + // To set a test as flaky, return a passing and failing JUnitTestCase with the same name. + JUnitsForEvents(events monitor.EventIntervals, duration time.Duration) (results []*JUnitTestCase, passed bool) +} + +// JUnitForEventsFunc converts a function into the JUnitForEvents interface. +type JUnitForEventsFunc func(events monitor.EventIntervals, duration time.Duration) (results []*JUnitTestCase, passed bool) + +func (fn JUnitForEventsFunc) JUnitsForEvents(events monitor.EventIntervals, duration time.Duration) (results []*JUnitTestCase, passed bool) { + return fn(events, duration) +} + +// JUnitsForAllEvents aggregates multiple JUnitsForEvent interfaces and returns +// the result of all invocations. It ignores nil interfaces. +type JUnitsForAllEvents []JUnitsForEvents + +func (a JUnitsForAllEvents) JUnitsForEvents(events monitor.EventIntervals, duration time.Duration) (all []*JUnitTestCase, passed bool) { + passed = true + for _, obj := range a { + if obj == nil { + continue + } + results, passed := obj.JUnitsForEvents(events, duration) + if !passed { + passed = false + } + all = append(all, results...) + } + return all, passed +} + func createEventsForTests(tests []*testCase) []*monitor.EventInterval { eventsForTests := []*monitor.EventInterval{} for _, test := range tests { @@ -79,152 +113,5 @@ func createSyntheticTestsFromMonitor(m *monitor.Monitor, eventsForTests []*monit ) } - // check events - syntheticTestResults = append(syntheticTestResults, testKubeAPIServerGracefulTermination(events)...) - syntheticTestResults = append(syntheticTestResults, testPodTransitions(events)...) - syntheticTestResults = append(syntheticTestResults, testSystemDTimeout(events)...) - syntheticTestResults = append(syntheticTestResults, testPodSandboxCreation(events)...) - return syntheticTestResults, buf, errBuf } - -func testKubeAPIServerGracefulTermination(events []*monitor.EventInterval) []*JUnitTestCase { - const testName = "[sig-node] kubelet terminates kube-apiserver gracefully" - success := &JUnitTestCase{Name: testName} - - failures := []string{} - for _, event := range events { - // from https://github.com/openshift/kubernetes/blob/1f35e4f63be8fbb19e22c9ff1df31048f6b42ddf/cmd/watch-termination/main.go#L96 - if strings.Contains(event.Message, "did not terminate gracefully") { - failures = append(failures, fmt.Sprintf("%v - %v", event.Locator, event.Message)) - } - } - if len(failures) == 0 { - return []*JUnitTestCase{success} - } - - failure := &JUnitTestCase{ - Name: testName, - SystemOut: strings.Join(failures, "\n"), - FailureOutput: &FailureOutput{ - Output: fmt.Sprintf("%d kube-apiserver reports a non-graceful termination. Probably kubelet or CRI-O is not giving the time to cleanly shut down. This can lead to connection refused and network I/O timeout errors in other components.\n\n%v", len(failures), strings.Join(failures, "\n")), - }, - } - - // This should fail a CI run, not flake it. - return []*JUnitTestCase{failure} - -} - -func testPodTransitions(events []*monitor.EventInterval) []*JUnitTestCase { - const testName = "[sig-node] pods should never transition back to pending" - success := &JUnitTestCase{Name: testName} - - failures := []string{} - for _, event := range events { - if strings.Contains(event.Message, "pod should not transition") || strings.Contains(event.Message, "pod moved back to Pending") { - failures = append(failures, fmt.Sprintf("%v - %v", event.Locator, event.Message)) - } - } - if len(failures) == 0 { - return []*JUnitTestCase{success} - } - - failure := &JUnitTestCase{ - Name: testName, - SystemOut: strings.Join(failures, "\n"), - FailureOutput: &FailureOutput{ - Output: fmt.Sprintf("%d pods illegally transitioned to Pending\n\n%v", len(failures), strings.Join(failures, "\n")), - }, - } - - // write a passing test to trigger detection of this issue as a flake. Doing this first to try to see how frequent the issue actually is - return []*JUnitTestCase{failure, success} -} - -func testSystemDTimeout(events []*monitor.EventInterval) []*JUnitTestCase { - const testName = "[sig-node] pods should not fail on systemd timeouts" - success := &JUnitTestCase{Name: testName} - - failures := []string{} - for _, event := range events { - if strings.Contains(event.Message, "systemd timed out for pod") { - failures = append(failures, fmt.Sprintf("%v - %v", event.Locator, event.Message)) - } - } - if len(failures) == 0 { - return []*JUnitTestCase{success} - } - - failure := &JUnitTestCase{ - Name: testName, - SystemOut: strings.Join(failures, "\n"), - FailureOutput: &FailureOutput{ - Output: fmt.Sprintf("%d systemd timed out for pod occurrences\n\n%v", len(failures), strings.Join(failures, "\n")), - }, - } - - // write a passing test to trigger detection of this issue as a flake. Doing this first to try to see how frequent the issue actually is - return []*JUnitTestCase{failure, success} -} - -func testPodSandboxCreation(events []*monitor.EventInterval) []*JUnitTestCase { - const testName = "[sig-network] pods should successfully create sandboxes" - // we can further refine this signal by subdividing different failure modes if it is pertinent. Right now I'm seeing - // 1. error reading container (probably exited) json message: EOF - // 2. dial tcp 10.0.76.225:6443: i/o timeout - // 3. error getting pod: pods "terminate-cmd-rpofb45fa14c-96bb-40f7-bd9e-346721740cac" not found - // 4. write child: broken pipe - bySubStrings := []struct { - by string - substring string - }{ - {by: " by reading container", substring: "error reading container (probably exited) json message: EOF"}, - {by: " by not timing out", substring: "i/o timeout"}, - {by: " by writing network status", substring: "error setting the networks status"}, - {by: " by getting pod", substring: " error getting pod: pods"}, - {by: " by writing child", substring: "write child: broken pipe"}, - {by: " by other", substring: " "}, // always matches - } - - successes := []*JUnitTestCase{} - for _, by := range bySubStrings { - successes = append(successes, &JUnitTestCase{Name: testName + by.by}) - } - - failures := []string{} - for _, event := range events { - if strings.Contains(event.Message, "reason/FailedCreatePodSandBox Failed to create pod sandbox") { - failures = append(failures, fmt.Sprintf("%v - %v", event.Locator, event.Message)) - } - } - if len(failures) == 0 { - return successes - } - - ret := []*JUnitTestCase{} - failuresBySubtest := map[string][]string{} - for _, failure := range failures { - for _, by := range bySubStrings { - if strings.Contains(failure, by.substring) { - failuresBySubtest[by.by] = append(failuresBySubtest[by.by], failure) - break // break after first match so we only add each failure one bucket - } - } - } - - // now iterate the individual failures to create failure entries - for by, subFailures := range failuresBySubtest { - failure := &JUnitTestCase{ - Name: testName + by, - SystemOut: strings.Join(subFailures, "\n"), - FailureOutput: &FailureOutput{ - Output: fmt.Sprintf("%d failures to create the sandbox\n\n%v", len(subFailures), strings.Join(subFailures, "\n")), - }, - } - ret = append(ret, failure) - } - - // write a passing test to trigger detection of this issue as a flake. Doing this first to try to see how frequent the issue actually is - return append(ret, successes...) -} diff --git a/pkg/test/ginkgo/test.go b/pkg/test/ginkgo/test.go index cd8e5c7a7a73..3c98fa50e165 100644 --- a/pkg/test/ginkgo/test.go +++ b/pkg/test/ginkgo/test.go @@ -63,10 +63,6 @@ type TestSuite struct { Matches func(name string) bool - // Init should be run once before a test in this suite is run. Not called by - // methods in this package. - Init func(map[string]string) error - // The number of times to execute each test in this suite. Count int // The maximum parallelism of this suite. @@ -74,6 +70,9 @@ type TestSuite struct { // The number of flakes that may occur before this test is marked as a failure. MaximumAllowedFlakes int + // SyntheticEventTests is a set of suite level synthetics applied + SyntheticEventTests JUnitsForEvents + TestTimeout time.Duration } diff --git a/test/e2e/upgrade/alert/alert.go b/test/e2e/upgrade/alert/alert.go index cd13f40404e7..800feb9505ce 100644 --- a/test/e2e/upgrade/alert/alert.go +++ b/test/e2e/upgrade/alert/alert.go @@ -6,6 +6,7 @@ import ( "time" g "github.com/onsi/ginkgo" + o "github.com/onsi/gomega" exutil "github.com/openshift/origin/test/extended/util" helper "github.com/openshift/origin/test/extended/util/prometheus" @@ -69,12 +70,12 @@ func (t *UpgradeTest) Test(f *framework.Framework, done <-chan struct{}, upgrade time.Sleep(alertCheckSleep) cancel() - if helper.TestUnsupportedAllowVersionSkew() { + if exutil.TolerateVersionSkewInTests() { e2eskipper.Skipf("Test is disabled to allow cluster components to have different versions, and skewed versions trigger multiple other alerts") } t.oc.SetupProject() ns := t.oc.Namespace() - execPod := exutil.CreateUbiExecPodOrFail(t.oc.AdminKubeClient(), ns, "execpod", nil) + execPod := exutil.CreateExecPodOrFail(t.oc.AdminKubeClient(), ns, "execpod") defer func() { t.oc.AdminKubeClient().CoreV1().Pods(ns).Delete(ctx, execPod.Name, *metav1.NewDeleteOptions(1)) }() @@ -91,7 +92,8 @@ func (t *UpgradeTest) Test(f *framework.Framework, done <-chan struct{}, upgrade criticalAlertQuery: false, } - helper.RunQueries(tests, t.oc, ns, execPod.Name, t.url, t.bearerToken) + err := helper.RunQueries(tests, t.oc, ns, execPod.Name, t.url, t.bearerToken) + o.Expect(err).NotTo(o.HaveOccurred()) framework.Logf("No critical alerts firing post-upgrade") } diff --git a/test/e2e/upgrade/monitor.go b/test/e2e/upgrade/monitor.go index afb095052732..2998e010e4d9 100644 --- a/test/e2e/upgrade/monitor.go +++ b/test/e2e/upgrade/monitor.go @@ -20,6 +20,7 @@ import ( configv1 "github.com/openshift/api/config/v1" configv1client "github.com/openshift/client-go/config/clientset/versioned" "github.com/openshift/origin/test/extended/util/disruption" + "github.com/openshift/origin/test/extended/util/image" ) type versionMonitor struct { @@ -155,13 +156,17 @@ func (m *versionMonitor) Describe(f *framework.Framework) { disruption.RecordJUnitResult(f, fmt.Sprintf("Operator upgrade %s", item.Name), 0, "") } + newVersion := "" + if m.lastCV != nil { + newVersion = m.lastCV.Status.Desired.Version + } fmt.Fprintf(tw, "%s\t%s %s %s\t%s\t%s\n", item.Name, findConditionShortStatus(available, configv1.ConditionTrue), findConditionShortStatus(degraded, configv1.ConditionFalse), findConditionShortStatus(progressing, configv1.ConditionFalse), - findVersion(item.Status.Versions, "operator", m.oldVersion, m.lastCV.Status.Desired.Version), + findVersion(item.Status.Versions, "operator", m.oldVersion, newVersion), findConditionMessage(item.Status.Conditions, configv1.OperatorProgressing), ) } @@ -336,7 +341,7 @@ func triggerReboot(kubeClient kubernetes.Interface, target string, attempt int, RunAsUser: &zero, Privileged: &isTrue, }, - Image: "ubi8/ubi", + Image: image.ShellImage(), Command: []string{ "/bin/bash", "-c", diff --git a/test/e2e/upgrade/upgrade.go b/test/e2e/upgrade/upgrade.go index be1777077356..ba1f3984a94b 100644 --- a/test/e2e/upgrade/upgrade.go +++ b/test/e2e/upgrade/upgrade.go @@ -31,13 +31,18 @@ import ( "github.com/openshift/origin/test/extended/util/disruption" "github.com/openshift/origin/test/extended/util/disruption/controlplane" "github.com/openshift/origin/test/extended/util/disruption/frontends" + "github.com/openshift/origin/test/extended/util/disruption/imageregistry" + "github.com/openshift/origin/test/extended/util/operator" ) func AllTests() []upgrades.Test { return []upgrades.Test{ - controlplane.NewKubeAvailableTest(), - controlplane.NewOpenShiftAvailableTest(), - controlplane.NewOAuthAvailableTest(), + controlplane.NewKubeAvailableWithNewConnectionsTest(), + controlplane.NewOpenShiftAvailableNewConnectionsTest(), + controlplane.NewOAuthAvailableNewConnectionsTest(), + controlplane.NewKubeAvailableWithConnectionReuseTest(), + controlplane.NewOpenShiftAvailableWithConnectionReuseTest(), + controlplane.NewOAuthAvailableWithConnectionReuseTest(), &alert.UpgradeTest{}, &frontends.AvailableTest{}, &service.UpgradeTest{}, @@ -48,6 +53,7 @@ func AllTests() []upgrades.Test { &apps.JobUpgradeTest{}, &upgrades.ConfigMapUpgradeTest{}, &apps.DaemonSetUpgradeTest{}, + &imageregistry.AvailableTest{}, } } @@ -434,6 +440,19 @@ func clusterUpgrade(f *framework.Framework, c configv1client.Interface, dc dynam return err } + if err := disruption.RecordJUnit( + f, + "[sig-cluster-lifecycle] ClusterOperators are available and not degraded after upgrade", + func() error { + if err := operator.WaitForOperatorsToSettle(context.TODO(), c); err != nil { + return err + } + return nil + }, + ); err != nil { + return err + } + return nil } diff --git a/test/extended/OWNERS b/test/extended/OWNERS index b99a729c0fbd..16c3416c3746 100644 --- a/test/extended/OWNERS +++ b/test/extended/OWNERS @@ -9,6 +9,7 @@ reviewers: - adambkaplan approvers: - smarterclayton + - ashcrow - bparees - mfojtik - knobunc diff --git a/test/extended/apiserver/graceful_termination.go b/test/extended/apiserver/graceful_termination.go index 9d5584195ab9..4dded758d7ba 100644 --- a/test/extended/apiserver/graceful_termination.go +++ b/test/extended/apiserver/graceful_termination.go @@ -15,7 +15,7 @@ import ( var _ = g.Describe("[sig-api-machinery][Feature:APIServer][Late]", func() { defer g.GinkgoRecover() - oc := exutil.NewCLI("terminating-kube-apiserver") + oc := exutil.NewCLIWithoutNamespace("terminating-kube-apiserver") g.It("kubelet terminates kube-apiserver gracefully", func() { t := g.GinkgoT() @@ -30,7 +30,11 @@ var _ = g.Describe("[sig-api-machinery][Feature:APIServer][Late]", func() { g.Fail(fmt.Sprintf("Unexpected error: %v", err)) } + eventsAfterTime := exutil.LimitTestsToStartTime() for _, ev := range evs.Items { + if ev.LastTimestamp.Time.Before(eventsAfterTime) { + continue + } if ev.Reason != "NonGracefulTermination" { continue } @@ -52,7 +56,11 @@ var _ = g.Describe("[sig-api-machinery][Feature:APIServer][Late]", func() { g.Fail(fmt.Sprintf("Unexpected error: %v", err)) } + eventsAfterTime := exutil.LimitTestsToStartTime() for _, ev := range evs.Items { + if ev.LastTimestamp.Time.Before(eventsAfterTime) { + continue + } if ev.Reason != "GracefulTerminationTimeout" { continue } @@ -74,7 +82,11 @@ var _ = g.Describe("[sig-api-machinery][Feature:APIServer][Late]", func() { g.Fail(fmt.Sprintf("Unexpected error: %v", err)) } + eventsAfterTime := exutil.LimitTestsToStartTime() for _, ev := range evs.Items { + if ev.LastTimestamp.Time.Before(eventsAfterTime) { + continue + } if ev.Reason != "LateConnections" { continue } @@ -96,7 +108,11 @@ var _ = g.Describe("[sig-api-machinery][Feature:APIServer][Late]", func() { g.Fail(fmt.Sprintf("Unexpected error: %v", err)) } + eventsAfterTime := exutil.LimitTestsToStartTime() for _, ev := range evs.Items { + if ev.LastTimestamp.Time.Before(eventsAfterTime) { + continue + } if ev.Reason != "NonReadyRequests" { continue } diff --git a/test/extended/apiserver/kubeconfigs.go b/test/extended/apiserver/kubeconfigs.go index 21fe39fac7c6..af01a58e8db6 100644 --- a/test/extended/apiserver/kubeconfigs.go +++ b/test/extended/apiserver/kubeconfigs.go @@ -32,7 +32,7 @@ var _ = g.Describe("[Conformance][sig-api-machinery][Feature:APIServer] local ku g.By("Testing master node " + master.Name) kubeconfigPath := "/etc/kubernetes/static-pod-resources/kube-apiserver-certs/secrets/node-kubeconfigs/" + kubeconfig framework.Logf("Verifying kubeconfig %q on master %s", master.Name) - out, err := oc.AsAdmin().Run("debug").Args("node/"+master.Name, "--image=registry.access.redhat.com/ubi8/ubi-minimal:latest", "--", "chroot", "/host", "/bin/bash", "-euxo", "pipefail", "-c", fmt.Sprintf(`oc --kubeconfig "%s" get namespace kube-system`, kubeconfigPath)).Output() + out, err := oc.AsAdmin().Run("debug").Args("node/"+master.Name, "--", "chroot", "/host", "/bin/bash", "-euxo", "pipefail", "-c", fmt.Sprintf(`oc --kubeconfig "%s" get namespace kube-system`, kubeconfigPath)).Output() o.Expect(err).NotTo(o.HaveOccurred()) framework.Logf(out) } diff --git a/test/extended/builds/clone_git_protocol.go b/test/extended/builds/clone_git_protocol.go new file mode 100644 index 000000000000..6da9bb9772b4 --- /dev/null +++ b/test/extended/builds/clone_git_protocol.go @@ -0,0 +1,48 @@ +package builds + +import ( + g "github.com/onsi/ginkgo" + o "github.com/onsi/gomega" + + exutil "github.com/openshift/origin/test/extended/util" +) + +var _ = g.Describe("[sig-builds][Feature:Builds] clone repository using git:// protocol", func() { + var ( + oc = exutil.NewCLI("build-clone-git-protocol") + ) + + g.Context("", func() { + + g.BeforeEach(func() { + exutil.PreTestDump() + }) + + g.JustBeforeEach(func() { + g.By("waiting for openshift namespace imagestreams") + err := exutil.WaitForOpenShiftNamespaceImageStreams(oc) + o.Expect(err).NotTo(o.HaveOccurred()) + + }) + + g.AfterEach(func() { + if g.CurrentGinkgoTestDescription().Failed { + exutil.DumpPodStates(oc) + exutil.DumpConfigMapStates(oc) + exutil.DumpPodLogsStartingWith("", oc) + } + }) + + g.It("should clone using git:// if no proxy is configured", func() { + proxyConfigured, err := exutil.IsClusterProxyEnabled(oc) + o.Expect(err).NotTo(o.HaveOccurred()) + if proxyConfigured { + g.Skip("Skipping test because proxy is configured") + } + + g.By("creating a new application using the git:// protocol") + err = oc.Run("new-app").Args("git://github.com/sclorg/ruby-ex.git").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + }) + }) +}) diff --git a/test/extended/builds/contextdir.go b/test/extended/builds/contextdir.go index 574031400e41..d27c28582d8c 100644 --- a/test/extended/builds/contextdir.go +++ b/test/extended/builds/contextdir.go @@ -10,6 +10,7 @@ import ( imageeco "github.com/openshift/origin/test/extended/image_ecosystem" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -102,7 +103,7 @@ var _ = g.Describe("[sig-builds][Feature:Builds][Slow] builds with a context dir repo, err := exutil.NewGitRepo("contextdir") o.Expect(err).NotTo(o.HaveOccurred()) defer repo.Remove() - err = repo.AddAndCommit("2.3/Dockerfile", "FROM image-registry.openshift-image-registry.svc:5000/openshift/tools:latest") + err = repo.AddAndCommit("2.3/Dockerfile", fmt.Sprintf("FROM %s", image.ShellImage())) o.Expect(err).NotTo(o.HaveOccurred()) exutil.WaitForOpenShiftNamespaceImageStreams(oc) diff --git a/test/extended/builds/controllers.go b/test/extended/builds/controllers.go index 668d99080fed..ab34e0751fca 100644 --- a/test/extended/builds/controllers.go +++ b/test/extended/builds/controllers.go @@ -589,7 +589,7 @@ func configChangeBuildConfig(ns string) *buildv1.BuildConfig { bc.Name = "testcfgbc" bc.Namespace = ns bc.Spec.Source.Git = &buildv1.GitBuildSource{} - bc.Spec.Source.Git.URI = "git://github.com/openshift/ruby-hello-world.git" + bc.Spec.Source.Git.URI = "https://github.com/openshift/ruby-hello-world.git" bc.Spec.Strategy.DockerStrategy = &buildv1.DockerBuildStrategy{} configChangeTrigger := buildv1.BuildTriggerPolicy{Type: buildv1.ConfigChangeBuildTriggerType} bc.Spec.Triggers = append(bc.Spec.Triggers, configChangeTrigger) @@ -642,7 +642,7 @@ func imageChangeBuildConfig(ns, name string, strategy buildv1.BuildStrategy) *bu CommonSpec: buildv1.CommonSpec{ Source: buildv1.BuildSource{ Git: &buildv1.GitBuildSource{ - URI: "git://github.com/openshift/ruby-hello-world.git", + URI: "https://github.com/openshift/ruby-hello-world.git", }, ContextDir: "contextimage", }, diff --git a/test/extended/builds/digest.go b/test/extended/builds/digest.go index e0012537a2b1..120de9e8e4a6 100644 --- a/test/extended/builds/digest.go +++ b/test/extended/builds/digest.go @@ -14,7 +14,7 @@ import ( var _ = g.Describe("[sig-builds][Feature:Builds][Slow] completed builds should have digest of the image in their status", func() { defer g.GinkgoRecover() var ( - imageStreamFixture = exutil.FixturePath("..", "integration", "testdata", "test-image-stream.json") + imageStreamFixture = exutil.FixturePath("testdata", "builds", "test-image-stream.json") stiBuildFixture = exutil.FixturePath("testdata", "builds", "test-s2i-build.json") dockerBuildFixture = exutil.FixturePath("testdata", "builds", "test-docker-build.json") oc = exutil.NewCLI("build-sti-labels") diff --git a/test/extended/builds/dockerfile.go b/test/extended/builds/dockerfile.go index bad0998692b3..4b653bdd6c83 100644 --- a/test/extended/builds/dockerfile.go +++ b/test/extended/builds/dockerfile.go @@ -13,6 +13,7 @@ import ( "github.com/openshift/library-go/pkg/image/imageutil" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" ) var _ = g.Describe("[sig-builds][Feature:Builds][Slow] build can have Dockerfile input", func() { @@ -20,10 +21,10 @@ var _ = g.Describe("[sig-builds][Feature:Builds][Slow] build can have Dockerfile var ( oc = exutil.NewCLI("build-dockerfile-env") dockerfileAdd = exutil.FixturePath("testdata", "builds", "docker-add") - testDockerfile = ` -FROM image-registry.openshift-image-registry.svc:5000/openshift/tools:latest + testDockerfile = fmt.Sprintf(` +FROM %s USER 1001 -` +`, image.ShellImage()) testDockerfile2 = ` FROM image-registry.openshift-image-registry.svc:5000/openshift/ruby:2.7 USER 1001 diff --git a/test/extended/builds/hooks.go b/test/extended/builds/hooks.go index 35ee700fcf2f..5143a9a02e0d 100644 --- a/test/extended/builds/hooks.go +++ b/test/extended/builds/hooks.go @@ -2,6 +2,7 @@ package builds import ( "context" + "fmt" "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -10,6 +11,7 @@ import ( o "github.com/onsi/gomega" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" ) var _ = g.Describe("[sig-builds][Feature:Builds][Slow] testing build configuration hooks", func() { @@ -163,7 +165,7 @@ var _ = g.Describe("[sig-builds][Feature:Builds][Slow] testing build configurati o.Expect(err).NotTo(o.HaveOccurred()) err = oc.Run("patch").Args("bc/mydockertest", "-p", `{"spec":{"output":{"to":{"kind":"ImageStreamTag","name":"mydockertest:latest"}}}}`).Execute() o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("patch").Args("bc/mydockertest", "-p", `{"spec":{"source":{"dockerfile":"FROM image-registry.openshift-image-registry.svc:5000/openshift/tools:latest \n ENTRYPOINT /bin/sleep 600 \n"}}}`).Execute() + err = oc.Run("patch").Args("bc/mydockertest", "-p", fmt.Sprintf(`{"spec":{"source":{"dockerfile":"FROM %s \n ENTRYPOINT /bin/sleep 600 \n"}}}`, image.ShellImage())).Execute() o.Expect(err).NotTo(o.HaveOccurred()) g.By("starting a build") diff --git a/test/extended/builds/labels.go b/test/extended/builds/labels.go index ce57a1a6ca24..31d9f8217051 100644 --- a/test/extended/builds/labels.go +++ b/test/extended/builds/labels.go @@ -14,7 +14,7 @@ import ( var _ = g.Describe("[sig-builds][Feature:Builds] result image should have proper labels set", func() { defer g.GinkgoRecover() var ( - imageStreamFixture = exutil.FixturePath("..", "integration", "testdata", "test-image-stream.json") + imageStreamFixture = exutil.FixturePath("testdata", "builds", "test-image-stream.json") stiBuildFixture = exutil.FixturePath("testdata", "builds", "test-s2i-build.json") dockerBuildFixture = exutil.FixturePath("testdata", "builds", "test-docker-build.json") oc = exutil.NewCLI("build-sti-labels") diff --git a/test/extended/builds/multistage.go b/test/extended/builds/multistage.go index 1db0be0fc5a7..20bc663c099d 100644 --- a/test/extended/builds/multistage.go +++ b/test/extended/builds/multistage.go @@ -14,108 +14,106 @@ import ( buildv1 "github.com/openshift/api/build/v1" eximages "github.com/openshift/origin/test/extended/images" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" ) var _ = g.Describe("[sig-builds][Feature:Builds] Multi-stage image builds", func() { defer g.GinkgoRecover() var ( oc = exutil.NewCLI("build-multistage") - testDockerfile = ` + testDockerfile = fmt.Sprintf(` FROM scratch as test USER 1001 -FROM image-registry.openshift-image-registry.svc:5000/openshift/cli:latest as other +FROM %[1]s as other COPY --from=test /usr/bin/curl /test/ -COPY --from=image-registry.openshift-image-registry.svc:5000/openshift/tools:latest /bin/echo /test/ -COPY --from=image-registry.openshift-image-registry.svc:5000/openshift/tools:latest /bin/ping /test/ -` +COPY --from=%[2]s /bin/echo /test/ +COPY --from=%[2]s /bin/ping /test/ +`, image.LimitedShellImage(), image.ShellImage()) ) - g.Context("", func() { - - g.AfterEach(func() { - if g.CurrentGinkgoTestDescription().Failed { - exutil.DumpPodStates(oc) - exutil.DumpConfigMapStates(oc) - exutil.DumpPodLogsStartingWith("", oc) - } - }) + g.AfterEach(func() { + if g.CurrentGinkgoTestDescription().Failed { + exutil.DumpPodStates(oc) + exutil.DumpConfigMapStates(oc) + exutil.DumpPodLogsStartingWith("", oc) + } + }) - g.It("should succeed", func() { - g.By("creating a build directly") - registryURL, err := eximages.GetDockerRegistryURL(oc) - o.Expect(err).NotTo(o.HaveOccurred()) + g.It("should succeed", func() { + g.By("creating a build directly") + registryURL, err := eximages.GetDockerRegistryURL(oc) + o.Expect(err).NotTo(o.HaveOccurred()) - build, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Create(context.Background(), &buildv1.Build{ - ObjectMeta: metav1.ObjectMeta{ - Name: "multi-stage", - }, - Spec: buildv1.BuildSpec{ - CommonSpec: buildv1.CommonSpec{ - Source: buildv1.BuildSource{ - Dockerfile: &testDockerfile, - Images: []buildv1.ImageSource{ - {From: corev1.ObjectReference{Kind: "DockerImage", Name: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest"}, As: []string{"scratch"}}, - }, - }, - Strategy: buildv1.BuildStrategy{ - DockerStrategy: &buildv1.DockerBuildStrategy{}, + build, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Create(context.Background(), &buildv1.Build{ + ObjectMeta: metav1.ObjectMeta{ + Name: "multi-stage", + }, + Spec: buildv1.BuildSpec{ + CommonSpec: buildv1.CommonSpec{ + Source: buildv1.BuildSource{ + Dockerfile: &testDockerfile, + Images: []buildv1.ImageSource{ + {From: corev1.ObjectReference{Kind: "DockerImage", Name: image.ShellImage()}, As: []string{"scratch"}}, }, - Output: buildv1.BuildOutput{ - To: &corev1.ObjectReference{ - Kind: "DockerImage", - Name: fmt.Sprintf("%s/%s/multi-stage:v1", registryURL, oc.Namespace()), - }, + }, + Strategy: buildv1.BuildStrategy{ + DockerStrategy: &buildv1.DockerBuildStrategy{}, + }, + Output: buildv1.BuildOutput{ + To: &corev1.ObjectReference{ + Kind: "DockerImage", + Name: fmt.Sprintf("%s/%s/multi-stage:v1", registryURL, oc.Namespace()), }, }, }, - }, metav1.CreateOptions{}) - o.Expect(err).NotTo(o.HaveOccurred()) - result := exutil.NewBuildResult(oc, build) - err = exutil.WaitForBuildResult(oc.AdminBuildClient().BuildV1().Builds(oc.Namespace()), result) - o.Expect(err).NotTo(o.HaveOccurred()) + }, + }, metav1.CreateOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + result := exutil.NewBuildResult(oc, build) + err = exutil.WaitForBuildResult(oc.AdminBuildClient().BuildV1().Builds(oc.Namespace()), result) + o.Expect(err).NotTo(o.HaveOccurred()) - pod, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Get(context.Background(), build.Name+"-build", metav1.GetOptions{}) - o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(result.BuildSuccess).To(o.BeTrue(), "Build did not succeed: %#v", result) + pod, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Get(context.Background(), build.Name+"-build", metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(result.BuildSuccess).To(o.BeTrue(), "Build did not succeed: %#v", result) - s, err := result.Logs() - o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(s).ToNot(o.ContainSubstring("--> FROM scratch")) - o.Expect(s).To(o.ContainSubstring("FROM image-registry.openshift-image-registry.svc:5000/openshift/cli:latest AS other")) - o.Expect(s).To(o.ContainSubstring("STEP 1: FROM image-registry.openshift-image-registry.svc:5000/openshift/tools:latest AS test")) - o.Expect(s).To(o.ContainSubstring("COPY --from")) - o.Expect(s).To(o.ContainSubstring(fmt.Sprintf("\"OPENSHIFT_BUILD_NAMESPACE\"=\"%s\"", oc.Namespace()))) - e2e.Logf("Build logs:\n%s", result) + s, err := result.Logs() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(s).ToNot(o.ContainSubstring("--> FROM scratch")) + o.Expect(s).ToNot(o.ContainSubstring("FROM busybox")) + o.Expect(s).To(o.ContainSubstring(fmt.Sprintf("STEP 1: FROM %s AS test", image.ShellImage()))) + o.Expect(s).To(o.ContainSubstring("COPY --from")) + o.Expect(s).To(o.ContainSubstring(fmt.Sprintf("\"OPENSHIFT_BUILD_NAMESPACE\"=\"%s\"", oc.Namespace()))) + e2e.Logf("Build logs:\n%s", result) - c := oc.KubeFramework().PodClient() - pod = c.Create(&corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - }, - Spec: corev1.PodSpec{ - RestartPolicy: corev1.RestartPolicyNever, - Containers: []corev1.Container{ - { - Name: "run", - Image: fmt.Sprintf("%s/%s/multi-stage:v1", registryURL, oc.Namespace()), - Command: []string{"/test/curl", "-k", "https://kubernetes.default.svc"}, - }, - { - Name: "check", - Image: fmt.Sprintf("%s/%s/multi-stage:v1", registryURL, oc.Namespace()), - Command: []string{"ls", "/test/"}, - }, + c := oc.KubeFramework().PodClient() + pod = c.Create(&corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + Spec: corev1.PodSpec{ + RestartPolicy: corev1.RestartPolicyNever, + Containers: []corev1.Container{ + { + Name: "run", + Image: fmt.Sprintf("%s/%s/multi-stage:v1", registryURL, oc.Namespace()), + Command: []string{"/test/curl", "-k", "https://kubernetes.default.svc"}, + }, + { + Name: "check", + Image: fmt.Sprintf("%s/%s/multi-stage:v1", registryURL, oc.Namespace()), + Command: []string{"ls", "/test/"}, }, }, - }) - c.WaitForSuccess(pod.Name, e2e.PodStartTimeout) - data, err := oc.Run("logs").Args("-f", "test", "-c", "run").Output() - o.Expect(err).NotTo(o.HaveOccurred()) - m, err := oc.Run("logs").Args("-f", "test", "-c", "check").Output() - o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(m).To(o.ContainSubstring("echo")) - o.Expect(m).To(o.ContainSubstring("ping")) - e2e.Logf("Pod logs:\n%s\n%s", string(data), string(m)) + }, }) + c.WaitForSuccess(pod.Name, e2e.PodStartTimeout) + data, err := oc.Run("logs").Args("-f", "test", "-c", "run").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + m, err := oc.Run("logs").Args("-f", "test", "-c", "check").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(m).To(o.ContainSubstring("echo")) + o.Expect(m).To(o.ContainSubstring("ping")) + e2e.Logf("Pod logs:\n%s\n%s", string(data), string(m)) }) }) diff --git a/test/extended/builds/optimized.go b/test/extended/builds/optimized.go index 3193889a61cc..80b65f8a516d 100644 --- a/test/extended/builds/optimized.go +++ b/test/extended/builds/optimized.go @@ -13,6 +13,7 @@ import ( buildv1 "github.com/openshift/api/build/v1" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" ) var _ = g.Describe("[sig-builds][Feature:Builds] Optimized image builds", func() { @@ -20,11 +21,11 @@ var _ = g.Describe("[sig-builds][Feature:Builds] Optimized image builds", func() var ( oc = exutil.NewCLI("build-dockerfile-env") skipLayers = buildv1.ImageOptimizationSkipLayers - testDockerfile = ` -FROM image-registry.openshift-image-registry.svc:5000/openshift/tools:latest + testDockerfile = fmt.Sprintf(` +FROM %s RUN yum list installed USER 1001 -` +`, image.ShellImage()) ) g.Context("", func() { diff --git a/test/extended/builds/pipeline_jenkins_e2e.go b/test/extended/builds/pipeline_jenkins_e2e.go index b264ef604a30..e5c35db62c16 100644 --- a/test/extended/builds/pipeline_jenkins_e2e.go +++ b/test/extended/builds/pipeline_jenkins_e2e.go @@ -194,466 +194,469 @@ var _ = g.Describe("[sig-devex][Feature:Jenkins][Slow] Jenkins repos e2e openshi // these tests are isolated so that PR testing the jenkins-client-plugin can execute the extended // tests with a ginkgo focus that runs only the tests within this ginkgo context - g.Context("Sync plugin tests", func() { - - g.It("using the persistent template", func() { - defer cleanup(jenkinsPersistentTemplatePath) - setupJenkins(jenkinsPersistentTemplatePath) - // additionally ensure that the build works in a memory constrained - // environment - _, err := oc.AdminKubeClient().CoreV1().LimitRanges(oc.Namespace()).Create(context.Background(), &corev1.LimitRange{ - ObjectMeta: metav1.ObjectMeta{ - Name: "limitrange", - }, - Spec: corev1.LimitRangeSpec{ - Limits: []corev1.LimitRangeItem{ - { - Type: corev1.LimitTypeContainer, - Default: corev1.ResourceList{ - corev1.ResourceMemory: resource.MustParse("512Mi"), + g.Context("", func() { + + g.Describe("Sync plugin tests", func() { + g.It("using the persistent template", func() { + defer cleanup(jenkinsPersistentTemplatePath) + setupJenkins(jenkinsPersistentTemplatePath) + // additionally ensure that the build works in a memory constrained + // environment + _, err := oc.AdminKubeClient().CoreV1().LimitRanges(oc.Namespace()).Create(context.Background(), &corev1.LimitRange{ + ObjectMeta: metav1.ObjectMeta{ + Name: "limitrange", + }, + Spec: corev1.LimitRangeSpec{ + Limits: []corev1.LimitRangeItem{ + { + Type: corev1.LimitTypeContainer, + Default: corev1.ResourceList{ + corev1.ResourceMemory: resource.MustParse("512Mi"), + }, }, }, }, - }, - }, metav1.CreateOptions{}) - o.Expect(err).NotTo(o.HaveOccurred()) - defer oc.AdminKubeClient().CoreV1().LimitRanges(oc.Namespace()).Delete(context.Background(), "limitrange", metav1.DeleteOptions{}) - - g.By("delete jenkins job runs when jenkins re-establishes communications") - g.By("should delete job runs when the associated build is deleted - jenkins unreachable") - type buildInfo struct { - number int - jenkinsBuildURI string - } - buildNameToBuildInfoMap := make(map[string]buildInfo) - - g.By(fmt.Sprintf("calling oc new-app -f %q", envVarsPipelinePath)) - err = oc.Run("new-app").Args("-f", envVarsPipelinePath).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - - g.By("starting 5 pipeline builds") - for i := 1; i <= 5; i++ { - // start the build - br, _ := exutil.StartBuildAndWait(oc, "sample-pipeline-withenvs") - br.AssertSuccess() - - // get the build information - build, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), fmt.Sprintf("sample-pipeline-withenvs-%d", i), metav1.GetOptions{}) + }, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) + defer oc.AdminKubeClient().CoreV1().LimitRanges(oc.Namespace()).Delete(context.Background(), "limitrange", metav1.DeleteOptions{}) - jenkinsBuildURI, err := url.Parse(build.Annotations[buildv1.BuildJenkinsBuildURIAnnotation]) - - if err != nil { - fmt.Fprintf(g.GinkgoWriter, "error parsing build uri: %s", err) + g.By("delete jenkins job runs when jenkins re-establishes communications") + g.By("should delete job runs when the associated build is deleted - jenkins unreachable") + type buildInfo struct { + number int + jenkinsBuildURI string } - buildNameToBuildInfoMap[build.Name] = buildInfo{number: i, jenkinsBuildURI: jenkinsBuildURI.Path} - } + buildNameToBuildInfoMap := make(map[string]buildInfo) - g.By("verifying that jobs exist for the 5 builds") - for buildName, buildInfo := range buildNameToBuildInfoMap { - _, status, err := j.GetResource(buildInfo.jenkinsBuildURI) - o.Expect(err).NotTo(o.HaveOccurred()) - _, err = oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), buildName, metav1.GetOptions{}) + g.By(fmt.Sprintf("calling oc new-app -f %q", envVarsPipelinePath)) + err = oc.Run("new-app").Args("-f", envVarsPipelinePath).Execute() o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(status == http.StatusOK).To(o.BeTrue(), "Jenkins job run does not exist for %s but should.", buildName) - } - g.By("scaling down jenkins") - _, err = oc.Run("scale").Args("dc/jenkins", "--replicas=0").Output() + g.By("starting 5 pipeline builds") + for i := 1; i <= 5; i++ { + // start the build + br, _ := exutil.StartBuildAndWait(oc, "sample-pipeline-withenvs") + br.AssertSuccess() - o.Expect(err).NotTo(o.HaveOccurred()) - g.By("deleting the even numbered builds") - for buildName, buildInfo := range buildNameToBuildInfoMap { - if buildInfo.number%2 == 0 { - fmt.Fprintf(g.GinkgoWriter, "Deleting build: %s", buildName) - err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Delete(context.Background(), buildName, metav1.DeleteOptions{}) + // get the build information + build, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), fmt.Sprintf("sample-pipeline-withenvs-%d", i), metav1.GetOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - } - } - - g.By("scaling up jenkins") - _, err = oc.Run("scale").Args("dc/jenkins", "--replicas=1").Output() + jenkinsBuildURI, err := url.Parse(build.Annotations[buildv1.BuildJenkinsBuildURIAnnotation]) - g.By("wait for jenkins to come up") - _, err = j.WaitForContent("", 200, 10*time.Minute, "") - if err != nil { - exutil.DumpApplicationPodLogs("jenkins", oc) - } + if err != nil { + fmt.Fprintf(g.GinkgoWriter, "error parsing build uri: %s", err) + } + buildNameToBuildInfoMap[build.Name] = buildInfo{number: i, jenkinsBuildURI: jenkinsBuildURI.Path} + } - g.By("giving the Jenkins sync plugin enough time to delete the job runs") - err = wait.PollImmediate(5*time.Second, 10*time.Minute, func() (bool, error) { + g.By("verifying that jobs exist for the 5 builds") for buildName, buildInfo := range buildNameToBuildInfoMap { _, status, err := j.GetResource(buildInfo.jenkinsBuildURI) o.Expect(err).NotTo(o.HaveOccurred()) - fmt.Fprintf(g.GinkgoWriter, "Checking %s, status: %v\n", buildName, status) - if buildInfo.number%2 == 0 { - if status == http.StatusOK { - fmt.Fprintf(g.GinkgoWriter, "Jenkins job run exists for %s but shouldn't, retrying ...", buildName) - return false, nil - } - } - } - return true, nil - }) - o.Expect(err).NotTo(o.HaveOccurred()) - - g.By("verifying that the correct builds and jobs exist") - for buildName, buildInfo := range buildNameToBuildInfoMap { - _, status, err := j.GetResource(buildInfo.jenkinsBuildURI) - o.Expect(err).NotTo(o.HaveOccurred()) - fmt.Fprintf(g.GinkgoWriter, "Checking %s, status: %v\n", buildName, status) - if buildInfo.number%2 == 0 { - _, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), buildName, metav1.GetOptions{}) - o.Expect(err).To(o.HaveOccurred()) - o.Expect(status != http.StatusOK).To(o.BeTrue(), "Jenkins job run exists for %s but shouldn't.", buildName) - } else { - _, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), buildName, metav1.GetOptions{}) + _, err = oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), buildName, metav1.GetOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(status == http.StatusOK).To(o.BeTrue(), "Jenkins job run does not exist for %s but should.", buildName) } - } - g.By("clean up openshift resources for next potential run") - err = oc.Run("delete").Args("bc", "sample-pipeline-withenvs").Execute() - }) - - g.It("using the ephemeral template", func() { - defer cleanup(jenkinsEphemeralTemplatePath) - setupJenkins(jenkinsEphemeralTemplatePath) - - g.By("Pipelines with maven slave") + g.By("scaling down jenkins") + _, err = oc.Run("scale").Args("dc/jenkins", "--replicas=0").Output() - g.By("should build a maven project and complete successfully", func() { - - // instantiate the template - g.By(fmt.Sprintf("calling oc new-app -f %q", mavenSlavePipelinePath)) - err := oc.Run("new-app").Args("-f", mavenSlavePipelinePath).Execute() o.Expect(err).NotTo(o.HaveOccurred()) + g.By("deleting the even numbered builds") + for buildName, buildInfo := range buildNameToBuildInfoMap { + if buildInfo.number%2 == 0 { + fmt.Fprintf(g.GinkgoWriter, "Deleting build: %s", buildName) + err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Delete(context.Background(), buildName, metav1.DeleteOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) - // start the build - g.By("starting the pipeline build and waiting for it to complete") - br, err := exutil.StartBuildAndWait(oc, "openshift-jee-sample") - if err != nil || !br.BuildSuccess { - exutil.DumpBuilds(oc) - exutil.DumpPodLogsStartingWith("maven", oc) - exutil.DumpBuildLogs("openshift-jee-sample-docker", oc) - exutil.DumpDeploymentLogs("openshift-jee-sample", 1, oc) + } } - debugAnyJenkinsFailure(br, oc.Namespace()+"-openshift-jee-sample", oc, true) - br.AssertSuccess() - - // wait for the service to be running - g.By("expecting the openshift-jee-sample service to be deployed and running") - _, err = exutil.GetEndpointAddress(oc, "openshift-jee-sample") - o.Expect(err).NotTo(o.HaveOccurred()) - g.By("clean up openshift resources for next potential run") - err = oc.Run("delete").Args("bc", "openshift-jee-sample").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("bc", "openshift-jee-sample-docker").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("dc", "openshift-jee-sample").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("is", "openshift-jee-sample").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("svc", "openshift-jee-sample").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("route", "openshift-jee-sample").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("is", "wildfly").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - }) + g.By("scaling up jenkins") + _, err = oc.Run("scale").Args("dc/jenkins", "--replicas=1").Output() - g.By("Pipelines with declarative syntax") + g.By("wait for jenkins to come up") + _, err = j.WaitForContent("", 200, 10*time.Minute, "") + if err != nil { + exutil.DumpApplicationPodLogs("jenkins", oc) + } - g.By("should build successfully", func() { - // create the bc - g.By(fmt.Sprintf("calling oc create -f %q", nodejsDeclarativePipelinePath)) - err := oc.Run("create").Args("-f", nodejsDeclarativePipelinePath).Execute() + g.By("giving the Jenkins sync plugin enough time to delete the job runs") + err = wait.PollImmediate(5*time.Second, 10*time.Minute, func() (bool, error) { + for buildName, buildInfo := range buildNameToBuildInfoMap { + _, status, err := j.GetResource(buildInfo.jenkinsBuildURI) + o.Expect(err).NotTo(o.HaveOccurred()) + fmt.Fprintf(g.GinkgoWriter, "Checking %s, status: %v\n", buildName, status) + if buildInfo.number%2 == 0 { + if status == http.StatusOK { + fmt.Fprintf(g.GinkgoWriter, "Jenkins job run exists for %s but shouldn't, retrying ...", buildName) + return false, nil + } + } + } + return true, nil + }) o.Expect(err).NotTo(o.HaveOccurred()) - // start the build - g.By("starting the pipeline build and waiting for it to complete") - br, err := exutil.StartBuildAndWait(oc, "nodejs-sample-pipeline") - if err != nil || !br.BuildSuccess { - exutil.DumpBuilds(oc) - exutil.DumpPodLogsStartingWith("nodejs", oc) - exutil.DumpBuildLogs("nodejs-mongodb-example", oc) - exutil.DumpDeploymentLogs("mongodb", 1, oc) - exutil.DumpDeploymentLogs("nodejs-mongodb-example", 1, oc) + g.By("verifying that the correct builds and jobs exist") + for buildName, buildInfo := range buildNameToBuildInfoMap { + _, status, err := j.GetResource(buildInfo.jenkinsBuildURI) + o.Expect(err).NotTo(o.HaveOccurred()) + fmt.Fprintf(g.GinkgoWriter, "Checking %s, status: %v\n", buildName, status) + if buildInfo.number%2 == 0 { + _, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), buildName, metav1.GetOptions{}) + o.Expect(err).To(o.HaveOccurred()) + o.Expect(status != http.StatusOK).To(o.BeTrue(), "Jenkins job run exists for %s but shouldn't.", buildName) + } else { + _, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), buildName, metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(status == http.StatusOK).To(o.BeTrue(), "Jenkins job run does not exist for %s but should.", buildName) + } } - debugAnyJenkinsFailure(br, oc.Namespace()+"-nodejs-sample-pipeline", oc, true) - br.AssertSuccess() - - // wait for the service to be running - g.By("expecting the nodejs-mongodb-example service to be deployed and running") - _, err = exutil.GetEndpointAddress(oc, "nodejs-mongodb-example") - o.Expect(err).NotTo(o.HaveOccurred()) g.By("clean up openshift resources for next potential run") - err = oc.Run("delete").Args("all", "-l", "app=nodejs-mongodb-example").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("secret", "nodejs-mongodb-example").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("bc", "nodejs-sample-pipeline").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("is", "nodejs-mongodb-example-staging").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("bc", "sample-pipeline-withenvs").Execute() }) - g.By("Pipeline with env vars and git repo source") + g.It("using the ephemeral template", func() { + defer cleanup(jenkinsEphemeralTemplatePath) + setupJenkins(jenkinsEphemeralTemplatePath) - g.By("should propagate env vars to bc", func() { - g.By(fmt.Sprintf("creating git repo %v", envVarsPipelineGitRepoBuildConfig)) - repo, err := exutil.NewGitRepo(envVarsPipelineGitRepoBuildConfig) - defer repo.Remove() - if err != nil { - files, dbgerr := ioutil.ReadDir("/tmp") - if dbgerr != nil { - e2e.Logf("problem diagnosing /tmp: %v", dbgerr) - } else { - for _, file := range files { - e2e.Logf("found file %s under temp isdir %q mode %s", file.Name(), file.IsDir(), file.Mode().String()) - } + g.By("Pipelines with maven slave") + + g.By("should build a maven project and complete successfully", func() { + + // instantiate the template + g.By(fmt.Sprintf("calling oc new-app -f %q", mavenSlavePipelinePath)) + err := oc.Run("new-app").Args("-f", mavenSlavePipelinePath).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + // start the build + g.By("starting the pipeline build and waiting for it to complete") + br, err := exutil.StartBuildAndWait(oc, "openshift-jee-sample") + if err != nil || !br.BuildSuccess { + exutil.DumpBuilds(oc) + exutil.DumpPodLogsStartingWith("maven", oc) + exutil.DumpBuildLogs("openshift-jee-sample-docker", oc) + exutil.DumpDeploymentLogs("openshift-jee-sample", 1, oc) } - } - o.Expect(err).NotTo(o.HaveOccurred()) - jf := `node() {\necho "FOO1 is ${env.FOO1}"\necho"FOO2is${env.FOO2}"\necho"FOO3is${env.FOO3}"\necho"FOO4is${env.FOO4}"}` - err = repo.AddAndCommit("Jenkinsfile", jf) - o.Expect(err).NotTo(o.HaveOccurred()) + debugAnyJenkinsFailure(br, oc.Namespace()+"-openshift-jee-sample", oc, true) + br.AssertSuccess() - // instantiate the bc - g.By(fmt.Sprintf("calling oc new-app %q --strategy=pipeline --build-env=FOO1=BAR1", repo.RepoPath)) - err = oc.Run("new-app").Args(repo.RepoPath, "--strategy=pipeline", "--build-env=FOO1=BAR1").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + // wait for the service to be running + g.By("expecting the openshift-jee-sample service to be deployed and running") + _, err = exutil.GetEndpointAddress(oc, "openshift-jee-sample") + o.Expect(err).NotTo(o.HaveOccurred()) - bc, err := oc.BuildClient().BuildV1().BuildConfigs(oc.Namespace()).Get(context.Background(), envVarsPipelineGitRepoBuildConfig, metav1.GetOptions{}) - o.Expect(err).NotTo(o.HaveOccurred()) - envs := bc.Spec.Strategy.JenkinsPipelineStrategy.Env - o.Expect(len(envs)).To(o.Equal(1)) - o.Expect(envs[0].Name).To(o.Equal("FOO1")) - o.Expect(envs[0].Value).To(o.Equal("BAR1")) - }) + g.By("clean up openshift resources for next potential run") + err = oc.Run("delete").Args("bc", "openshift-jee-sample").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("bc", "openshift-jee-sample-docker").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("dc", "openshift-jee-sample").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("is", "openshift-jee-sample").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("svc", "openshift-jee-sample").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("route", "openshift-jee-sample").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("is", "wildfly").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + }) - g.By("Blue-green pipeline") + g.By("Pipelines with declarative syntax") - g.By("Blue-green pipeline should build and complete successfully", func() { - // instantiate the template - g.By(fmt.Sprintf("calling oc new-app -f %q", blueGreenPipelinePath)) - err := oc.Run("new-app").Args("-f", blueGreenPipelinePath, "-p", "VERBOSE=true").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("should build successfully", func() { + // create the bc + g.By(fmt.Sprintf("calling oc create -f %q", nodejsDeclarativePipelinePath)) + err := oc.Run("create").Args("-f", nodejsDeclarativePipelinePath).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - buildAndSwitch := func(newColour string) { // start the build - g.By("starting the bluegreen pipeline build") - br, err := exutil.StartBuildResult(oc, "bluegreen-pipeline") + g.By("starting the pipeline build and waiting for it to complete") + br, err := exutil.StartBuildAndWait(oc, "nodejs-sample-pipeline") if err != nil || !br.BuildSuccess { - debugAnyJenkinsFailure(br, oc.Namespace()+"-bluegreen-pipeline", oc, false) exutil.DumpBuilds(oc) + exutil.DumpPodLogsStartingWith("nodejs", oc) + exutil.DumpBuildLogs("nodejs-mongodb-example", oc) + exutil.DumpDeploymentLogs("mongodb", 1, oc) + exutil.DumpDeploymentLogs("nodejs-mongodb-example", 1, oc) } + debugAnyJenkinsFailure(br, oc.Namespace()+"-nodejs-sample-pipeline", oc, true) + br.AssertSuccess() + + // wait for the service to be running + g.By("expecting the nodejs-mongodb-example service to be deployed and running") + _, err = exutil.GetEndpointAddress(oc, "nodejs-mongodb-example") o.Expect(err).NotTo(o.HaveOccurred()) - errs := make(chan error, 2) - stop := make(chan struct{}) - go func() { - defer g.GinkgoRecover() + g.By("clean up openshift resources for next potential run") + err = oc.Run("delete").Args("all", "-l", "app=nodejs-mongodb-example").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("secret", "nodejs-mongodb-example").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("bc", "nodejs-sample-pipeline").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("is", "nodejs-mongodb-example-staging").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + }) - g.By("Waiting for the build uri") - var jenkinsBuildURI string - for { - build, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), br.BuildName, metav1.GetOptions{}) - if err != nil { - errs <- fmt.Errorf("error getting build: %s", err) - return - } - jenkinsBuildURI = build.Annotations[buildv1.BuildJenkinsBuildURIAnnotation] - if jenkinsBuildURI != "" { - break - } + g.By("Pipeline with env vars and git repo source") - select { - case <-stop: - return - default: - time.Sleep(10 * time.Second) + g.By("should propagate env vars to bc", func() { + g.By(fmt.Sprintf("creating git repo %v", envVarsPipelineGitRepoBuildConfig)) + repo, err := exutil.NewGitRepo(envVarsPipelineGitRepoBuildConfig) + defer repo.Remove() + if err != nil { + files, dbgerr := ioutil.ReadDir("/tmp") + if dbgerr != nil { + e2e.Logf("problem diagnosing /tmp: %v", dbgerr) + } else { + for _, file := range files { + e2e.Logf("found file %s under temp isdir %q mode %s", file.Name(), file.IsDir(), file.Mode().String()) } } + } + o.Expect(err).NotTo(o.HaveOccurred()) + jf := `node() {\necho "FOO1 is ${env.FOO1}"\necho"FOO2is${env.FOO2}"\necho"FOO3is${env.FOO3}"\necho"FOO4is${env.FOO4}"}` + err = repo.AddAndCommit("Jenkinsfile", jf) + o.Expect(err).NotTo(o.HaveOccurred()) - url, err := url.Parse(jenkinsBuildURI) - if err != nil { - errs <- fmt.Errorf("error parsing build uri: %s", err) - return + // instantiate the bc + g.By(fmt.Sprintf("calling oc new-app %q --strategy=pipeline --build-env=FOO1=BAR1", repo.RepoPath)) + err = oc.Run("new-app").Args(repo.RepoPath, "--strategy=pipeline", "--build-env=FOO1=BAR1").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + bc, err := oc.BuildClient().BuildV1().BuildConfigs(oc.Namespace()).Get(context.Background(), envVarsPipelineGitRepoBuildConfig, metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + envs := bc.Spec.Strategy.JenkinsPipelineStrategy.Env + o.Expect(len(envs)).To(o.Equal(1)) + o.Expect(envs[0].Name).To(o.Equal("FOO1")) + o.Expect(envs[0].Value).To(o.Equal("BAR1")) + }) + + g.By("Blue-green pipeline") + + g.By("Blue-green pipeline should build and complete successfully", func() { + // instantiate the template + g.By(fmt.Sprintf("calling oc new-app -f %q", blueGreenPipelinePath)) + err := oc.Run("new-app").Args("-f", blueGreenPipelinePath, "-p", "VERBOSE=true").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + buildAndSwitch := func(newColour string) { + // start the build + g.By("starting the bluegreen pipeline build") + br, err := exutil.StartBuildResult(oc, "bluegreen-pipeline") + if err != nil || !br.BuildSuccess { + debugAnyJenkinsFailure(br, oc.Namespace()+"-bluegreen-pipeline", oc, false) + exutil.DumpBuilds(oc) } - jenkinsBuildURI = strings.Trim(url.Path, "/") // trim leading https://host/ and trailing / + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("Waiting for the approval prompt") - for { - body, status, err := j.GetResource(jenkinsBuildURI + "/consoleText") - if err == nil && status == http.StatusOK && strings.Contains(body, "Approve?") { - break + errs := make(chan error, 2) + stop := make(chan struct{}) + go func() { + defer g.GinkgoRecover() + + g.By("Waiting for the build uri") + var jenkinsBuildURI string + for { + build, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), br.BuildName, metav1.GetOptions{}) + if err != nil { + errs <- fmt.Errorf("error getting build: %s", err) + return + } + jenkinsBuildURI = build.Annotations[buildv1.BuildJenkinsBuildURIAnnotation] + if jenkinsBuildURI != "" { + break + } + + select { + case <-stop: + return + default: + time.Sleep(10 * time.Second) + } } - select { - case <-stop: + + url, err := url.Parse(jenkinsBuildURI) + if err != nil { + errs <- fmt.Errorf("error parsing build uri: %s", err) return - default: - time.Sleep(10 * time.Second) } + jenkinsBuildURI = strings.Trim(url.Path, "/") // trim leading https://host/ and trailing / + + g.By("Waiting for the approval prompt") + for { + body, status, err := j.GetResource(jenkinsBuildURI + "/consoleText") + if err == nil && status == http.StatusOK && strings.Contains(body, "Approve?") { + break + } + select { + case <-stop: + return + default: + time.Sleep(10 * time.Second) + } + } + + g.By("Approving the current build") + _, _, err = j.Post("", jenkinsBuildURI+"/input/Approval/proceedEmpty", "") + if err != nil { + errs <- fmt.Errorf("error approving the current build: %s", err) + } + }() + + go func() { + defer g.GinkgoRecover() + + for { + build, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), br.BuildName, metav1.GetOptions{}) + switch { + case err != nil: + errs <- fmt.Errorf("error getting build: %s", err) + return + case exutil.CheckBuildFailed(build): + errs <- nil + return + case exutil.CheckBuildSuccess(build): + br.BuildSuccess = true + errs <- nil + return + } + select { + case <-stop: + return + default: + time.Sleep(5 * time.Second) + } + } + }() + + g.By("waiting for the build to complete") + select { + case <-time.After(60 * time.Minute): + err = errors.New("timeout waiting for build to complete") + case err = <-errs: } + close(stop) - g.By("Approving the current build") - _, _, err = j.Post("", jenkinsBuildURI+"/input/Approval/proceedEmpty", "") if err != nil { - errs <- fmt.Errorf("error approving the current build: %s", err) + fmt.Fprintf(g.GinkgoWriter, "error occurred (%s): getting logs before failing\n", err) } - }() - - go func() { - defer g.GinkgoRecover() - for { - build, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), br.BuildName, metav1.GetOptions{}) - switch { - case err != nil: - errs <- fmt.Errorf("error getting build: %s", err) - return - case exutil.CheckBuildFailed(build): - errs <- nil - return - case exutil.CheckBuildSuccess(build): - br.BuildSuccess = true - errs <- nil - return - } - select { - case <-stop: - return - default: - time.Sleep(5 * time.Second) - } + debugAnyJenkinsFailure(br, oc.Namespace()+"-bluegreen-pipeline", oc, true) + if err != nil || !br.BuildSuccess { + debugAnyJenkinsFailure(br, oc.Namespace()+"-bluegreen-pipeline", oc, false) + exutil.DumpBuilds(oc) } - }() + br.AssertSuccess() + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("waiting for the build to complete") - select { - case <-time.After(60 * time.Minute): - err = errors.New("timeout waiting for build to complete") - case err = <-errs: + g.By(fmt.Sprintf("verifying that the main route has been switched to %s", newColour)) + value, err := oc.Run("get").Args("route", "nodejs-mongodb-example", "-o", "jsonpath={ .spec.to.name }").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + activeRoute := strings.TrimSpace(value) + g.By(fmt.Sprintf("verifying that the active route is 'nodejs-mongodb-example-%s'", newColour)) + o.Expect(activeRoute).To(o.Equal(fmt.Sprintf("nodejs-mongodb-example-%s", newColour))) } - close(stop) - if err != nil { - fmt.Fprintf(g.GinkgoWriter, "error occurred (%s): getting logs before failing\n", err) - } + buildAndSwitch("green") + buildAndSwitch("blue") - debugAnyJenkinsFailure(br, oc.Namespace()+"-bluegreen-pipeline", oc, true) - if err != nil || !br.BuildSuccess { - debugAnyJenkinsFailure(br, oc.Namespace()+"-bluegreen-pipeline", oc, false) - exutil.DumpBuilds(oc) - } - br.AssertSuccess() + g.By("clean up openshift resources for next potential run") + err = oc.Run("delete").Args("all", "-l", "app=bluegreen-pipeline").Execute() o.Expect(err).NotTo(o.HaveOccurred()) + }) - g.By(fmt.Sprintf("verifying that the main route has been switched to %s", newColour)) - value, err := oc.Run("get").Args("route", "nodejs-mongodb-example", "-o", "jsonpath={ .spec.to.name }").Output() - o.Expect(err).NotTo(o.HaveOccurred()) - activeRoute := strings.TrimSpace(value) - g.By(fmt.Sprintf("verifying that the active route is 'nodejs-mongodb-example-%s'", newColour)) - o.Expect(activeRoute).To(o.Equal(fmt.Sprintf("nodejs-mongodb-example-%s", newColour))) - } + g.By("delete jenkins job runs when the associated build is deleted") - buildAndSwitch("green") - buildAndSwitch("blue") + g.By("should delete a job run when the associated build is deleted", func() { + type buildInfo struct { + number int + jenkinsBuildURI string + } + buildNameToBuildInfoMap := make(map[string]buildInfo) - g.By("clean up openshift resources for next potential run") - err = oc.Run("delete").Args("all", "-l", "app=bluegreen-pipeline").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - }) + g.By(fmt.Sprintf("calling oc create -f %q", envVarsPipelinePath)) + err := oc.Run("new-app").Args("-f", envVarsPipelinePath).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("delete jenkins job runs when the associated build is deleted") + g.By("starting 5 pipeline builds") + for i := 1; i <= 5; i++ { + // start the build + br, _ := exutil.StartBuildAndWait(oc, "sample-pipeline-withenvs") + br.AssertSuccess() - g.By("should delete a job run when the associated build is deleted", func() { - type buildInfo struct { - number int - jenkinsBuildURI string - } - buildNameToBuildInfoMap := make(map[string]buildInfo) + // get the build information + build, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), fmt.Sprintf("sample-pipeline-withenvs-%d", i), metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) - g.By(fmt.Sprintf("calling oc create -f %q", envVarsPipelinePath)) - err := oc.Run("new-app").Args("-f", envVarsPipelinePath).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + jenkinsBuildURI, err := url.Parse(build.Annotations[buildv1.BuildJenkinsBuildURIAnnotation]) + if err != nil { + fmt.Fprintf(g.GinkgoWriter, "error parsing build uri: %s", err) + } + buildNameToBuildInfoMap[build.Name] = buildInfo{number: i, jenkinsBuildURI: jenkinsBuildURI.Path} + } - g.By("starting 5 pipeline builds") - for i := 1; i <= 5; i++ { - // start the build - br, _ := exutil.StartBuildAndWait(oc, "sample-pipeline-withenvs") - br.AssertSuccess() + g.By("verifying that jobs exist for the 5 builds") + for buildName, buildInfo := range buildNameToBuildInfoMap { + _, status, err := j.GetResource(buildInfo.jenkinsBuildURI) + o.Expect(err).NotTo(o.HaveOccurred()) + _, err = oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), buildName, metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(status == http.StatusOK).To(o.BeTrue(), "Jenkins job run does not exist for %s but should.", buildName) + } - // get the build information - build, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), fmt.Sprintf("sample-pipeline-withenvs-%d", i), metav1.GetOptions{}) - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("deleting the even numbered builds") + for buildName, buildInfo := range buildNameToBuildInfoMap { + if buildInfo.number%2 == 0 { + fmt.Fprintf(g.GinkgoWriter, "Deleting build: %s", buildName) + err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Delete(context.Background(), buildName, metav1.DeleteOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) - jenkinsBuildURI, err := url.Parse(build.Annotations[buildv1.BuildJenkinsBuildURIAnnotation]) - if err != nil { - fmt.Fprintf(g.GinkgoWriter, "error parsing build uri: %s", err) + } } - buildNameToBuildInfoMap[build.Name] = buildInfo{number: i, jenkinsBuildURI: jenkinsBuildURI.Path} - } - g.By("verifying that jobs exist for the 5 builds") - for buildName, buildInfo := range buildNameToBuildInfoMap { - _, status, err := j.GetResource(buildInfo.jenkinsBuildURI) - o.Expect(err).NotTo(o.HaveOccurred()) - _, err = oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), buildName, metav1.GetOptions{}) + g.By("giving the Jenkins sync plugin enough time to delete the job runs") + err = wait.PollImmediate(5*time.Second, 10*time.Minute, func() (bool, error) { + for buildName, buildInfo := range buildNameToBuildInfoMap { + _, status, err := j.GetResource(buildInfo.jenkinsBuildURI) + o.Expect(err).NotTo(o.HaveOccurred()) + fmt.Fprintf(g.GinkgoWriter, "Checking %s, status: %v\n", buildName, status) + if buildInfo.number%2 == 0 { + if status == http.StatusOK { + fmt.Fprintf(g.GinkgoWriter, "Jenkins job run exists for %s but shouldn't, retrying ...", buildName) + return false, nil + } + } + } + return true, nil + }) o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(status == http.StatusOK).To(o.BeTrue(), "Jenkins job run does not exist for %s but should.", buildName) - } - g.By("deleting the even numbered builds") - for buildName, buildInfo := range buildNameToBuildInfoMap { - if buildInfo.number%2 == 0 { - fmt.Fprintf(g.GinkgoWriter, "Deleting build: %s", buildName) - err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Delete(context.Background(), buildName, metav1.DeleteOptions{}) - o.Expect(err).NotTo(o.HaveOccurred()) - - } - } - - g.By("giving the Jenkins sync plugin enough time to delete the job runs") - err = wait.PollImmediate(5*time.Second, 10*time.Minute, func() (bool, error) { + g.By("verifying that the correct builds and jobs exist") for buildName, buildInfo := range buildNameToBuildInfoMap { _, status, err := j.GetResource(buildInfo.jenkinsBuildURI) o.Expect(err).NotTo(o.HaveOccurred()) - fmt.Fprintf(g.GinkgoWriter, "Checking %s, status: %v\n", buildName, status) if buildInfo.number%2 == 0 { - if status == http.StatusOK { - fmt.Fprintf(g.GinkgoWriter, "Jenkins job run exists for %s but shouldn't, retrying ...", buildName) - return false, nil - } + _, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), buildName, metav1.GetOptions{}) + o.Expect(err).To(o.HaveOccurred()) + o.Expect(status != http.StatusOK).To(o.BeTrue(), "Jenkins job run exists for %s but shouldn't.", buildName) + } else { + _, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), buildName, metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(status == http.StatusOK).To(o.BeTrue(), "Jenkins job run does not exist for %s but should.", buildName) } } - return true, nil - }) - o.Expect(err).NotTo(o.HaveOccurred()) - g.By("verifying that the correct builds and jobs exist") - for buildName, buildInfo := range buildNameToBuildInfoMap { - _, status, err := j.GetResource(buildInfo.jenkinsBuildURI) + g.By("clean up openshift resources for next potential run") + err = oc.Run("delete").Args("bc", "sample-pipeline-withenvs").Execute() o.Expect(err).NotTo(o.HaveOccurred()) - if buildInfo.number%2 == 0 { - _, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), buildName, metav1.GetOptions{}) - o.Expect(err).To(o.HaveOccurred()) - o.Expect(status != http.StatusOK).To(o.BeTrue(), "Jenkins job run exists for %s but shouldn't.", buildName) - } else { - _, err := oc.BuildClient().BuildV1().Builds(oc.Namespace()).Get(context.Background(), buildName, metav1.GetOptions{}) - o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(status == http.StatusOK).To(o.BeTrue(), "Jenkins job run does not exist for %s but should.", buildName) - } - } + }) - g.By("clean up openshift resources for next potential run") - err = oc.Run("delete").Args("bc", "sample-pipeline-withenvs").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) }) }) diff --git a/test/extended/builds/pipeline_origin_bld.go b/test/extended/builds/pipeline_origin_bld.go index 3e4aa77bec47..0b0a01079847 100644 --- a/test/extended/builds/pipeline_origin_bld.go +++ b/test/extended/builds/pipeline_origin_bld.go @@ -213,488 +213,490 @@ var _ = g.Describe("[sig-builds][Feature:Builds][sig-devex][Feature:Jenkins][Slo } ) - g.Context("jenkins-client-plugin tests", func() { + g.Context("", func() { - g.It("using the ephemeral template", func() { - defer cleanup(jenkinsEphemeralTemplatePath) - setupJenkins(jenkinsEphemeralTemplatePath) + g.Describe("jenkins-client-plugin tests", func() { + g.It("using the ephemeral template", func() { + defer cleanup(jenkinsEphemeralTemplatePath) + setupJenkins(jenkinsEphemeralTemplatePath) - g.By("Pipeline using jenkins-client-plugin") + g.By("Pipeline using jenkins-client-plugin") - g.By("should verify services successfully", func() { - redisTemplate := "redis-ephemeral" - redisAppName := "redis" - verifyServiceBuildConfig := "jenkins-verifyservice-pipeline" + g.By("should verify services successfully", func() { + redisTemplate := "redis-ephemeral" + redisAppName := "redis" + verifyServiceBuildConfig := "jenkins-verifyservice-pipeline" - newAppRedisEphemeralArgs := []string{redisTemplate, "--name", redisAppName, "-p", "MEMORY_LIMIT=128Mi"} + newAppRedisEphemeralArgs := []string{redisTemplate, "--name", redisAppName, "-p", "MEMORY_LIMIT=128Mi"} - // Redis deployment with the redis service - g.By("instantiate the test application") - err := oc.Run("new-app").Args(newAppRedisEphemeralArgs...).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = exutil.WaitForDeploymentConfig(oc.KubeClient(), oc.AppsClient().AppsV1(), oc.Namespace(), redisAppName, 1, false, oc) - if err != nil { - exutil.DumpApplicationPodLogs(redisAppName, oc) - } + // Redis deployment with the redis service + g.By("instantiate the test application") + err := oc.Run("new-app").Args(newAppRedisEphemeralArgs...).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = exutil.WaitForDeploymentConfig(oc.KubeClient(), oc.AppsClient().AppsV1(), oc.Namespace(), redisAppName, 1, false, oc) + if err != nil { + exutil.DumpApplicationPodLogs(redisAppName, oc) + } - // Redis headless service and jenkinsFile which runs verify service on both the services - g.By("create the jenkins pipeline strategy build config that leverages openshift client plugin") - err = oc.Run("new-app").Args("-f", verifyServiceClientPluginPipelinePath).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + // Redis headless service and jenkinsFile which runs verify service on both the services + g.By("create the jenkins pipeline strategy build config that leverages openshift client plugin") + err = oc.Run("new-app").Args("-f", verifyServiceClientPluginPipelinePath).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + brservices, err := exutil.StartBuildAndWait(oc, verifyServiceBuildConfig) + if err != nil || !brservices.BuildSuccess { + debugAnyJenkinsFailure(brservices, oc.Namespace()+"-"+verifyServiceBuildConfig, oc, true) + exutil.DumpBuilds(oc) + exutil.DumpDeploymentLogs(redisAppName, 1, oc) + exutil.DumpBuildLogs(verifyServiceBuildConfig, oc) + } + brservices.AssertSuccess() + + g.By("get build console logs and see if succeeded") + _, err = j.GetJobConsoleLogsAndMatchViaBuildResult(brservices, "Finished: SUCCESS") + o.Expect(err).NotTo(o.HaveOccurred()) + g.By("clean up openshift resources for next potential run") + err = oc.Run("delete").Args("bc", verifyServiceBuildConfig).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("dc", redisAppName).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.AsAdmin().Run("delete").Args("all", "-l", fmt.Sprintf("app=%v", redisAppName)).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - brservices, err := exutil.StartBuildAndWait(oc, verifyServiceBuildConfig) - if err != nil || !brservices.BuildSuccess { - debugAnyJenkinsFailure(brservices, oc.Namespace()+"-"+verifyServiceBuildConfig, oc, true) - exutil.DumpBuilds(oc) - exutil.DumpDeploymentLogs(redisAppName, 1, oc) - exutil.DumpBuildLogs(verifyServiceBuildConfig, oc) - } - brservices.AssertSuccess() + }) - g.By("get build console logs and see if succeeded") - _, err = j.GetJobConsoleLogsAndMatchViaBuildResult(brservices, "Finished: SUCCESS") - o.Expect(err).NotTo(o.HaveOccurred()) - g.By("clean up openshift resources for next potential run") - err = oc.Run("delete").Args("bc", verifyServiceBuildConfig).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("dc", redisAppName).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.AsAdmin().Run("delete").Args("all", "-l", fmt.Sprintf("app=%v", redisAppName)).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("should handle multi-namespace templates", func() { + g.By("create additional projects") + namespace := oc.Namespace() + namespace2 := oc.Namespace() + "-2" + namespace3 := oc.Namespace() + "-3" + + err := oc.Run("new-project").Args(namespace2).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("new-project").Args(namespace3).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + // no calls to delete these two projects here; leads to timing + // issues with the framework deleting all namespaces + + g.By("set up policy for jenkins jobs in " + namespace2) + err = oc.Run("policy").Args("add-role-to-user", "edit", "system:serviceaccount:"+namespace+":jenkins", "-n", namespace2).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + g.By("set up policy for jenkins jobs in " + namespace3) + err = oc.Run("policy").Args("add-role-to-user", "edit", "system:serviceaccount:"+namespace+":jenkins", "-n", namespace3).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + // instantiate the bc + g.By("instantiate the jenkins pipeline strategy build config that leverages openshift client plugin with multiple namespaces") + err = oc.Run("new-app").Args("-f", multiNamespaceClientPluginPipelinePath, "-p", "NAMESPACE="+namespace, "-p", "NAMESPACE2="+namespace2, "-p", "NAMESPACE3="+namespace3).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + // run the build + g.By("starting the pipeline build and waiting for it to complete") + br, err := exutil.StartBuildAndWait(oc, "multi-namespace-pipeline") + if err != nil || !br.BuildSuccess { + debugAnyJenkinsFailure(br, oc.Namespace()+"-multi-namespace-pipeline", oc, true) + exutil.DumpBuilds(oc) + } + br.AssertSuccess() + g.By("get build console logs and see if succeeded") + _, err = j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") + o.Expect(err).NotTo(o.HaveOccurred()) + + g.By("confirm there are objects in second and third namespaces") + defer oc.SetNamespace(namespace) + oc.SetNamespace(namespace2) + output, err := oc.AsAdmin().Run("get").Args("all").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(output).To(o.ContainSubstring("deploymentconfig.apps.openshift.io/mongodb")) + oc.SetNamespace(namespace3) + output, err = oc.AsAdmin().Run("get").Args("all").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(output).To(o.ContainSubstring("service/mongodb")) + + g.By("clean up openshift resources for next potential run") + oc.SetNamespace(namespace) + err = oc.Run("delete").Args("bc", "multi-namespace-pipeline").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.AsAdmin().Run("delete").Args("all", "-l", "template=mongodb-ephemeral-template").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("template", "mongodb-ephemeral").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + }) }) - g.By("should handle multi-namespace templates", func() { - g.By("create additional projects") - namespace := oc.Namespace() - namespace2 := oc.Namespace() + "-2" - namespace3 := oc.Namespace() + "-3" - - err := oc.Run("new-project").Args(namespace2).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("new-project").Args(namespace3).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - // no calls to delete these two projects here; leads to timing - // issues with the framework deleting all namespaces - - g.By("set up policy for jenkins jobs in " + namespace2) - err = oc.Run("policy").Args("add-role-to-user", "edit", "system:serviceaccount:"+namespace+":jenkins", "-n", namespace2).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - g.By("set up policy for jenkins jobs in " + namespace3) - err = oc.Run("policy").Args("add-role-to-user", "edit", "system:serviceaccount:"+namespace+":jenkins", "-n", namespace3).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - - // instantiate the bc - g.By("instantiate the jenkins pipeline strategy build config that leverages openshift client plugin with multiple namespaces") - err = oc.Run("new-app").Args("-f", multiNamespaceClientPluginPipelinePath, "-p", "NAMESPACE="+namespace, "-p", "NAMESPACE2="+namespace2, "-p", "NAMESPACE3="+namespace3).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - - // run the build - g.By("starting the pipeline build and waiting for it to complete") - br, err := exutil.StartBuildAndWait(oc, "multi-namespace-pipeline") - if err != nil || !br.BuildSuccess { - debugAnyJenkinsFailure(br, oc.Namespace()+"-multi-namespace-pipeline", oc, true) - exutil.DumpBuilds(oc) - } - br.AssertSuccess() - - g.By("get build console logs and see if succeeded") - _, err = j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") - o.Expect(err).NotTo(o.HaveOccurred()) - - g.By("confirm there are objects in second and third namespaces") - defer oc.SetNamespace(namespace) - oc.SetNamespace(namespace2) - output, err := oc.AsAdmin().Run("get").Args("all").Output() - o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(output).To(o.ContainSubstring("deploymentconfig.apps.openshift.io/mongodb")) - oc.SetNamespace(namespace3) - output, err = oc.AsAdmin().Run("get").Args("all").Output() - o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(output).To(o.ContainSubstring("service/mongodb")) - - g.By("clean up openshift resources for next potential run") - oc.SetNamespace(namespace) - err = oc.Run("delete").Args("bc", "multi-namespace-pipeline").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.AsAdmin().Run("delete").Args("all", "-l", "template=mongodb-ephemeral-template").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("template", "mongodb-ephemeral").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - }) }) - }) - g.Context("Sync plugin tests", func() { + g.Describe("Sync plugin tests", func() { + g.It("using the ephemeral template", func() { + defer cleanup(jenkinsEphemeralTemplatePath) + setupJenkins(jenkinsEphemeralTemplatePath) - g.It("using the ephemeral template", func() { - defer cleanup(jenkinsEphemeralTemplatePath) - setupJenkins(jenkinsEphemeralTemplatePath) - - g.By("Deleted pipeline strategy buildconfigs") - - g.By("should not be recreated by the sync plugin", func() { - // create the bc - g.By(fmt.Sprintf("calling oc new-app -f %q", origPipelinePath)) - err := oc.Run("new-app").Args("-f", origPipelinePath).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("Deleted pipeline strategy buildconfigs") - g.By("verify job is in jenkins") - _, err = j.WaitForContent("", 200, 30*time.Second, "job/%s/job/%s-sample-pipeline/", oc.Namespace(), oc.Namespace()) - if err != nil { - exutil.DumpApplicationPodLogs("jenkins", oc) - } - o.Expect(err).NotTo(o.HaveOccurred()) - - g.By(fmt.Sprintf("delete pipeline strategy bc %q", origPipelinePath)) - err = oc.Run("delete").Args("bc", "sample-pipeline").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("should not be recreated by the sync plugin", func() { + // create the bc + g.By(fmt.Sprintf("calling oc new-app -f %q", origPipelinePath)) + err := oc.Run("new-app").Args("-f", origPipelinePath).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("verify job is not in jenkins") - _, err = j.WaitForContent("", 404, 30*time.Second, "job/%s/job/%s-sample-pipeline/", oc.Namespace(), oc.Namespace()) - if err != nil { - exutil.DumpApplicationPodLogs("jenkins", oc) - } - o.Expect(err).NotTo(o.HaveOccurred()) - - g.By("verify bc is still deleted") - err = oc.Run("get").Args("bc", "sample-pipeline").Execute() - o.Expect(err).To(o.HaveOccurred()) - - g.By("clean up openshift resources for next potential run") - // doing this as admin to avoid errors like this: - // Dec 14 13:13:02.275: INFO: Error running &{/usr/bin/oc [oc delete --config=/tmp/configfile590595709 --namespace=e2e-test-jenkins-pipeline-2z82q all -l template=mongodb-ephemeral-template] [] replicationcontroller "mongodb-1" deleted - // service "mongodb" deleted - // deploymentconfig.apps.openshift.io "mongodb" deleted - // Error from server (Forbidden): clusterserviceversions.operators.coreos.com is forbidden: User "e2e-test-jenkins-pipeline-2z82q-user" cannot list clusterserviceversions.operators.coreos.com in the namespace "e2e-test-jenkins-pipeline-2z82q": no RBAC policy matched - // Error from server (Forbidden): catalogsources.operators.coreos.com is forbidden: User "e2e-test-jenkins-pipeline-2z82q-user" cannot list catalogsources.operators.coreos.com in the namespace "e2e-test-jenkins-pipeline-2z82q": no RBAC policy matched - // Error from server (Forbidden): installplans.operators.coreos.com is forbidden: User "e2e-test-jenkins-pipeline-2z82q-user" cannot list installplans.operators.coreos.com in the namespace "e2e-test-jenkins-pipeline-2z82q": no RBAC policy matched - // Error from server (Forbidden): subscriptions.operators.coreos.com is forbidden: User "e2e-test-jenkins-pipeline-2z82q-user" cannot list subscriptions.operators.coreos.com in the namespace "e2e-test-jenkins-pipeline-2z82q": no RBAC policy matched - err = oc.AsAdmin().Run("delete").Args("all", "-l", "app=jenkins-pipeline-example").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - }) - - g.By("Sync secret to credential") - - g.By("should map openshift secret to a jenkins credential as the secret is manipulated", func() { - g.By("create secret for jenkins credential") - err := oc.Run("create").Args("-f", secretPath).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - - g.By("verify credential created since label should be there") - // NOTE, for the credential URL in Jenkins - // it returns rc 200 with no output if credential exists and a 404 if it does not exists - _, err = j.WaitForContent("", 200, 10*time.Second, "credentials/store/system/domain/_/credential/%s-%s/", oc.Namespace(), secretName) - if err != nil { - exutil.DumpApplicationPodLogs("jenkins", oc) - } - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("verify job is in jenkins") + _, err = j.WaitForContent("", 200, 30*time.Second, "job/%s/job/%s-sample-pipeline/", oc.Namespace(), oc.Namespace()) + if err != nil { + exutil.DumpApplicationPodLogs("jenkins", oc) + } + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("verify credential deleted when label removed") - err = oc.Run("label").Args("secret", secretName, secretCredentialSyncLabel+"-").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - _, err = j.WaitForContent("", 404, 10*time.Second, "credentials/store/system/domain/_/credential/%s-%s/", oc.Namespace(), secretName) - if err != nil { - exutil.DumpApplicationPodLogs("jenkins", oc) - } - o.Expect(err).NotTo(o.HaveOccurred()) + g.By(fmt.Sprintf("delete pipeline strategy bc %q", origPipelinePath)) + err = oc.Run("delete").Args("bc", "sample-pipeline").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("verify credential added when label added") - err = oc.Run("label").Args("secret", secretName, secretCredentialSyncLabel+"=true").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - _, err = j.WaitForContent("", 200, 10*time.Second, "credentials/store/system/domain/_/credential/%s-%s/", oc.Namespace(), secretName) - if err != nil { - exutil.DumpApplicationPodLogs("jenkins", oc) - } - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("verify job is not in jenkins") + _, err = j.WaitForContent("", 404, 30*time.Second, "job/%s/job/%s-sample-pipeline/", oc.Namespace(), oc.Namespace()) + if err != nil { + exutil.DumpApplicationPodLogs("jenkins", oc) + } + o.Expect(err).NotTo(o.HaveOccurred()) + + g.By("verify bc is still deleted") + err = oc.Run("get").Args("bc", "sample-pipeline").Execute() + o.Expect(err).To(o.HaveOccurred()) + + g.By("clean up openshift resources for next potential run") + // doing this as admin to avoid errors like this: + // Dec 14 13:13:02.275: INFO: Error running &{/usr/bin/oc [oc delete --config=/tmp/configfile590595709 --namespace=e2e-test-jenkins-pipeline-2z82q all -l template=mongodb-ephemeral-template] [] replicationcontroller "mongodb-1" deleted + // service "mongodb" deleted + // deploymentconfig.apps.openshift.io "mongodb" deleted + // Error from server (Forbidden): clusterserviceversions.operators.coreos.com is forbidden: User "e2e-test-jenkins-pipeline-2z82q-user" cannot list clusterserviceversions.operators.coreos.com in the namespace "e2e-test-jenkins-pipeline-2z82q": no RBAC policy matched + // Error from server (Forbidden): catalogsources.operators.coreos.com is forbidden: User "e2e-test-jenkins-pipeline-2z82q-user" cannot list catalogsources.operators.coreos.com in the namespace "e2e-test-jenkins-pipeline-2z82q": no RBAC policy matched + // Error from server (Forbidden): installplans.operators.coreos.com is forbidden: User "e2e-test-jenkins-pipeline-2z82q-user" cannot list installplans.operators.coreos.com in the namespace "e2e-test-jenkins-pipeline-2z82q": no RBAC policy matched + // Error from server (Forbidden): subscriptions.operators.coreos.com is forbidden: User "e2e-test-jenkins-pipeline-2z82q-user" cannot list subscriptions.operators.coreos.com in the namespace "e2e-test-jenkins-pipeline-2z82q": no RBAC policy matched + err = oc.AsAdmin().Run("delete").Args("all", "-l", "app=jenkins-pipeline-example").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + }) - g.By("verify credential deleted when secret deleted") - err = oc.Run("delete").Args("secret", secretName).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - _, err = j.WaitForContent("", 404, 10*time.Second, "credentials/store/system/domain/_/credential/%s-%s/", oc.Namespace(), secretName) - if err != nil { - exutil.DumpApplicationPodLogs("jenkins", oc) - } - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("Sync secret to credential") - // no need to clean up, last operation above deleted the secret - }) + g.By("should map openshift secret to a jenkins credential as the secret is manipulated", func() { + g.By("create secret for jenkins credential") + err := oc.Run("create").Args("-f", secretPath).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - //TODO - for these config map slave tests, as well and the imagestream/imagestreamtag - // tests ... rather than actually running the pipelines, we could just inspect the config in jenkins - // to make sure the k8s pod templates are there. - // In general, while we want at least one verification somewhere in pipeline.go that the agent - // images work, we should minimize the actually running of pipelines using them to only one - // for each maven/nodejs - g.By("Pipeline using config map slave") - - g.By("should build and complete successfully", func() { - g.By("create the pod template with config map") - err := oc.Run("create").Args("-f", configMapPodTemplatePath).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("verify credential created since label should be there") + // NOTE, for the credential URL in Jenkins + // it returns rc 200 with no output if credential exists and a 404 if it does not exists + _, err = j.WaitForContent("", 200, 10*time.Second, "credentials/store/system/domain/_/credential/%s-%s/", oc.Namespace(), secretName) + if err != nil { + exutil.DumpApplicationPodLogs("jenkins", oc) + } + o.Expect(err).NotTo(o.HaveOccurred()) - g.By(fmt.Sprintf("calling oc new-app -f %q", podTemplateSlavePipelinePath)) - err = oc.Run("new-app").Args("-f", podTemplateSlavePipelinePath).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("verify credential deleted when label removed") + err = oc.Run("label").Args("secret", secretName, secretCredentialSyncLabel+"-").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + _, err = j.WaitForContent("", 404, 10*time.Second, "credentials/store/system/domain/_/credential/%s-%s/", oc.Namespace(), secretName) + if err != nil { + exutil.DumpApplicationPodLogs("jenkins", oc) + } + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("starting the pipeline build and waiting for it to complete") - // this just does sh "mvn --version" - br, err := exutil.StartBuildAndWait(oc, "openshift-jee-sample") - if err != nil || !br.BuildSuccess { - debugAnyJenkinsFailure(br, oc.Namespace()+"-openshift-jee-sample", oc, true) - exutil.DumpBuilds(oc) - } - br.AssertSuccess() + g.By("verify credential added when label added") + err = oc.Run("label").Args("secret", secretName, secretCredentialSyncLabel+"=true").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + _, err = j.WaitForContent("", 200, 10*time.Second, "credentials/store/system/domain/_/credential/%s-%s/", oc.Namespace(), secretName) + if err != nil { + exutil.DumpApplicationPodLogs("jenkins", oc) + } + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("getting job log, make sure has success message") - out, err := j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") - o.Expect(err).NotTo(o.HaveOccurred()) - g.By("making sure job log ran with our config map slave pod template") - o.Expect(out).To(o.ContainSubstring("Running on jenkins-slave")) + g.By("verify credential deleted when secret deleted") + err = oc.Run("delete").Args("secret", secretName).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + _, err = j.WaitForContent("", 404, 10*time.Second, "credentials/store/system/domain/_/credential/%s-%s/", oc.Namespace(), secretName) + if err != nil { + exutil.DumpApplicationPodLogs("jenkins", oc) + } + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("clean up openshift resources for next potential run") - err = oc.Run("delete").Args("configmap", "jenkins-slave").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("bc", "openshift-jee-sample").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - }) + // no need to clean up, last operation above deleted the secret + }) - g.By("Pipeline using imagestream slave") + //TODO - for these config map slave tests, as well and the imagestream/imagestreamtag + // tests ... rather than actually running the pipelines, we could just inspect the config in jenkins + // to make sure the k8s pod templates are there. + // In general, while we want at least one verification somewhere in pipeline.go that the agent + // images work, we should minimize the actually running of pipelines using them to only one + // for each maven/nodejs + g.By("Pipeline using config map slave") + + g.By("should build and complete successfully", func() { + g.By("create the pod template with config map") + err := oc.Run("create").Args("-f", configMapPodTemplatePath).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + g.By(fmt.Sprintf("calling oc new-app -f %q", podTemplateSlavePipelinePath)) + err = oc.Run("new-app").Args("-f", podTemplateSlavePipelinePath).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + g.By("starting the pipeline build and waiting for it to complete") + // this just does sh "mvn --version" + br, err := exutil.StartBuildAndWait(oc, "openshift-jee-sample") + if err != nil || !br.BuildSuccess { + debugAnyJenkinsFailure(br, oc.Namespace()+"-openshift-jee-sample", oc, true) + exutil.DumpBuilds(oc) + } + br.AssertSuccess() - g.By("should build and complete successfully", func() { - g.By("create the pod template with imagestream") - err := oc.Run("create").Args("-f", imagestreamPodTemplatePath).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("getting job log, make sure has success message") + out, err := j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") + o.Expect(err).NotTo(o.HaveOccurred()) + g.By("making sure job log ran with our config map slave pod template") + o.Expect(out).To(o.ContainSubstring("Running on jenkins-slave")) + + g.By("clean up openshift resources for next potential run") + err = oc.Run("delete").Args("configmap", "jenkins-slave").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("bc", "openshift-jee-sample").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + }) - g.By(fmt.Sprintf("calling oc new-app -f %q", podTemplateSlavePipelinePath)) - err = oc.Run("new-app").Args("-f", podTemplateSlavePipelinePath).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("Pipeline using imagestream slave") - g.By("starting the pipeline build and waiting for it to complete") - // this just does sh "mvn --version" - br, err := exutil.StartBuildAndWait(oc, "openshift-jee-sample") - if err != nil || !br.BuildSuccess { - debugAnyJenkinsFailure(br, oc.Namespace()+"-openshift-jee-sample", oc, true) - exutil.DumpBuilds(oc) - } - br.AssertSuccess() + g.By("should build and complete successfully", func() { + g.By("create the pod template with imagestream") + err := oc.Run("create").Args("-f", imagestreamPodTemplatePath).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("getting job log, making sure job log has success message") - out, err := j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") - o.Expect(err).NotTo(o.HaveOccurred()) - g.By("making sure job log ran with our config map slave pod template") - o.Expect(out).To(o.ContainSubstring("Running on jenkins-slave")) + g.By(fmt.Sprintf("calling oc new-app -f %q", podTemplateSlavePipelinePath)) + err = oc.Run("new-app").Args("-f", podTemplateSlavePipelinePath).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("clean up openshift resources for next potential run") - err = oc.Run("delete").Args("is", "jenkins-slave").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("bc", "openshift-jee-sample").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - }) + g.By("starting the pipeline build and waiting for it to complete") + // this just does sh "mvn --version" + br, err := exutil.StartBuildAndWait(oc, "openshift-jee-sample") + if err != nil || !br.BuildSuccess { + debugAnyJenkinsFailure(br, oc.Namespace()+"-openshift-jee-sample", oc, true) + exutil.DumpBuilds(oc) + } + br.AssertSuccess() - g.By("Pipeline using imagestreamtag slave") + g.By("getting job log, making sure job log has success message") + out, err := j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") + o.Expect(err).NotTo(o.HaveOccurred()) + g.By("making sure job log ran with our config map slave pod template") + o.Expect(out).To(o.ContainSubstring("Running on jenkins-slave")) + + g.By("clean up openshift resources for next potential run") + err = oc.Run("delete").Args("is", "jenkins-slave").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("bc", "openshift-jee-sample").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + }) - g.By("should build and complete successfully", func() { - g.By("create the pod template with imagestream") - err := oc.Run("create").Args("-f", imagestreamtagPodTemplatePath).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("Pipeline using imagestreamtag slave") - g.By(fmt.Sprintf("calling oc new-app -f %q", podTemplateSlavePipelinePath)) - err = oc.Run("new-app").Args("-f", podTemplateSlavePipelinePath).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("should build and complete successfully", func() { + g.By("create the pod template with imagestream") + err := oc.Run("create").Args("-f", imagestreamtagPodTemplatePath).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("starting the pipeline build and waiting for it to complete") - // this just does sh "mvn --version" - br, err := exutil.StartBuildAndWait(oc, "openshift-jee-sample") - if err != nil || !br.BuildSuccess { - debugAnyJenkinsFailure(br, oc.Namespace()+"-openshift-jee-sample", oc, true) - exutil.DumpBuilds(oc) - } - br.AssertSuccess() + g.By(fmt.Sprintf("calling oc new-app -f %q", podTemplateSlavePipelinePath)) + err = oc.Run("new-app").Args("-f", podTemplateSlavePipelinePath).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("getting job log, making sure job log has success message") - out, err := j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") - o.Expect(err).NotTo(o.HaveOccurred()) - g.By("making sure job log ran with our config map slave pod template") - o.Expect(out).To(o.ContainSubstring("Running on slave-jenkins")) + g.By("starting the pipeline build and waiting for it to complete") + // this just does sh "mvn --version" + br, err := exutil.StartBuildAndWait(oc, "openshift-jee-sample") + if err != nil || !br.BuildSuccess { + debugAnyJenkinsFailure(br, oc.Namespace()+"-openshift-jee-sample", oc, true) + exutil.DumpBuilds(oc) + } + br.AssertSuccess() - g.By("clean up openshift resources for next potential run") - err = oc.Run("delete").Args("is", "slave-jenkins").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("bc", "openshift-jee-sample").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - }) + g.By("getting job log, making sure job log has success message") + out, err := j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") + o.Expect(err).NotTo(o.HaveOccurred()) + g.By("making sure job log ran with our config map slave pod template") + o.Expect(out).To(o.ContainSubstring("Running on slave-jenkins")) + + g.By("clean up openshift resources for next potential run") + err = oc.Run("delete").Args("is", "slave-jenkins").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("bc", "openshift-jee-sample").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + }) - g.By("Pipeline with env vars") + g.By("Pipeline with env vars") - g.By("should build and complete successfully", func() { - // instantiate the bc - g.By(fmt.Sprintf("calling oc new-app -f %q", envVarsPipelinePath)) - err := oc.Run("new-app").Args("-f", envVarsPipelinePath).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("should build and complete successfully", func() { + // instantiate the bc + g.By(fmt.Sprintf("calling oc new-app -f %q", envVarsPipelinePath)) + err := oc.Run("new-app").Args("-f", envVarsPipelinePath).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - // start the build - g.By("starting the pipeline build, including env var, and waiting for it to complete") - br, err := exutil.StartBuildAndWait(oc, "-e", "FOO2=BAR2", "sample-pipeline-withenvs") - if err != nil || !br.BuildSuccess { - debugAnyJenkinsFailure(br, oc.Namespace()+"-sample-pipeline-withenvs", oc, true) - exutil.DumpBuilds(oc) - } - br.AssertSuccess() + // start the build + g.By("starting the pipeline build, including env var, and waiting for it to complete") + br, err := exutil.StartBuildAndWait(oc, "-e", "FOO2=BAR2", "sample-pipeline-withenvs") + if err != nil || !br.BuildSuccess { + debugAnyJenkinsFailure(br, oc.Namespace()+"-sample-pipeline-withenvs", oc, true) + exutil.DumpBuilds(oc) + } + br.AssertSuccess() - g.By("confirm all the log annotations are there") - _, err = jenkins.ProcessLogURLAnnotations(oc, br) - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("confirm all the log annotations are there") + _, err = jenkins.ProcessLogURLAnnotations(oc, br) + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("get build console logs and see if succeeded") - out, err := j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") - if err != nil { - exutil.DumpApplicationPodLogs("jenkins", oc) - exutil.DumpBuilds(oc) - } - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("get build console logs and see if succeeded") + out, err := j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") + if err != nil { + exutil.DumpApplicationPodLogs("jenkins", oc) + exutil.DumpBuilds(oc) + } + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("and see if env is set") - if !strings.Contains(out, "FOO2 is BAR2") { - exutil.DumpApplicationPodLogs("jenkins", oc) - exutil.DumpBuilds(oc) - o.Expect(out).To(o.ContainSubstring("FOO2 is BAR2")) - } + g.By("and see if env is set") + if !strings.Contains(out, "FOO2 is BAR2") { + exutil.DumpApplicationPodLogs("jenkins", oc) + exutil.DumpBuilds(oc) + o.Expect(out).To(o.ContainSubstring("FOO2 is BAR2")) + } - // start the nextbuild - g.By("starting the pipeline build and waiting for it to complete") - br, err = exutil.StartBuildAndWait(oc, "sample-pipeline-withenvs") - if err != nil || !br.BuildSuccess { - debugAnyJenkinsFailure(br, oc.Namespace()+"-sample-pipeline-withenvs", oc, true) - exutil.DumpApplicationPodLogs("jenkins", oc) - exutil.DumpBuilds(oc) - } - br.AssertSuccess() + // start the nextbuild + g.By("starting the pipeline build and waiting for it to complete") + br, err = exutil.StartBuildAndWait(oc, "sample-pipeline-withenvs") + if err != nil || !br.BuildSuccess { + debugAnyJenkinsFailure(br, oc.Namespace()+"-sample-pipeline-withenvs", oc, true) + exutil.DumpApplicationPodLogs("jenkins", oc) + exutil.DumpBuilds(oc) + } + br.AssertSuccess() - g.By("get build console logs and see if succeeded") - out, err = j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") - if err != nil { - exutil.DumpApplicationPodLogs("jenkins", oc) - exutil.DumpBuilds(oc) - } - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("get build console logs and see if succeeded") + out, err = j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") + if err != nil { + exutil.DumpApplicationPodLogs("jenkins", oc) + exutil.DumpBuilds(oc) + } + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("and see if env FOO1 is set") - if !strings.Contains(out, "FOO1 is BAR1") { - exutil.DumpApplicationPodLogs("jenkins", oc) - exutil.DumpBuilds(oc) - o.Expect(out).To(o.ContainSubstring("FOO1 is BAR1")) - } + g.By("and see if env FOO1 is set") + if !strings.Contains(out, "FOO1 is BAR1") { + exutil.DumpApplicationPodLogs("jenkins", oc) + exutil.DumpBuilds(oc) + o.Expect(out).To(o.ContainSubstring("FOO1 is BAR1")) + } - g.By("and see if env FOO2 is still not set") - if !strings.Contains(out, "FOO2 is null") { - exutil.DumpApplicationPodLogs("jenkins", oc) - exutil.DumpBuilds(oc) - o.Expect(out).To(o.ContainSubstring("FOO2 is null")) - } + g.By("and see if env FOO2 is still not set") + if !strings.Contains(out, "FOO2 is null") { + exutil.DumpApplicationPodLogs("jenkins", oc) + exutil.DumpBuilds(oc) + o.Expect(out).To(o.ContainSubstring("FOO2 is null")) + } - g.By("clean up openshift resources for next potential run") - err = oc.Run("delete").Args("bc", "sample-pipeline-withenvs").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - }) + g.By("clean up openshift resources for next potential run") + err = oc.Run("delete").Args("bc", "sample-pipeline-withenvs").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + }) - g.By("delete jenkins job runs when the associated build is deleted") + g.By("delete jenkins job runs when the associated build is deleted") - g.By("should prune pipeline builds based on the buildConfig settings", func() { + g.By("should prune pipeline builds based on the buildConfig settings", func() { - g.By("creating successful test pipeline") - err := oc.Run("create").Args("-f", successfulPipeline).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("creating successful test pipeline") + err := oc.Run("create").Args("-f", successfulPipeline).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("starting four test builds") - // builds only do sh 'exit 0' - for i := 0; i < 4; i++ { - br, _ := exutil.StartBuildAndWait(oc, "successful-pipeline") - br.AssertSuccess() - } + g.By("starting four test builds") + // builds only do sh 'exit 0' + for i := 0; i < 4; i++ { + br, _ := exutil.StartBuildAndWait(oc, "successful-pipeline") + br.AssertSuccess() + } - buildConfig, err := oc.BuildClient().BuildV1().BuildConfigs(oc.Namespace()).Get(context.Background(), "successful-pipeline", metav1.GetOptions{}) - if err != nil { - fmt.Fprintf(g.GinkgoWriter, "%v", err) - } + buildConfig, err := oc.BuildClient().BuildV1().BuildConfigs(oc.Namespace()).Get(context.Background(), "successful-pipeline", metav1.GetOptions{}) + if err != nil { + fmt.Fprintf(g.GinkgoWriter, "%v", err) + } - var builds *buildv1.BuildList + var builds *buildv1.BuildList + + g.By("waiting up to one minute for pruning to complete") + err = wait.PollImmediate(pollingInterval, timeout, func() (bool, error) { + builds, err = oc.BuildClient().BuildV1().Builds(oc.Namespace()).List(context.Background(), metav1.ListOptions{LabelSelector: BuildConfigSelector("successful-pipeline").String()}) + if err != nil { + fmt.Fprintf(g.GinkgoWriter, "%v", err) + return false, err + } + if int32(len(builds.Items)) == *buildConfig.Spec.SuccessfulBuildsHistoryLimit { + fmt.Fprintf(g.GinkgoWriter, "%v builds exist, retrying...", len(builds.Items)) + return true, nil + } + return false, nil + }) - g.By("waiting up to one minute for pruning to complete") - err = wait.PollImmediate(pollingInterval, timeout, func() (bool, error) { - builds, err = oc.BuildClient().BuildV1().Builds(oc.Namespace()).List(context.Background(), metav1.ListOptions{LabelSelector: BuildConfigSelector("successful-pipeline").String()}) if err != nil { fmt.Fprintf(g.GinkgoWriter, "%v", err) - return false, err } - if int32(len(builds.Items)) == *buildConfig.Spec.SuccessfulBuildsHistoryLimit { - fmt.Fprintf(g.GinkgoWriter, "%v builds exist, retrying...", len(builds.Items)) - return true, nil + + passed := false + if int32(len(builds.Items)) == 2 || int32(len(builds.Items)) == 3 { + passed = true } - return false, nil - }) + o.Expect(passed).To(o.BeTrue(), "there should be 2-3 completed builds left after pruning, but instead there were %v", len(builds.Items)) - if err != nil { - fmt.Fprintf(g.GinkgoWriter, "%v", err) - } + g.By("creating failed test pipeline") + err = oc.Run("create").Args("-f", failedPipeline).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - passed := false - if int32(len(builds.Items)) == 2 || int32(len(builds.Items)) == 3 { - passed = true - } - o.Expect(passed).To(o.BeTrue(), "there should be 2-3 completed builds left after pruning, but instead there were %v", len(builds.Items)) + g.By("starting four test builds") + for i := 0; i < 4; i++ { + br, _ := exutil.StartBuildAndWait(oc, "failed-pipeline") + br.AssertFailure() + } - g.By("creating failed test pipeline") - err = oc.Run("create").Args("-f", failedPipeline).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + buildConfig, err = oc.BuildClient().BuildV1().BuildConfigs(oc.Namespace()).Get(context.Background(), "failed-pipeline", metav1.GetOptions{}) + if err != nil { + fmt.Fprintf(g.GinkgoWriter, "%v", err) + } - g.By("starting four test builds") - for i := 0; i < 4; i++ { - br, _ := exutil.StartBuildAndWait(oc, "failed-pipeline") - br.AssertFailure() - } + g.By("waiting up to one minute for pruning to complete") + err = wait.PollImmediate(pollingInterval, timeout, func() (bool, error) { + builds, err = oc.BuildClient().BuildV1().Builds(oc.Namespace()).List(context.Background(), metav1.ListOptions{LabelSelector: BuildConfigSelector("successful-pipeline").String()}) + if err != nil { + fmt.Fprintf(g.GinkgoWriter, "%v", err) + return false, err + } + if int32(len(builds.Items)) == *buildConfig.Spec.FailedBuildsHistoryLimit { + fmt.Fprintf(g.GinkgoWriter, "%v builds exist, retrying...", len(builds.Items)) + return true, nil + } + return false, nil + }) - buildConfig, err = oc.BuildClient().BuildV1().BuildConfigs(oc.Namespace()).Get(context.Background(), "failed-pipeline", metav1.GetOptions{}) - if err != nil { - fmt.Fprintf(g.GinkgoWriter, "%v", err) - } - - g.By("waiting up to one minute for pruning to complete") - err = wait.PollImmediate(pollingInterval, timeout, func() (bool, error) { - builds, err = oc.BuildClient().BuildV1().Builds(oc.Namespace()).List(context.Background(), metav1.ListOptions{LabelSelector: BuildConfigSelector("successful-pipeline").String()}) if err != nil { fmt.Fprintf(g.GinkgoWriter, "%v", err) - return false, err - } - if int32(len(builds.Items)) == *buildConfig.Spec.FailedBuildsHistoryLimit { - fmt.Fprintf(g.GinkgoWriter, "%v builds exist, retrying...", len(builds.Items)) - return true, nil } - return false, nil - }) - if err != nil { - fmt.Fprintf(g.GinkgoWriter, "%v", err) - } + passed = false + if int32(len(builds.Items)) == 2 || int32(len(builds.Items)) == 3 { + passed = true + } + o.Expect(passed).To(o.BeTrue(), "there should be 2-3 completed builds left after pruning, but instead there were %v", len(builds.Items)) - passed = false - if int32(len(builds.Items)) == 2 || int32(len(builds.Items)) == 3 { - passed = true - } - o.Expect(passed).To(o.BeTrue(), "there should be 2-3 completed builds left after pruning, but instead there were %v", len(builds.Items)) + g.By("clean up openshift resources for next potential run") + err = oc.Run("delete").Args("bc", "successful-pipeline").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("bc", "failed-pipeline").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("clean up openshift resources for next potential run") - err = oc.Run("delete").Args("bc", "successful-pipeline").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("bc", "failed-pipeline").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + }) }) }) }) - }) // BuildConfigSelector returns a label Selector which can be used to find all diff --git a/test/extended/builds/pipeline_origin_bld_rhelimagesonly.go b/test/extended/builds/pipeline_origin_bld_rhelimagesonly.go index cb3e016614c4..1687958a2cb5 100644 --- a/test/extended/builds/pipeline_origin_bld_rhelimagesonly.go +++ b/test/extended/builds/pipeline_origin_bld_rhelimagesonly.go @@ -148,215 +148,218 @@ var _ = g.Describe("[sig-devex][Feature:JenkinsRHELImagesOnly][Slow] openshift p } ) - g.Context("Sync plugin tests", func() { - - g.It("using the ephemeral template", func() { - defer cleanup("jenkins-ephemeral") - setupJenkins("jenkins-ephemeral") - - //TODO - for these config map slave tests, as well and the imagestream/imagestreamtag - // tests ... rather than actually running the pipelines, we could just inspect the config in jenkins - // to make sure the k8s pod templates are there. - // In general, while we want at least one verification somewhere in pipeline.go that the agent - // images work, we should minimize the actually running of pipelines using them to only one - // for each maven/nodejs - g.By("Pipeline using nodejs agent and client plugin") - - g.By("should build and complete successfully", func() { - g.By("create pipeline strategy build using nodejs agent and client plugin") - err := oc.Run("create").Args("-f", "https://raw.githubusercontent.com/openshift/origin/master/examples/jenkins/pipeline/nodejs-sample-pipeline.yaml").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - - g.By("starting the pipeline build and waiting for it to complete") - // this just does sh "mvn --version" - br, err := exutil.StartBuildAndWait(oc, "nodejs-sample-pipeline") - if err != nil || !br.BuildSuccess { - debugAnyJenkinsFailure(br, oc.Namespace()+"-nodejs-sample-pipeline", oc, true) - exutil.DumpBuilds(oc) - } - br.AssertSuccess() - - g.By("getting job log, make sure has success message") - out, err := j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") - o.Expect(err).NotTo(o.HaveOccurred()) - g.By("making sure job log ran with our nodejs pod template") - o.Expect(out).To(o.ContainSubstring("Running on nodejs")) + g.Context("", func() { + + g.Describe("Sync plugin tests", func() { + g.It("using the ephemeral template", func() { + defer cleanup("jenkins-ephemeral") + setupJenkins("jenkins-ephemeral") + + //TODO - for these config map slave tests, as well and the imagestream/imagestreamtag + // tests ... rather than actually running the pipelines, we could just inspect the config in jenkins + // to make sure the k8s pod templates are there. + // In general, while we want at least one verification somewhere in pipeline.go that the agent + // images work, we should minimize the actually running of pipelines using them to only one + // for each maven/nodejs + g.By("Pipeline using nodejs agent and client plugin") + + g.By("should build and complete successfully", func() { + g.By("create pipeline strategy build using nodejs agent and client plugin") + err := oc.Run("create").Args("-f", "https://raw.githubusercontent.com/openshift/origin/master/examples/jenkins/pipeline/nodejs-sample-pipeline.yaml").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + g.By("starting the pipeline build and waiting for it to complete") + // this just does sh "mvn --version" + br, err := exutil.StartBuildAndWait(oc, "nodejs-sample-pipeline") + if err != nil || !br.BuildSuccess { + debugAnyJenkinsFailure(br, oc.Namespace()+"-nodejs-sample-pipeline", oc, true) + exutil.DumpBuilds(oc) + } + br.AssertSuccess() - g.By("clean up openshift resources for next potential run") - err = oc.Run("delete").Args("bc", "--all").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("is", "--all").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("dc,svc", "mongodb", "--ignore-not-found").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("dc,svc,secret,route", "nodejs-mongodb-example", "--ignore-not-found").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("getting job log, make sure has success message") + out, err := j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") + o.Expect(err).NotTo(o.HaveOccurred()) + g.By("making sure job log ran with our nodejs pod template") + o.Expect(out).To(o.ContainSubstring("Running on nodejs")) + + g.By("clean up openshift resources for next potential run") + err = oc.Run("delete").Args("bc", "--all").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("is", "--all").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("dc,svc", "mongodb", "--ignore-not-found").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("dc,svc,secret,route", "nodejs-mongodb-example", "--ignore-not-found").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - }) + }) - g.By("Pipeline with env vars") + g.By("Pipeline with env vars") - g.By("should build and complete successfully", func() { - // instantiate the bc - g.By(fmt.Sprintf("calling oc new-app -f %q", envVarsPipelinePath)) - err := oc.Run("new-app").Args("-f", envVarsPipelinePath).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("should build and complete successfully", func() { + // instantiate the bc + g.By(fmt.Sprintf("calling oc new-app -f %q", envVarsPipelinePath)) + err := oc.Run("new-app").Args("-f", envVarsPipelinePath).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - // start the build - g.By("starting the pipeline build, including env var, and waiting for it to complete") - br, err := exutil.StartBuildAndWait(oc, "-e", "FOO2=BAR2", "sample-pipeline-withenvs") - if err != nil || !br.BuildSuccess { - debugAnyJenkinsFailure(br, oc.Namespace()+"-sample-pipeline-withenvs", oc, true) - exutil.DumpBuilds(oc) - } - br.AssertSuccess() + // start the build + g.By("starting the pipeline build, including env var, and waiting for it to complete") + br, err := exutil.StartBuildAndWait(oc, "-e", "FOO2=BAR2", "sample-pipeline-withenvs") + if err != nil || !br.BuildSuccess { + debugAnyJenkinsFailure(br, oc.Namespace()+"-sample-pipeline-withenvs", oc, true) + exutil.DumpBuilds(oc) + } + br.AssertSuccess() - g.By("confirm all the log annotations are there") - _, err = jenkins.ProcessLogURLAnnotations(oc, br) - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("confirm all the log annotations are there") + _, err = jenkins.ProcessLogURLAnnotations(oc, br) + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("get build console logs and see if succeeded") - out, err := j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") - if err != nil { - exutil.DumpApplicationPodLogs("jenkins", oc) - exutil.DumpBuilds(oc) - } - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("get build console logs and see if succeeded") + out, err := j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") + if err != nil { + exutil.DumpApplicationPodLogs("jenkins", oc) + exutil.DumpBuilds(oc) + } + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("and see if env is set") - if !strings.Contains(out, "FOO2 is BAR2") { - exutil.DumpApplicationPodLogs("jenkins", oc) - exutil.DumpBuilds(oc) - o.Expect(out).To(o.ContainSubstring("FOO2 is BAR2")) - } + g.By("and see if env is set") + if !strings.Contains(out, "FOO2 is BAR2") { + exutil.DumpApplicationPodLogs("jenkins", oc) + exutil.DumpBuilds(oc) + o.Expect(out).To(o.ContainSubstring("FOO2 is BAR2")) + } - // start the nextbuild - g.By("starting the pipeline build and waiting for it to complete") - br, err = exutil.StartBuildAndWait(oc, "sample-pipeline-withenvs") - if err != nil || !br.BuildSuccess { - debugAnyJenkinsFailure(br, oc.Namespace()+"-sample-pipeline-withenvs", oc, true) - exutil.DumpApplicationPodLogs("jenkins", oc) - exutil.DumpBuilds(oc) - } - br.AssertSuccess() + // start the nextbuild + g.By("starting the pipeline build and waiting for it to complete") + br, err = exutil.StartBuildAndWait(oc, "sample-pipeline-withenvs") + if err != nil || !br.BuildSuccess { + debugAnyJenkinsFailure(br, oc.Namespace()+"-sample-pipeline-withenvs", oc, true) + exutil.DumpApplicationPodLogs("jenkins", oc) + exutil.DumpBuilds(oc) + } + br.AssertSuccess() - g.By("get build console logs and see if succeeded") - out, err = j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") - if err != nil { - exutil.DumpApplicationPodLogs("jenkins", oc) - exutil.DumpBuilds(oc) - } - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("get build console logs and see if succeeded") + out, err = j.GetJobConsoleLogsAndMatchViaBuildResult(br, "Finished: SUCCESS") + if err != nil { + exutil.DumpApplicationPodLogs("jenkins", oc) + exutil.DumpBuilds(oc) + } + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("and see if env FOO1 is set") - if !strings.Contains(out, "FOO1 is BAR1") { - exutil.DumpApplicationPodLogs("jenkins", oc) - exutil.DumpBuilds(oc) - o.Expect(out).To(o.ContainSubstring("FOO1 is BAR1")) - } + g.By("and see if env FOO1 is set") + if !strings.Contains(out, "FOO1 is BAR1") { + exutil.DumpApplicationPodLogs("jenkins", oc) + exutil.DumpBuilds(oc) + o.Expect(out).To(o.ContainSubstring("FOO1 is BAR1")) + } - g.By("and see if env FOO2 is still not set") - if !strings.Contains(out, "FOO2 is null") { - exutil.DumpApplicationPodLogs("jenkins", oc) - exutil.DumpBuilds(oc) - o.Expect(out).To(o.ContainSubstring("FOO2 is null")) - } + g.By("and see if env FOO2 is still not set") + if !strings.Contains(out, "FOO2 is null") { + exutil.DumpApplicationPodLogs("jenkins", oc) + exutil.DumpBuilds(oc) + o.Expect(out).To(o.ContainSubstring("FOO2 is null")) + } - g.By("clean up openshift resources for next potential run") - err = oc.Run("delete").Args("bc", "sample-pipeline-withenvs").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - }) + g.By("clean up openshift resources for next potential run") + err = oc.Run("delete").Args("bc", "sample-pipeline-withenvs").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + }) - g.By("delete jenkins job runs when the associated build is deleted") + g.By("delete jenkins job runs when the associated build is deleted") - g.By("should prune pipeline builds based on the buildConfig settings", func() { + g.By("should prune pipeline builds based on the buildConfig settings", func() { - g.By("creating successful test pipeline") - err := oc.Run("create").Args("-f", successfulPipeline).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("creating successful test pipeline") + err := oc.Run("create").Args("-f", successfulPipeline).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("starting four test builds") - // builds only do sh 'exit 0' - for i := 0; i < 4; i++ { - br, _ := exutil.StartBuildAndWait(oc, "successful-pipeline") - br.AssertSuccess() - } + g.By("starting four test builds") + // builds only do sh 'exit 0' + for i := 0; i < 4; i++ { + br, _ := exutil.StartBuildAndWait(oc, "successful-pipeline") + br.AssertSuccess() + } - buildConfig, err := oc.BuildClient().BuildV1().BuildConfigs(oc.Namespace()).Get(context.Background(), "successful-pipeline", metav1.GetOptions{}) - if err != nil { - fmt.Fprintf(g.GinkgoWriter, "%v", err) - } + buildConfig, err := oc.BuildClient().BuildV1().BuildConfigs(oc.Namespace()).Get(context.Background(), "successful-pipeline", metav1.GetOptions{}) + if err != nil { + fmt.Fprintf(g.GinkgoWriter, "%v", err) + } - var builds *buildv1.BuildList + var builds *buildv1.BuildList + + g.By("waiting up to one minute for pruning to complete") + err = wait.PollImmediate(pollingInterval, timeout, func() (bool, error) { + builds, err = oc.BuildClient().BuildV1().Builds(oc.Namespace()).List(context.Background(), metav1.ListOptions{LabelSelector: BuildConfigSelector("successful-pipeline").String()}) + if err != nil { + fmt.Fprintf(g.GinkgoWriter, "%v", err) + return false, err + } + if int32(len(builds.Items)) == *buildConfig.Spec.SuccessfulBuildsHistoryLimit { + fmt.Fprintf(g.GinkgoWriter, "%v builds exist, retrying...", len(builds.Items)) + return true, nil + } + return false, nil + }) - g.By("waiting up to one minute for pruning to complete") - err = wait.PollImmediate(pollingInterval, timeout, func() (bool, error) { - builds, err = oc.BuildClient().BuildV1().Builds(oc.Namespace()).List(context.Background(), metav1.ListOptions{LabelSelector: BuildConfigSelector("successful-pipeline").String()}) if err != nil { fmt.Fprintf(g.GinkgoWriter, "%v", err) - return false, err } - if int32(len(builds.Items)) == *buildConfig.Spec.SuccessfulBuildsHistoryLimit { - fmt.Fprintf(g.GinkgoWriter, "%v builds exist, retrying...", len(builds.Items)) - return true, nil - } - return false, nil - }) - if err != nil { - fmt.Fprintf(g.GinkgoWriter, "%v", err) - } + passed := false + if int32(len(builds.Items)) == 2 || int32(len(builds.Items)) == 3 { + passed = true + } + o.Expect(passed).To(o.BeTrue(), "there should be 2-3 completed builds left after pruning, but instead there were %v", len(builds.Items)) - passed := false - if int32(len(builds.Items)) == 2 || int32(len(builds.Items)) == 3 { - passed = true - } - o.Expect(passed).To(o.BeTrue(), "there should be 2-3 completed builds left after pruning, but instead there were %v", len(builds.Items)) + g.By("creating failed test pipeline") + err = oc.Run("create").Args("-f", failedPipeline).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - g.By("creating failed test pipeline") - err = oc.Run("create").Args("-f", failedPipeline).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + g.By("starting four test builds") + for i := 0; i < 4; i++ { + br, _ := exutil.StartBuildAndWait(oc, "failed-pipeline") + br.AssertFailure() + } - g.By("starting four test builds") - for i := 0; i < 4; i++ { - br, _ := exutil.StartBuildAndWait(oc, "failed-pipeline") - br.AssertFailure() - } + buildConfig, err = oc.BuildClient().BuildV1().BuildConfigs(oc.Namespace()).Get(context.Background(), "failed-pipeline", metav1.GetOptions{}) + if err != nil { + fmt.Fprintf(g.GinkgoWriter, "%v", err) + } - buildConfig, err = oc.BuildClient().BuildV1().BuildConfigs(oc.Namespace()).Get(context.Background(), "failed-pipeline", metav1.GetOptions{}) - if err != nil { - fmt.Fprintf(g.GinkgoWriter, "%v", err) - } + g.By("waiting up to one minute for pruning to complete") + err = wait.PollImmediate(pollingInterval, timeout, func() (bool, error) { + builds, err = oc.BuildClient().BuildV1().Builds(oc.Namespace()).List(context.Background(), metav1.ListOptions{LabelSelector: BuildConfigSelector("successful-pipeline").String()}) + if err != nil { + fmt.Fprintf(g.GinkgoWriter, "%v", err) + return false, err + } + if int32(len(builds.Items)) == *buildConfig.Spec.FailedBuildsHistoryLimit { + fmt.Fprintf(g.GinkgoWriter, "%v builds exist, retrying...", len(builds.Items)) + return true, nil + } + return false, nil + }) - g.By("waiting up to one minute for pruning to complete") - err = wait.PollImmediate(pollingInterval, timeout, func() (bool, error) { - builds, err = oc.BuildClient().BuildV1().Builds(oc.Namespace()).List(context.Background(), metav1.ListOptions{LabelSelector: BuildConfigSelector("successful-pipeline").String()}) if err != nil { fmt.Fprintf(g.GinkgoWriter, "%v", err) - return false, err } - if int32(len(builds.Items)) == *buildConfig.Spec.FailedBuildsHistoryLimit { - fmt.Fprintf(g.GinkgoWriter, "%v builds exist, retrying...", len(builds.Items)) - return true, nil + + passed = false + if int32(len(builds.Items)) == 2 || int32(len(builds.Items)) == 3 { + passed = true } - return false, nil - }) + o.Expect(passed).To(o.BeTrue(), "there should be 2-3 completed builds left after pruning, but instead there were %v", len(builds.Items)) - if err != nil { - fmt.Fprintf(g.GinkgoWriter, "%v", err) - } + g.By("clean up openshift resources for next potential run") + err = oc.Run("delete").Args("bc", "successful-pipeline").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("delete").Args("bc", "failed-pipeline").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) - passed = false - if int32(len(builds.Items)) == 2 || int32(len(builds.Items)) == 3 { - passed = true - } - o.Expect(passed).To(o.BeTrue(), "there should be 2-3 completed builds left after pruning, but instead there were %v", len(builds.Items)) - - g.By("clean up openshift resources for next potential run") - err = oc.Run("delete").Args("bc", "successful-pipeline").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("delete").Args("bc", "failed-pipeline").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) + }) }) diff --git a/test/extended/builds/remove_buildconfig.go b/test/extended/builds/remove_buildconfig.go index 976d4a934ab7..4b1ab5ec01c8 100644 --- a/test/extended/builds/remove_buildconfig.go +++ b/test/extended/builds/remove_buildconfig.go @@ -43,6 +43,9 @@ var _ = g.Describe("[sig-builds][Feature:Builds] remove all builds when build co err error builds [4]string ) + configMaps, err := oc.KubeClient().CoreV1().ConfigMaps(oc.Namespace()).List(context.Background(), metav1.ListOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + initialConfigMapCount := len(configMaps.Items) g.By("starting multiple builds") for i := range builds { @@ -64,7 +67,7 @@ var _ = g.Describe("[sig-builds][Feature:Builds] remove all builds when build co } configMaps, err := oc.KubeClient().CoreV1().ConfigMaps(oc.Namespace()).List(context.Background(), metav1.ListOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - if len(configMaps.Items) > 0 { + if len(configMaps.Items) > initialConfigMapCount { return false, nil } return true, nil diff --git a/test/extended/builds/run_fs_verification.go b/test/extended/builds/run_fs_verification.go index 4ea38b2daad2..cdb5b98bdbc7 100644 --- a/test/extended/builds/run_fs_verification.go +++ b/test/extended/builds/run_fs_verification.go @@ -8,6 +8,7 @@ import ( o "github.com/onsi/gomega" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" ) var _ = g.Describe("[sig-builds][Feature:Builds] verify /run filesystem contents", func() { @@ -34,7 +35,7 @@ spec: value: "10" imageOptimizationPolicy: SkipLayers type: Docker -`, "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest") // replace with image.ShellImage()) when github.com/openshift/origin/test/extended/util/image lands in this release +`, image.ShellImage()) testVerifyRunFSContentsBuildConfigYaml = fmt.Sprintf(` apiVersion: build.openshift.io/v1 kind: BuildConfig @@ -55,7 +56,7 @@ spec: value: "10" imageOptimizationPolicy: SkipLayers type: Docker -`, "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest") // replace with image.ShellImage()) when github.com/openshift/origin/test/extended/util/image lands in this release +`, image.ShellImage()) lsRSlashRun = ` /run: lock diff --git a/test/extended/builds/s2i_env.go b/test/extended/builds/s2i_env.go index 853cde0a69d0..62741c592b81 100644 --- a/test/extended/builds/s2i_env.go +++ b/test/extended/builds/s2i_env.go @@ -22,7 +22,7 @@ var _ = g.Describe("[sig-builds][Feature:Builds][Slow] s2i build with environmen ) var ( - imageStreamFixture = exutil.FixturePath("..", "integration", "testdata", "test-image-stream.json") + imageStreamFixture = exutil.FixturePath("testdata", "builds", "test-image-stream.json") stiEnvBuildFixture = exutil.FixturePath("testdata", "builds", "test-env-build.json") podAndServiceFixture = exutil.FixturePath("testdata", "builds", "test-build-podsvc.json") oc = exutil.NewCLI("build-sti-env") diff --git a/test/extended/builds/s2i_root.go b/test/extended/builds/s2i_root.go index feca4f5e98bf..4cf10cb2bf65 100644 --- a/test/extended/builds/s2i_root.go +++ b/test/extended/builds/s2i_root.go @@ -2,6 +2,8 @@ package builds import ( "context" + "fmt" + "github.com/openshift/origin/test/extended/util/image" g "github.com/onsi/ginkgo" o "github.com/onsi/gomega" @@ -35,7 +37,8 @@ var _ = g.Describe("[sig-builds][Feature:Builds] s2i build with a root user imag Before(oc) defer After(oc) - err := oc.Run("new-app").Args("quay.io/redhat-developer/test-build-roots2i~https://github.com/sclorg/nodejs-ex", "--name", "nodejsfail").Execute() + firstArgString := fmt.Sprintf("%s~https://github.com/sclorg/nodejs-ex", image.LocationFor("registry.svc.ci.openshift.org/ocp/4.7:test-build-roots2i")) + err := oc.Run("new-app").Args(firstArgString, "--name", "nodejsfail").Execute() o.Expect(err).NotTo(o.HaveOccurred()) err = exutil.WaitForABuild(oc.BuildClient().BuildV1().Builds(oc.Namespace()), "nodejsfail-1", nil, nil, nil) @@ -111,7 +114,8 @@ var _ = g.Describe("[sig-builds][Feature:Builds] s2i build with a root user imag roleBinding, err = oc.AdminKubeClient().RbacV1().RoleBindings(oc.Namespace()).Create(context.Background(), roleBinding, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - err = oc.Run("new-build").Args("quay.io/redhat-developer/test-build-roots2i~https://github.com/sclorg/nodejs-ex", "--name", "nodejspass").Execute() + firstArgString := fmt.Sprintf("%s~https://github.com/sclorg/nodejs-ex", image.LocationFor("registry.svc.ci.openshift.org/ocp/4.7:test-build-roots2i")) + err = oc.Run("new-build").Args(firstArgString, "--name", "nodejspass").Execute() o.Expect(err).NotTo(o.HaveOccurred()) err = exutil.WaitForABuild(oc.BuildClient().BuildV1().Builds(oc.Namespace()), "nodejspass-1", nil, nil, nil) diff --git a/test/extended/builds/service.go b/test/extended/builds/service.go index d8c694c86ebf..5d8054f297e6 100644 --- a/test/extended/builds/service.go +++ b/test/extended/builds/service.go @@ -2,6 +2,7 @@ package builds import ( "context" + "fmt" g "github.com/onsi/ginkgo" o "github.com/onsi/gomega" @@ -9,19 +10,21 @@ import ( kapierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kdeployutil "k8s.io/kubernetes/test/e2e/framework/deployment" + k8simage "k8s.io/kubernetes/test/utils/image" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" ) var _ = g.Describe("[sig-builds][Feature:Builds] build can reference a cluster service", func() { defer g.GinkgoRecover() var ( oc = exutil.NewCLI("build-service") - testDockerfile = ` -FROM image-registry.openshift-image-registry.svc:5000/openshift/tools:latest + testDockerfile = fmt.Sprintf(` +FROM %s RUN cat /etc/resolv.conf -RUN curl -vvv hello-openshift:8080 -` +RUN curl -vvv hello-openshift:6379 +`, image.ShellImage()) ) g.Context("", func() { @@ -41,7 +44,7 @@ RUN curl -vvv hello-openshift:8080 g.Describe("with a build being created from new-build", func() { g.It("should be able to run a build that references a cluster service", func() { g.By("standing up a new hello world service") - err := oc.Run("new-app").Args("quay.io/openshifttest/hello-openshift:openshift").Execute() + err := oc.Run("new-app").Args("--name", "hello-openshift", k8simage.GetE2EImage(k8simage.Redis)).Execute() o.Expect(err).NotTo(o.HaveOccurred()) deploy, derr := oc.KubeClient().AppsV1().Deployments(oc.Namespace()).Get(context.Background(), "hello-openshift", metav1.GetOptions{}) diff --git a/test/extended/builds/start.go b/test/extended/builds/start.go index a7ce6a3cd19b..dd6b79164295 100644 --- a/test/extended/builds/start.go +++ b/test/extended/builds/start.go @@ -368,7 +368,7 @@ var _ = g.Describe("[sig-builds][Feature:Builds][Slow] starting a build using CL }) g.It("Should accept build args that are specified in the Dockerfile", func() { g.By("starting the build with --build-arg flag") - br, _ := exutil.StartBuildAndWait(oc, "sample-build-docker-args", "--build-arg=foo=bar") + br, _ := exutil.StartBuildAndWait(oc, "sample-build-docker-args", "--build-arg=foofoo=bar") br.AssertSuccess() verifyNodeSelector(oc, br.BuildName) buildLog, err := br.Logs() diff --git a/test/extended/cli/adm.go b/test/extended/cli/adm.go deleted file mode 100644 index c08202843c1e..000000000000 --- a/test/extended/cli/adm.go +++ /dev/null @@ -1,74 +0,0 @@ -package cli - -import ( - "context" - "fmt" - "math/rand" - "time" - - g "github.com/onsi/ginkgo" - o "github.com/onsi/gomega" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/kubernetes/test/e2e/framework" - - exutil "github.com/openshift/origin/test/extended/util" -) - -var _ = g.Describe("[sig-cli] oc adm", func() { - defer g.GinkgoRecover() - - f := framework.NewDefaultFramework("oc-adm") - f.SkipNamespaceCreation = true - f.SkipPrivilegedPSPBinding = true - - oc := exutil.NewCLIWithoutNamespace("oc-adm").AsAdmin() - - g.It("oc adm node-logs", func() { - o.Expect(oc.Run("adm", "node-logs").Args(randomNode(oc)).Execute()).To(o.Succeed()) - }) - - g.It("oc adm node-logs --role=master --since=-2m", func() { - masters, err := oc.AdminKubeClient().CoreV1().Nodes().List(context.Background(), metav1.ListOptions{ - LabelSelector: "node-role.kubernetes.io/master", - }) - o.Expect(err).NotTo(o.HaveOccurred()) - - out, err := oc.Run("adm", "node-logs").Args("--role=master", "--since=-2m").Output() - o.Expect(err).NotTo(o.HaveOccurred()) - for _, m := range masters.Items { - if hostname, ok := m.Labels["kubernetes.io/hostname"]; ok { - o.Expect(out).To(o.ContainSubstring(hostname)) - } - } - }) - - g.It("oc adm node-logs --boot=0", func() { - o.Expect(oc.Run("adm", "node-logs").Args(randomNode(oc), "--boot=0").Execute()).To(o.Succeed()) - }) - - g.It("oc adm node-logs --since=-2m --until=-1m", func() { - o.Expect(oc.Run("adm", "node-logs").Args(randomNode(oc), "--since=-2m", "--until=-1m").Execute()).To(o.Succeed()) - }) - - g.It("oc adm node-logs --since= --until=-1m", func() { - since := time.Now().Add(-2 * time.Minute).Format("2006-01-02 15:04:05") - out, err := oc.Run("adm", "node-logs").Args(randomNode(oc), fmt.Sprintf("--since=%s", since)).Output() - o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(out).NotTo(o.ContainSubstring("Failed to parse timestamp: ")) - }) - - g.It("oc adm node-logs --unit=kubelet --since=-1m", func() { - o.Expect(oc.Run("adm", "node-logs").Args(randomNode(oc), "--unit=kubelet", "--since=-2m").Execute()).To(o.Succeed()) - }) - - g.It("oc adm node-logs --tail=5", func() { - o.Expect(oc.Run("adm", "node-logs").Args(randomNode(oc), "--tail=5").Execute()).To(o.Succeed()) - }) -}) - -func randomNode(oc *exutil.CLI) string { - nodes, err := oc.AdminKubeClient().CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) - o.Expect(err).NotTo(o.HaveOccurred()) - return nodes.Items[rand.Intn(len(nodes.Items))].Name -} diff --git a/test/extended/cli/admin.go b/test/extended/cli/admin.go new file mode 100644 index 000000000000..0254def30efa --- /dev/null +++ b/test/extended/cli/admin.go @@ -0,0 +1,609 @@ +package cli + +import ( + "context" + "fmt" + "math/rand" + "strings" + "time" + + g "github.com/onsi/ginkgo" + o "github.com/onsi/gomega" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/apiserver/pkg/storage/names" + "k8s.io/kubernetes/test/e2e/framework" + + exutil "github.com/openshift/origin/test/extended/util" +) + +var ( + cliInterval = 5 * time.Second + cliTimeout = 1 * time.Minute +) + +var _ = g.Describe("[sig-cli] oc adm", func() { + defer g.GinkgoRecover() + + f := framework.NewDefaultFramework("oc-adm") + f.SkipNamespaceCreation = true + f.SkipPrivilegedPSPBinding = true + + oc := exutil.NewCLIWithoutNamespace("oc-adm").AsAdmin() + ocns := exutil.NewCLI("oc-adm-ns").AsAdmin() + policyRolesPath := exutil.FixturePath("testdata", "roles", "policy-roles.yaml") + policyClusterRolesPath := exutil.FixturePath("testdata", "roles", "policy-clusterroles.yaml") + gen := names.SimpleNameGenerator + + g.It("node-logs", func() { + o.Expect(oc.Run("adm", "node-logs").Args(randomNode(oc)).Execute()).To(o.Succeed()) + + masters, err := oc.AdminKubeClient().CoreV1().Nodes().List(context.Background(), metav1.ListOptions{ + LabelSelector: "node-role.kubernetes.io/master", + }) + o.Expect(err).NotTo(o.HaveOccurred()) + + out, err := oc.Run("adm", "node-logs").Args("--role=master", "--since=-2m").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + for _, m := range masters.Items { + if hostname, ok := m.Labels["kubernetes.io/hostname"]; ok { + o.Expect(out).To(o.ContainSubstring(hostname)) + } + } + + o.Expect(oc.Run("adm", "node-logs").Args(randomNode(oc), "--boot=0").Execute()).To(o.Succeed()) + + o.Expect(oc.Run("adm", "node-logs").Args(randomNode(oc), "--since=-2m", "--until=-1m").Execute()).To(o.Succeed()) + + since := time.Now().Add(-2 * time.Minute).Format("2006-01-02 15:04:05") + out, err = oc.Run("adm", "node-logs").Args(randomNode(oc), fmt.Sprintf("--since=%s", since)).Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).NotTo(o.ContainSubstring("Failed to parse timestamp: ")) + + o.Expect(oc.Run("adm", "node-logs").Args(randomNode(oc), "--unit=kubelet", "--since=-2m").Execute()).To(o.Succeed()) + + o.Expect(oc.Run("adm", "node-logs").Args(randomNode(oc), "--tail=5").Execute()).To(o.Succeed()) + }) + + g.It("groups", func() { + shortoutputgroup := gen.GenerateName("shortoutputgroup-") + out, err := oc.Run("adm", "groups", "new").Args(shortoutputgroup, "--output=name").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("group.user.openshift.io/shortoutputgroup-")) + + out, err = oc.Run("adm", "groups", "new").Args(gen.GenerateName("mygroup-"), "--dry-run").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.MatchRegexp(`group\.user\.openshift\.io\/mygroup-[[:alnum:]]+ created \(dry run\)`)) + + out, err = oc.Run("get").Args("groups", "mygroup").Output() + o.Expect(err).To(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring(`groups.user.openshift.io "mygroup" not found`)) + + out, err = oc.Run("adm", "groups", "new").Args(gen.GenerateName("shortoutputgroup-"), "-oname", "--dry-run").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("group.user.openshift.io/shortoutputgroup-")) + + out, err = oc.Run("adm", "groups", "new").Args(shortoutputgroup).Output() + o.Expect(err).To(o.HaveOccurred()) + o.Expect(out).To(o.MatchRegexp(`groups\.user\.openshift\.io "shortoutputgroup-[[:alnum:]]+" already exists`)) + + errorgroup := gen.GenerateName("errorgroup-") + out, err = oc.Run("adm", "groups", "new").Args(errorgroup, "-o", "blah").Output() + o.Expect(err).To(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring(`unable to match a printer suitable for the output format "blah"`)) + + out, err = oc.Run("get").Args(fmt.Sprintf("groups/%s", errorgroup), "-o blah").Output() + o.Expect(err).To(o.HaveOccurred()) + o.Expect(out).To(o.MatchRegexp(`groups\.user\.openshift\.io "errorgroup-[[:alnum:]]+" not found`)) + + group1 := gen.GenerateName("group1-") + o.Expect(oc.Run("adm", "groups", "new").Args(group1, "foo", "bar").Execute()).To(o.Succeed()) + + out, err = oc.Run("get").Args(fmt.Sprintf("groups/%s", group1), "--no-headers").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("foo, bar")) + + o.Expect(oc.Run("adm", "groups", "add-users").Args(group1, "baz").Execute()).To(o.Succeed()) + + out, err = oc.Run("get").Args(fmt.Sprintf("groups/%s", group1), "-ogo-template", `--template="{{.users}}"`).Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("baz")) + + o.Expect(oc.Run("adm", "groups", "remove-users").Args(group1, "bar").Execute()).To(o.Succeed()) + + out, err = oc.Run("get").Args(fmt.Sprintf("groups/%s", group1), "--no-headers").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).NotTo(o.ContainSubstring("bar")) + + out, err = oc.Run("adm", "prune", "auth").Args("users/baz").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.MatchRegexp(`group\.user\.openshift\.io\/group1-[[:alnum:]]+ updated`)) + + oc.Run("delete", fmt.Sprintf("groups/%s", shortoutputgroup)).Execute() + oc.Run("delete", fmt.Sprintf("groups/%s", group1)).Execute() + }) + + g.It("who-can", func() { + o.Expect(oc.Run("adm", "policy", "who-can").Args("get", "pods").Execute()).To(o.Succeed()) + o.Expect(oc.Run("adm", "policy", "who-can").Args("get", "pods", "-n", "default").Execute()).To(o.Succeed()) + o.Expect(oc.Run("adm", "policy", "who-can").Args("get", "pods", "--all-namespaces").Execute()).To(o.Succeed()) + + // check to make sure that the resource arg conforms to resource rules + out, err := oc.Run("adm", "policy", "who-can").Args("get", "Pod").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("Resource: pods")) + + out, err = oc.Run("adm", "policy", "who-can").Args("get", "PodASDF").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("Resource: PodASDF")) + + out, err = oc.Run("adm", "policy", "who-can").Args("get", "hpa.autoscaling", "--namespace=default").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("Resource: horizontalpodautoscalers.autoscaling")) + + out, err = oc.Run("adm", "policy", "who-can").Args("get", "hpa.v1.autoscaling", "--namespace=default").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("Resource: horizontalpodautoscalers.autoscaling")) + + out, err = oc.Run("adm", "policy", "who-can").Args("get", "hpa", "--namespace=default").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("Resource: horizontalpodautoscalers.autoscaling")) + }) + + g.It("policy", func() { + o.Expect(ocns.Run("adm", "policy", "add-role-to-group").Args("--rolebinding-name=cluster-admin", "cluster-admin", "system:unauthenticated").Execute()).To(o.Succeed()) + o.Expect(ocns.Run("adm", "policy", "add-role-to-user").Args("--rolebinding-name=cluster-admin", "cluster-admin", "system:no-user").Execute()).To(o.Succeed()) + + o.Expect(ocns.Run("adm", "policy", "remove-role-from-group").Args("cluster-admin", "system:unauthenticated").Execute()).To(o.Succeed()) + o.Expect(ocns.Run("adm", "policy", "remove-role-from-user").Args("cluster-admin", "system:no-user").Execute()).To(o.Succeed()) + + o.Expect(ocns.Run("adm", "policy", "add-role-to-user").Args("--rolebinding-name=admin", "admin", "-z", "fake-sa").Execute()).To(o.Succeed()) + out, err := ocns.Run("get").Args("rolebinding/admin", "-o", "jsonpath={.subjects}").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("fake-sa")) + o.Expect(ocns.Run("adm", "policy", "remove-role-from-user").Args("admin", "-z", "fake-sa").Execute()).To(o.Succeed()) + out, err = ocns.Run("get").Args("rolebinding/admin", "-o", "jsonpath={.subjects}").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).NotTo(o.ContainSubstring("fake-sa")) + + o.Expect(ocns.Run("adm", "policy", "add-role-to-user").Args("--rolebinding-name=admin", "admin", "-z", "fake-sa").Execute()).To(o.Succeed()) + out, err = ocns.Run("get").Args("rolebinding/admin", "-o", "jsonpath={.subjects}").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("fake-sa")) + o.Expect(ocns.Run("adm", "policy", "remove-role-from-user").Args("admin", fmt.Sprintf("system:serviceaccount:%s:fake-sa", ocns.Namespace())).Execute()).To(o.Succeed()) + out, err = ocns.Run("get").Args("rolebinding/admin", "-o", "jsonpath={.subjects}").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).NotTo(o.ContainSubstring("fake-sa")) + + o.Expect(ocns.Run("adm", "policy", "add-role-to-user").Args("admin", "fake-ghost").Execute()).To(o.Succeed()) + out, err = ocns.Run("adm", "policy", "remove-role-from-user").Args("admin", "ghost").Output() + o.Expect(err).To(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("error: unable to find target [ghost]")) + out, err = ocns.Run("adm", "policy", "remove-role-from-user").Args("admin", "-z", "ghost").Output() + o.Expect(err).To(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("error: unable to find target [ghost]")) + o.Expect(ocns.Run("adm", "policy", "remove-role-from-user").Args("admin", "fake-ghost").Execute()).To(o.Succeed()) + + o.Expect(ocns.Run("adm", "policy", "remove-group").Args("system:unauthenticated").Execute()).To(o.Succeed()) + o.Expect(ocns.Run("adm", "policy", "remove-user").Args("system:no-user").Execute()).To(o.Succeed()) + + o.Expect(oc.Run("adm", "policy", "add-cluster-role-to-group").Args("cluster-admin", "system:unauthenticated").Execute()).To(o.Succeed()) + o.Expect(oc.Run("adm", "policy", "remove-cluster-role-from-group").Args("cluster-admin", "system:unauthenticated").Execute()).To(o.Succeed()) + o.Expect(oc.Run("adm", "policy", "add-cluster-role-to-group").Args("cluster-admin", "system:no-user").Execute()).To(o.Succeed()) + o.Expect(oc.Run("adm", "policy", "remove-cluster-role-from-group").Args("cluster-admin", "system:no-user").Execute()).To(o.Succeed()) + + o.Expect(ocns.Run("adm", "policy", "add-role-to-user").Args("view", "foo").Execute()).To(o.Succeed()) + o.Expect(ocns.Run("adm", "policy", "add-role-to-user").Args("view", "bar", "--rolebinding-name=custom").Execute()).To(o.Succeed()) + o.Expect(ocns.Run("adm", "policy", "add-role-to-user").Args("view", "baz", "--rolebinding-name=custom").Execute()).To(o.Succeed()) + + out, err = ocns.Run("get").Args("rolebinding/view", "-o", `jsonpath="{.metadata.name},{.roleRef.name},{.subjects[*].name}"`).Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("view,view,foo")) + + out, err = ocns.Run("get").Args("rolebinding/custom", "-o", `jsonpath="{.metadata.name},{.roleRef.name},{.subjects[*].name}"`).Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("custom,view,bar baz")) + + out, err = ocns.Run("adm", "policy", "add-role-to-user").Args("other", "fuz", "--rolebinding-name=custom").Output() + o.Expect(err).To(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("error: rolebinding custom found for role view, not other")) + + o.Expect(oc.Run("adm", "policy", "add-scc-to-user").Args("privileged", "fake-user").Execute()).To(o.Succeed()) + o.Expect(oc.Run("adm", "policy", "add-scc-to-user").Args("privileged", "-z", "fake-sa").Execute()).To(o.Succeed()) + o.Expect(oc.Run("adm", "policy", "add-scc-to-group").Args("privileged", "fake-group").Execute()).To(o.Succeed()) + out, err = oc.Run("get").Args("clusterrolebinding/system:openshift:scc:privileged", "-o", "yaml").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("fake-user")) + o.Expect(out).To(o.ContainSubstring("fake-sa")) + o.Expect(out).To(o.ContainSubstring("fake-group")) + + o.Expect(oc.Run("adm", "policy", "remove-scc-from-user").Args("privileged", "fake-user").Execute()).To(o.Succeed()) + o.Expect(oc.Run("adm", "policy", "remove-scc-from-user").Args("privileged", "-z", "fake-sa").Execute()).To(o.Succeed()) + o.Expect(oc.Run("adm", "policy", "remove-scc-from-group").Args("privileged", "fake-group").Execute()).To(o.Succeed()) + out, err = oc.Run("get").Args("clusterrolebinding/system:openshift:scc:privileged", "-o", "yaml").Output() + o.Expect(err).To(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring(`clusterrolebindings.rbac.authorization.k8s.io "system:openshift:scc:privileged" not found`)) + + // check pruning + o.Expect(oc.Run("adm", "policy", "add-scc-to-user").Args("privileged", "fake-user").Execute()).To(o.Succeed()) + out, err = oc.Run("adm", "prune", "auth").Args("users/fake-user").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("clusterrolebinding.rbac.authorization.k8s.io/system:openshift:scc:privileged updated")) + + o.Expect(oc.Run("adm", "policy", "add-scc-to-group").Args("privileged", "fake-group").Execute()).To(o.Succeed()) + out, err = oc.Run("adm", "prune", "auth").Args("group/fake-group").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("clusterrolebinding.rbac.authorization.k8s.io/system:openshift:scc:privileged updated")) + }) + + g.It("storage-admin", func() { + g.By("Test storage-admin role and impersonation") + o.Expect(oc.Run("adm", "policy", "add-cluster-role-to-user").Args("storage-admin", "storage-adm").Execute()).To(o.Succeed()) + o.Expect(oc.Run("adm", "policy", "add-cluster-role-to-user").Args("storage-admin", "storage-adm2").Execute()).To(o.Succeed()) + o.Expect(ocns.Run("adm", "policy", "add-role-to-user").Args("admin", "storage-adm2").Execute()).To(o.Succeed()) + out, err := oc.Run("policy", "who-can").Args("impersonate", "storage-admin").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("cluster-admin")) + + g.By("Test storage-admin can not do normal project scoped tasks") + out, err = oc.Run("auth", "can-i").Args("--as=storage-adm", "create", "pods", "--all-namespaces").Output() + o.Expect(err).To(o.HaveOccurred()) + o.Expect(out).To(o.HaveSuffix("no")) + + out, err = oc.Run("auth", "can-i").Args("--as=storage-adm", "create", "projects").Output() + o.Expect(err).To(o.HaveOccurred()) + o.Expect(out).To(o.HaveSuffix("no")) + + out, err = oc.Run("auth", "can-i").Args("--as=storage-adm", "create", "pvc").Output() + o.Expect(err).To(o.HaveOccurred()) + o.Expect(out).To(o.HaveSuffix("no")) + + g.By("Test storage-admin can read pvc and pods, and create pv and storageclass") + out, err = oc.Run("auth", "can-i").Args("--as=storage-adm", "get", "pvc", "--all-namespaces").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.HaveSuffix("yes")) + + out, err = oc.Run("auth", "can-i").Args("--as=storage-adm", "get", "storageclass").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.HaveSuffix("yes")) + + out, err = oc.Run("auth", "can-i").Args("--as=storage-adm", "create", "pv").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.HaveSuffix("yes")) + + out, err = oc.Run("auth", "can-i").Args("--as=storage-adm", "create", "storageclass").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.HaveSuffix("yes")) + + out, err = oc.Run("auth", "can-i").Args("--as=storage-adm", "get", "pods", "--all-namespaces").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.HaveSuffix("yes")) + + g.By("Test failure to change policy on users for storage-admin") + out, err = oc.Run("policy", "add-role-to-user").Args("admin", "storage-adm", "--as=storage-adm").Output() + o.Expect(err).To(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring(`cannot list resource "rolebindings" in API group "rbac.authorization.k8s.io"`)) + + out, err = oc.Run("policy", "remove-user").Args("screeley", "--as=storage-adm").Output() + o.Expect(err).To(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring(`cannot list resource "rolebindings" in API group "rbac.authorization.k8s.io"`)) + + g.By("Test that scoped storage-admin now an admin in project foo") + o.Expect(oc.Run("new-project").Args("--as=storage-adm2", "--as-group=system:authenticated:oauth", "--as-group=sytem:authenticated", "policy-can-i").Execute()).NotTo(o.HaveOccurred()) + + out, err = oc.Run("auth", "can-i").Args("--as=storage-adm2", "create", "pod", "--all-namespaces").Output() + o.Expect(err).To(o.HaveOccurred()) + o.Expect(out).To(o.HaveSuffix("no")) + + out, err = oc.Run("auth", "can-i").Args("--as=storage-adm2", "create", "pod").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.HaveSuffix("yes")) + + out, err = oc.Run("auth", "can-i").Args("--as=storage-adm2", "create", "pvc").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.HaveSuffix("yes")) + + out, err = oc.Run("auth", "can-i").Args("--as=storage-adm2", "create", "endpoints").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.HaveSuffix("yes")) + + oc.Run("delete").Args("policy-can-i").Execute() + }) + + g.It("role-reapers", func() { + policyRoles, _, err := ocns.Run("process").Args("-f", policyRolesPath, "-p", fmt.Sprintf("NAMESPACE=%s", ocns.Namespace())).Outputs() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(ocns.Run("create").Args("-f", "-").InputString(policyRoles).Execute()).To(o.Succeed()) + o.Expect(ocns.Run("get").Args("rolebinding/basic-users").Execute()).To(o.Succeed()) + var out string + out, err = ocns.Run("adm", "prune", "auth").Args("role/basic-user").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("rolebinding.rbac.authorization.k8s.io/basic-users deleted")) + err = wait.Poll(cliInterval, cliTimeout, func() (bool, error) { + err := ocns.Run("get").Args("rolebinding/basic-users").Execute() + return err != nil, nil + }) + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(ocns.Run("delete").Args("role/basic-user").Execute()).To(o.Succeed()) + + oc.Run("delete").Args("-f", "-").InputString(policyRoles).Execute() + }) + + g.It("cluster-role-reapers", func() { + clusterRole := gen.GenerateName("basic-user2-") + clusterBinding := gen.GenerateName("basic-users2-") + policyClusterRoles, _, err := ocns.Run("process").Args("-f", policyClusterRolesPath, "-p", fmt.Sprintf("ROLE_NAME=%s", clusterRole), "-p", fmt.Sprintf("BINDING_NAME=%s", clusterBinding)).Outputs() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(oc.Run("create").Args("-f", "-").InputString(policyClusterRoles).Execute()).To(o.Succeed()) + + o.Expect(oc.Run("get").Args(fmt.Sprintf("clusterrolebinding/%s", clusterBinding)).Execute()).To(o.Succeed()) + out, err := oc.Run("adm", "prune", "auth").Args(fmt.Sprintf("clusterrole/%s", clusterRole)).Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.MatchRegexp(`clusterrolebinding\.rbac\.authorization\.k8s\.io\/basic-users2-[[:alnum:]]+ deleted`)) + err = wait.Poll(cliInterval, cliTimeout, func() (bool, error) { + err := oc.Run("get").Args("clusterrolebinding", clusterBinding).Execute() + return err != nil, nil + }) + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(ocns.Run("delete").Args(fmt.Sprintf("clusterrole/%s", clusterRole)).Execute()).To(o.Succeed()) + + o.Expect(ocns.Run("policy", "add-role-to-user").Args("edit", "foo").Execute()).To(o.Succeed()) + o.Expect(ocns.Run("get").Args("rolebinding/edit").Execute()).To(o.Succeed()) + o.Expect(oc.Run("adm", "prune", "auth").Args("clusterrole/edit").Execute()).To(o.Succeed()) + err = wait.Poll(cliInterval, cliTimeout, func() (bool, error) { + err := ocns.Run("get").Args("rolebinding/edit").Execute() + return err != nil, nil + }) + o.Expect(err).NotTo(o.HaveOccurred()) + + oc.Run("delete").Args("-f", "-").InputString(policyClusterRoles).Execute() + }) + + g.It("role-selectors", func() { + clusterRole := gen.GenerateName("basic-user2-") + clusterBinding := gen.GenerateName("basic-users2-") + // template processing requires a namespaced client + policyClusterRoles, _, err := ocns.Run("process").Args("-f", policyClusterRolesPath, "-p", fmt.Sprintf("ROLE_NAME=%s", clusterRole), "-p", fmt.Sprintf("BINDING_NAME=%s", clusterBinding)).Outputs() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(oc.Run("create").Args("-f", "-").InputString(policyClusterRoles).Execute()).To(o.Succeed()) + + o.Expect(oc.Run("get").Args(fmt.Sprintf("clusterrole/%s", clusterRole)).Execute()).To(o.Succeed()) + o.Expect(oc.Run("label").Args(fmt.Sprintf("clusterrole/%s", clusterRole), "foo=bar").Execute()).To(o.Succeed()) + + out, err := oc.Run("get").Args("clusterroles", "--selector=foo=bar").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).NotTo(o.ContainSubstring("No resources found")) + out, err = oc.Run("get").Args("clusterroles", "--selector=foo=unknown").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("No resources found")) + + o.Expect(oc.Run("get").Args(fmt.Sprintf("clusterrolebinding/%s", clusterBinding)).Execute()).To(o.Succeed()) + o.Expect(oc.Run("label").Args(fmt.Sprintf("clusterrolebinding/%s", clusterBinding), "foo=bar").Execute()).To(o.Succeed()) + + out, err = oc.Run("get").Args("clusterrolebindings", "--selector=foo=bar").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).NotTo(o.ContainSubstring("No resources found")) + out, err = oc.Run("get").Args("clusterrolebindings", "--selector=foo=unknown").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("No resources found")) + + oc.Run("delete").Args("-f", "-").InputString(policyClusterRoles).Execute() + }) + + g.It("ui-project-commands", func() { + // Test the commands the UI projects page tells users to run + // These should match what is described in projects.html + o.Expect(oc.Run("adm", "new-project").Args("ui-test-project", "--admin=createuser").Execute()).To(o.Succeed()) + o.Expect(oc.Run("adm", "policy", "add-role-to-user").Args("--rolebinding-name=admin", "admin", "adduser", "-n", "ui-test-project").Execute()).To(o.Succeed()) + + // Make sure project can be listed by oc (after auth cache syncs) + err := wait.Poll(cliInterval, cliTimeout, func() (bool, error) { + err := ocns.Run("get").Args("project/ui-test-project").Execute() + return err == nil, nil + }) + o.Expect(err).NotTo(o.HaveOccurred()) + + // Make sure users got added + var out string + out, err = oc.Run("get").Args("rolebinding/admin", "-n", "ui-test-project", "-o", "jsonpath={.subjects[*].name}").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("createuser adduser")) + + ocns.Run("delete").Args("project/ui-test-project").Execute() + }) + + g.It("new-project", func() { + // Test deleting and recreating a project + o.Expect(oc.Run("adm", "new-project").Args("recreated-project", "--admin=createuser1").Execute()).To(o.Succeed()) + o.Expect(oc.Run("delete").Args("project", "recreated-project").Execute()).To(o.Succeed()) + err := wait.Poll(cliInterval, cliTimeout, func() (bool, error) { + out, err := ocns.Run("get").Args("project/recreated-project").Output() + return err != nil && strings.Contains(out, "not found"), nil + }) + o.Expect(err).NotTo(o.HaveOccurred()) + + o.Expect(oc.Run("adm", "new-project").Args("recreated-project", "--admin=createuser2").Execute()).To(o.Succeed()) + var out string + out, err = oc.Run("get").Args("rolebinding", "admin", "-n", "recreated-project", "-o", "jsonpath={.subjects[*].name}").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("createuser2")) + + oc.Run("delete").Args("project", "recreated-project").Execute() + }) + + g.It("build-chain", func() { + // Test building a dependency tree + s2iBuildPath := exutil.FixturePath("..", "..", "examples", "sample-app", "application-template-stibuild.json") + out, _, err := ocns.Run("process").Args("-f", s2iBuildPath, "-l", "build=sti").Outputs() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(ocns.Run("create").Args("-f", "-").InputString(out).Execute()).To(o.Succeed()) + + // Test both the type/name resource syntax and the fact that istag/origin-ruby-sample:latest is still + // not created but due to a buildConfig pointing to it, we get back its graph of deps. + out, err = ocns.Run("adm", "build-chain").Args("istag/origin-ruby-sample").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("origin-ruby-sample:latest")) + + out, err = ocns.Run("adm", "build-chain").Args("ruby-27-centos7", "-o", "dot").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring(`digraph "ruby-27-centos7:latest"`)) + + ocns.Run("delete").Args("all", "-l", "build=sti").Execute() + }) + + g.It("serviceaccounts", func() { + // create a new service account + out, err := ocns.Run("create", "serviceaccount").Args("my-sa-name").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("serviceaccount/my-sa-name created")) + o.Expect(ocns.Run("get").Args("sa", "my-sa-name").Execute()).To(o.Succeed()) + err = wait.Poll(cliInterval, cliTimeout, func() (bool, error) { + err := ocns.Run("sa", "get-token").Args("my-sa-name").Execute() + return err == nil, nil + }) + o.Expect(err).NotTo(o.HaveOccurred()) + + // TODO (soltysh): the problem with this test is we can't force --token + // flag to take precedence over KUBECONFIG env var which is injected + // by default into tests: + + // extract token and ensure it links us back to the service account + // var token string + // token, err = ocns.Run("sa", "get-token").Args("my-sa-name").Output() + // o.Expect(err).NotTo(o.HaveOccurred()) + // out, err = ocns.WithToken(token).Run("get").Args("user/~").Output() + // o.Expect(err).NotTo(o.HaveOccurred()) + // o.Expect(out).To(o.ContainSubstring(fmt.Sprintf("system:serviceaccount:%s:my-sa-name", ocns.Namespace()))) + + // add a new labeled token and ensure the label stuck + o.Expect(ocns.Run("sa", "new-token").Args("my-sa-name", "--labels=mykey=myvalue,myotherkey=myothervalue").Execute()).To(o.Succeed()) + out, err = ocns.Run("get").Args("secrets", "--selector=mykey=myvalue").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("my-sa-name")) + out, err = ocns.Run("get").Args("secrets", "--selector=myotherkey=myothervalue").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("my-sa-name")) + out, err = ocns.Run("get").Args("secrets", "--selector=mykey=myvalue,myotherkey=myothervalue").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("my-sa-name")) + + ocns.Run("delete").Args("sa/my-sa-name").Execute() + }) + + g.It("user-creation", func() { + user := gen.GenerateName("test-cmd-user-") + identity := gen.GenerateName("test-idp:test-uid-") + o.Expect(oc.Run("create", "user").Args(user).Execute()).To(o.Succeed()) + o.Expect(oc.Run("create", "identity").Args(identity).Execute()).To(o.Succeed()) + o.Expect(oc.Run("create", "useridentitymapping").Args(identity, user).Execute()).To(o.Succeed()) + + out, err := oc.Run("describe").Args("identity", identity).Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("test-cmd-user")) + out, err = oc.Run("describe").Args("user", user).Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("test-idp:test-uid")) + + oc.Run("delete").Args(fmt.Sprintf("user/%s", user)).Execute() + oc.Run("delete").Args(fmt.Sprintf("identity/%s", identity)).Execute() + oc.Run("delete").Args(fmt.Sprintf("useridentitymapping/%s", identity)).Execute() + }) + + g.It("images", func() { + stableBusyboxPath := exutil.FixturePath("testdata", "stable-busybox.yaml") + o.Expect(oc.Run("create").Args("-f", stableBusyboxPath).Execute()).To(o.Succeed()) + + out, err := oc.Run("adm", "top", "images").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.MatchRegexp(`sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6\W+default/busybox \(latest\)\W+\W+\W+yes\W+653\.4KiB`)) + out, err = oc.Run("adm", "top", "imagestreams").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.MatchRegexp(`default/busybox\W+653\.4KiB\W+1\W+1`)) + + oc.Run("delete").Args("-f", stableBusyboxPath).Execute() + }) + + // TODO (soltysh): sync with Standa and figure out if we can get these + // enabled back, they were all disabled in admin.sh: + + // os::test::junit::declare_suite_start "cmd/admin/rolebinding-allowed" + // # Admin can bind local roles without cluster-admin permissions + // os::cmd::expect_success "oc create -f ${TEST_DATA}/roles/empty-role.yaml -n '${project}'" + // os::cmd::expect_success 'oc adm policy add-role-to-user admin local-admin -n '${project}'' + // os::cmd::expect_success 'oc login -u local-admin -p pw' + // os::cmd::expect_success 'oc policy add-role-to-user empty-role other --role-namespace='${project}' -n '${project}'' + // os::cmd::expect_success 'oc login -u system:admin' + // os::cmd::expect_success "oc delete role/empty-role -n '${project}'" + // echo "cmd/admin/rolebinding-allowed: ok" + // os::test::junit::declare_suite_end + + // os::test::junit::declare_suite_start "cmd/admin/rolebinding-local-only" + // # Admin cannot bind local roles from different namespace + // otherproject='someotherproject' + // os::cmd::expect_success "oc new-project '${otherproject}'" + // os::cmd::expect_success "oc create -f ${TEST_DATA}/roles/empty-role.yaml -n '${project}'" + // os::cmd::expect_success 'oc adm policy add-role-to-user admin local-admin -n '${otherproject}'' + // os::cmd::expect_success 'oc login -u local-admin -p pw' + // os::cmd::expect_failure_and_text 'oc policy add-role-to-user empty-role other --role-namespace='${project}' -n '${otherproject}'' "role binding in namespace \"${otherproject}\" can't reference role in different namespace \"${project}\"" + // os::cmd::expect_success 'oc login -u system:admin' + // os::cmd::expect_success "oc delete role/empty-role -n '${project}'" + // echo "rolebinding-local-only: ok" + // os::test::junit::declare_suite_end + + // os::test::junit::declare_suite_start "cmd/admin/user-group-cascade" + // # Create test users/identities and groups + // os::cmd::expect_success 'oc login -u cascaded-user -p pw' + // os::cmd::expect_success 'oc login -u orphaned-user -p pw' + // os::cmd::expect_success 'oc login -u system:admin' + // # switch to using --template once template printing is available to all cmds through the genericclioptions printer + // os::cmd::expect_success_and_text 'oc adm groups new cascaded-group cascaded-user orphaned-user -o yaml' '\- cascaded\-user' + // # switch to using --template once template printing is available to all cmds through the genericclioptions printer + // os::cmd::expect_success_and_text 'oc adm groups new orphaned-group cascaded-user orphaned-user -o yaml' '\- orphaned\-user' + // # Add roles, sccs to users/groups + // os::cmd::expect_success 'oc adm policy add-scc-to-user restricted cascaded-user orphaned-user' + // os::cmd::expect_success 'oc adm policy add-scc-to-group restricted cascaded-group orphaned-group' + // os::cmd::expect_success 'oc adm policy add-role-to-user --rolebinding-name=cluster-admin cluster-admin cascaded-user orphaned-user -n default' + // os::cmd::expect_success 'oc adm policy add-role-to-group --rolebinding-name=cluster-admin cluster-admin cascaded-group orphaned-group -n default' + // os::cmd::expect_success 'oc adm policy add-cluster-role-to-user --rolebinding-name=cluster-admin cluster-admin cascaded-user orphaned-user' + // os::cmd::expect_success 'oc adm policy add-cluster-role-to-group --rolebinding-name=cluster-admin cluster-admin cascaded-group orphaned-group' + + // # Delete users + // os::cmd::expect_success 'oc adm prune auth user/cascaded-user' + // os::cmd::expect_success 'oc delete user cascaded-user' + // os::cmd::expect_success 'oc delete user orphaned-user --cascade=false' + // # Verify all identities remain + // os::cmd::expect_success 'oc get identities/alwaysallow:cascaded-user' + // os::cmd::expect_success 'oc get identities/alwaysallow:orphaned-user' + // # Verify orphaned user references are left + // os::cmd::expect_success_and_text "oc get clusterrolebindings/cluster-admins clusterrolebindings/cluster-admin -o jsonpath='{ .items[*].subjects }'" 'orphaned-user' + // os::cmd::expect_success_and_text "oc get rolebindings/cluster-admin --template='{{.subjects}}' -n default" 'orphaned-user' + // os::cmd::expect_success_and_text "oc get scc/restricted --template='{{.users}}'" 'orphaned-user' + // os::cmd::expect_success_and_text "oc get group/cascaded-group --template='{{.users}}'" 'orphaned-user' + // # Verify cascaded user references are removed + // os::cmd::expect_success_and_not_text "oc get clusterrolebindings/cluster-admins clusterrolebindings/cluster-admin -o jsonpath='{ .items[*].subjects }'" 'cascaded-user' + // os::cmd::expect_success_and_not_text "oc get rolebindings/cluster-admin --template='{{.subjects}}' -n default" 'cascaded-user' + // os::cmd::expect_success_and_not_text "oc get scc/restricted --template='{{.users}}'" 'cascaded-user' + // os::cmd::expect_success_and_not_text "oc get group/cascaded-group --template='{{.users}}'" 'cascaded-user' + + // # Delete groups + // os::cmd::expect_success "oc adm prune auth group/cascaded-group" + // os::cmd::expect_success 'oc delete group cascaded-group' + // os::cmd::expect_success 'oc delete group orphaned-group --cascade=false' + // # Verify orphaned group references are left + // os::cmd::expect_success_and_text "oc get clusterrolebindings/cluster-admins clusterrolebindings/cluster-admin -o jsonpath='{ .items[*].subjects }'" 'orphaned-group' + // os::cmd::expect_success_and_text "oc get rolebindings/cluster-admin --template='{{.subjects}}' -n default" 'orphaned-group' + // os::cmd::expect_success_and_text "oc get scc/restricted --template='{{.groups}}'" 'orphaned-group' + // # Verify cascaded group references are removed + // os::cmd::expect_success_and_not_text "oc get clusterrolebindings/cluster-admins clusterrolebindings/cluster-admin -o jsonpath='{ .items[*].subjects }'" 'cascaded-group' + // os::cmd::expect_success_and_not_text "oc get rolebindings/cluster-admin --template='{{.subjects}}' -n default" 'cascaded-group' + // os::cmd::expect_success_and_not_text "oc get scc/restricted --template='{{.groups}}'" 'cascaded-group' + // echo "user-group-cascade: ok" + // os::test::junit::declare_suite_end +}) + +func randomNode(oc *exutil.CLI) string { + nodes, err := oc.AdminKubeClient().CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + return nodes.Items[rand.Intn(len(nodes.Items))].Name +} diff --git a/test/extended/cli/compat.go b/test/extended/cli/compat.go index 3b9bf019c36b..5852ea8e32d9 100644 --- a/test/extended/cli/compat.go +++ b/test/extended/cli/compat.go @@ -13,11 +13,10 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" ) func cliPod(cli *exutil.CLI, shell string) *kapiv1.Pod { - cliImage, _ := exutil.FindCLIImage(cli) - return &kapiv1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "cli-test", @@ -27,7 +26,7 @@ func cliPod(cli *exutil.CLI, shell string) *kapiv1.Pod { Containers: []kapiv1.Container{ { Name: "test", - Image: cliImage, + Image: image.ShellImage(), Command: []string{"/bin/bash", "-c", "set -euo pipefail; " + shell}, Env: []kapiv1.EnvVar{ { @@ -41,9 +40,7 @@ func cliPod(cli *exutil.CLI, shell string) *kapiv1.Pod { } } -func cliPodWithImage(cli *exutil.CLI, image string, shell string) *kapiv1.Pod { - cliImage, _ := exutil.FindCLIImage(cli) - +func cliPodWithImage(cli *exutil.CLI, shell string) *kapiv1.Pod { return &kapiv1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "cli-test", @@ -51,50 +48,17 @@ func cliPodWithImage(cli *exutil.CLI, image string, shell string) *kapiv1.Pod { Spec: kapiv1.PodSpec{ ServiceAccountName: "builder", RestartPolicy: kapiv1.RestartPolicyNever, - Volumes: []kapiv1.Volume{ - { - Name: "bin", - VolumeSource: kapiv1.VolumeSource{ - EmptyDir: &kapiv1.EmptyDirVolumeSource{}, - }, - }, - }, - InitContainers: []kapiv1.Container{ - { - Name: "cli", - Image: cliImage, - Command: []string{"/bin/bash", "-c", "set -e; cp /usr/bin/oc /tmp/bin/"}, - Env: []kapiv1.EnvVar{ - { - Name: "HOME", - Value: "/tmp", - }, - }, - VolumeMounts: []kapiv1.VolumeMount{ - { - Name: "bin", - MountPath: "/tmp/bin", - }, - }, - }, - }, Containers: []kapiv1.Container{ { Name: "test", - Image: cliImage, - Command: []string{"/bin/bash", "-c", "set -euo pipefail; export PATH=/tmp/bin:$PATH; " + shell}, + Image: image.ShellImage(), + Command: []string{"/bin/bash", "-c", shell}, Env: []kapiv1.EnvVar{ { Name: "HOME", Value: "/tmp", }, }, - VolumeMounts: []kapiv1.VolumeMount{ - { - Name: "bin", - MountPath: "/tmp/bin", - }, - }, }, }, }, @@ -128,7 +92,7 @@ var _ = g.Describe("[sig-cli] CLI", func() { }, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - pod := cli.Create(cliPodWithImage(oc, "busybox:latest", heredoc.Docf(` + pod := cli.Create(cliPodWithImage(oc, heredoc.Docf(` set -x # verify we can make API calls diff --git a/test/extended/cli/debug.go b/test/extended/cli/debug.go index bfdc58f33af0..b0a8cd6db6a5 100644 --- a/test/extended/cli/debug.go +++ b/test/extended/cli/debug.go @@ -1,46 +1,203 @@ package cli import ( + "fmt" + "time" + g "github.com/onsi/ginkgo" o "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/util/wait" + exutil "github.com/openshift/origin/test/extended/util" ) -var _ = g.Describe("[sig-cli][Slow] oc debug", func() { +var ( + buildTimeout = 10 * time.Minute + deployTimeout = 2 * time.Minute +) + +var _ = g.Describe("[sig-cli] oc debug", func() { + defer g.GinkgoRecover() + oc := exutil.NewCLI("oc-debug") - templatePath := exutil.FixturePath("testdata", "test-cli-debug.yaml") + testCLIDebug := exutil.FixturePath("testdata", "test-cli-debug.yaml") + testDeploymentConfig := exutil.FixturePath("testdata", "test-deployment-config.yaml") + testReplicationController := exutil.FixturePath("testdata", "test-replication-controller.yaml") + helloPod := exutil.FixturePath("..", "..", "examples", "hello-openshift", "hello-pod.json") + imageStreamsCentos := exutil.FixturePath("..", "..", "examples", "image-streams", "image-streams-centos7.json") + + g.It("deployment configs from a build", func() { + err := oc.Run("create").Args("-f", testCLIDebug).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + // wait for image stream to be present which means the build has completed + err = wait.Poll(cliInterval, buildTimeout, func() (bool, error) { + err := oc.Run("get").Args("imagestreamtags", "local-busybox:latest").Execute() + return err == nil, nil + }) + o.Expect(err).NotTo(o.HaveOccurred()) + // and for replication controller which means we can kick of debug session + err = wait.Poll(cliInterval, deployTimeout, func() (bool, error) { + err := oc.Run("get").Args("replicationcontrollers", "local-busybox1-1").Execute() + return err == nil, nil + }) + o.Expect(err).NotTo(o.HaveOccurred()) + + g.By("should print the imagestream-based container entrypoint/command") + var out string + out, err = oc.Run("debug").Args("dc/local-busybox1").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("Starting pod/local-busybox1-debug, command was: /usr/bin/bash\n")) - g.JustBeforeEach(func() { - g.By("calling oc create -f " + templatePath) - err := oc.Run("create").Args("-f", templatePath).Execute() + g.By("should print the overridden imagestream-based container entrypoint/command") + out, err = oc.Run("debug").Args("dc/local-busybox2").Output() o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("Starting pod/local-busybox2-debug, command was: foo bar baz qux\n")) - exutil.WaitForAnImageStreamTag(oc, oc.Namespace(), "local-busybox", "latest") + g.By("should print the container image-based container entrypoint/command") + out, err = oc.Run("debug").Args("dc/busybox1").Output() o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("Starting pod/busybox1-debug ...\n")) + + g.By("should print the overridden container image-based container entrypoint/command") + out, err = oc.Run("debug").Args("dc/busybox2").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("Starting pod/busybox2-debug, command was: foo bar baz qux\n")) }) - g.It("should print the imagestream-based container entrypoint/command", func() { - out, err := oc.Run("debug").Args("dc/local-busybox1").Output() + g.It("dissect deployment config debug", func() { + err := oc.Run("create").Args("-f", testDeploymentConfig).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + var out string + out, err = oc.Run("debug").Args("dc/test-deployment-config", "-oyaml").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("- /bin/sh")) + + out, err = oc.Run("debug").Args("dc/test-deployment-config", "--keep-annotations", "-oyaml").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("annotations:")) + + out, err = oc.Run("debug").Args("dc/test-deployment-config", "--as-root", "-oyaml").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("runAsUser: 0")) + + out, err = oc.Run("debug").Args("dc/test-deployment-config", "--as-root=false", "-oyaml").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("runAsNonRoot: true")) + + out, err = oc.Run("debug").Args("dc/test-deployment-config", "--as-user=1", "-oyaml").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("runAsUser: 1")) + + out, err = oc.Run("debug").Args("dc/test-deployment-config", "-t", "-oyaml").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("stdinOnce")) + o.Expect(out).To(o.ContainSubstring("tty")) + + out, err = oc.Run("debug").Args("dc/test-deployment-config", "--tty=false", "-oyaml").Output() o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(out).To(o.ContainSubstring("Debugging with pod/local-busybox1-debug, original command: sh\n")) + o.Expect(out).NotTo(o.ContainSubstring("tty")) + + out, err = oc.Run("debug").Args("dc/test-deployment-config", "-oyaml", "--", "/bin/env").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("- /bin/env")) + o.Expect(out).NotTo(o.ContainSubstring("stdin")) + o.Expect(out).NotTo(o.ContainSubstring("tty")) + + out, err = oc.Run("debug").Args("dc/test-deployment-config", "--node-name=invalid", "--", "/bin/env").Output() + o.Expect(err).To(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring(`on node "invalid"`)) }) - g.It("should print the overridden imagestream-based container entrypoint/command", func() { - out, err := oc.Run("debug").Args("dc/local-busybox2").Output() + g.It("does not require a real resource on the server", func() { + out, err := oc.Run("debug").Args("-T", "-f", helloPod, "-oyaml").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).NotTo(o.ContainSubstring("tty")) + + err = oc.Run("debug").Args("-f", helloPod, "--keep-liveness", "--keep-readiness", "-oyaml").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + out, err = oc.Run("debug").Args("-f", helloPod, "-oyaml", "--", "/bin/env").Output() o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(out).To(o.ContainSubstring("Debugging with pod/local-busybox2-debug, original command: foo bar baz qux\n")) + o.Expect(out).To(o.ContainSubstring("- /bin/env")) + o.Expect(out).NotTo(o.ContainSubstring("stdin")) + o.Expect(out).NotTo(o.ContainSubstring("tty")) }) - g.It("should print the container image-based container entrypoint/command", func() { - out, err := oc.Run("debug").Args("dc/busybox1").Output() + // TODO: write a test that emulates a TTY to verify the correct defaulting of what the pod is created + + g.It("ensure debug does not depend on a container actually existing for the selected resource", func() { + err := oc.Run("create").Args("-f", testReplicationController).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = oc.Run("create").Args("-f", testDeploymentConfig).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + // The command should not hang waiting for an attachable pod. Timeout each cmd after 10s. + err = oc.Run("scale").Args("--replicas=0", "rc/test-replication-controller").Execute() o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(out).To(o.ContainSubstring("Debugging with pod/busybox1-debug, original command: sh\n")) + + var out string + out, err = oc.Run("debug").Args("--request-timeout=10s", "-c", "ruby-helloworld", "--one-container", "rc/test-replication-controller", "-o", "jsonpath='{.metadata.name}").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("test-replication-controller-debug")) + + err = oc.Run("scale").Args("--replicas=0", "dc/test-deployment-config").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + out, err = oc.Run("debug").Args("--request-timeout=10s", "-c", "ruby-helloworld", "--one-container", "dc/test-deployment-config", "-o", "jsonpath='{.metadata.name}").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("test-deployment-config")) + + err = oc.Run("create").Args("-f", "-").InputString(` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: test-deployment + labels: + deployment: test-deployment +spec: + replicas: 0 + selector: + matchLabels: + deployment: test-deployment + template: + metadata: + labels: + deployment: test-deployment + name: test-deployment + spec: + containers: + - name: ruby-helloworld + image: openshift/origin-pod + imagePullPolicy: IfNotPresent +`).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + out, err = oc.Run("debug").Args("--request-timeout=10s", "-c", "ruby-helloworld", "--one-container", "deploy/test-deployment", "-o", "jsonpath='{.metadata.name}").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("test-deployment-debug")) }) - g.It("should print the overridden container image-based container entrypoint/command", func() { - out, err := oc.Run("debug").Args("dc/busybox2").Output() + g.It("ensure it works with image streams", func() { + err := oc.Run("create").Args("-f", imageStreamsCentos).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + err = wait.Poll(cliInterval, cliTimeout, func() (bool, error) { + err := oc.Run("get").Args("imagestreamtags", "wildfly:latest").Execute() + return err == nil, nil + }) + o.Expect(err).NotTo(o.HaveOccurred()) + + var out string + out, err = oc.Run("debug").Args("istag/wildfly:latest", "-o", "yaml").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.MatchRegexp("image:.*oc-debug-.*/wildfly@sha256")) + + var sha string + sha, err = oc.Run("get").Args("istag/wildfly:latest", "--template", "{{ .image.metadata.name }}").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + out, err = oc.Run("debug").Args(fmt.Sprintf("isimage/wildfly@%s", sha), "-o", "yaml").Output() o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(out).To(o.ContainSubstring("Debugging with pod/busybox2-debug, original command: foo bar baz qux\n")) + o.Expect(out).To(o.ContainSubstring("image: quay.io/wildfly/wildfly-centos7")) }) }) diff --git a/test/extended/cli/mustgather.go b/test/extended/cli/mustgather.go index 55fd237f333a..c872add17458 100644 --- a/test/extended/cli/mustgather.go +++ b/test/extended/cli/mustgather.go @@ -28,6 +28,7 @@ import ( var _ = g.Describe("[sig-cli] oc adm must-gather", func() { defer g.GinkgoRecover() + oc := exutil.NewCLI("oc-adm-must-gather").AsAdmin() g.JustBeforeEach(func() { diff --git a/test/extended/cli/timeout.go b/test/extended/cli/timeout.go new file mode 100644 index 000000000000..c9bac637a59c --- /dev/null +++ b/test/extended/cli/timeout.go @@ -0,0 +1,38 @@ +package cli + +import ( + g "github.com/onsi/ginkgo" + o "github.com/onsi/gomega" + + exutil "github.com/openshift/origin/test/extended/util" +) + +var _ = g.Describe("[sig-cli] oc --request-timeout", func() { + defer g.GinkgoRecover() + + oc := exutil.NewCLI("oc-request-timeout") + + g.It("works as expected", func() { + err := oc.Run("create").Args("deploymentconfig", "testdc", "--image=busybox").Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + out, err := oc.Run("get", "dc/testdc").Args("-w", "-v=5", "--request-timeout=1s").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + // timeout is set for both the request and on context in request + // seek8s.io/client-go/rest/request.go#request so if we get timeout + // from server or from context it's ok + o.Expect(out).Should(o.SatisfyAny(o.ContainSubstring("request canceled"), o.ContainSubstring("context deadline exceeded"))) + + out, err = oc.Run("get", "dc/testdc").Args("--request-timeout=1s").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("testdc")) + + out, err = oc.Run("get", "dc/testdc").Args("--request-timeout=1").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).To(o.ContainSubstring("testdc")) + + out, err = oc.Run("get", "pods").Args("--watch", "-v=5", "--request-timeout=1s").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + o.Expect(out).Should(o.SatisfyAny(o.ContainSubstring("request canceled"), o.ContainSubstring("context deadline exceeded"))) + }) +}) diff --git a/test/extended/cmd.sh b/test/extended/cmd.sh index a0e7a6da783d..82609ff95a1b 100755 --- a/test/extended/cmd.sh +++ b/test/extended/cmd.sh @@ -161,7 +161,7 @@ os::cmd::expect_success "oc set volumes dc/nginx --add --configmap-name=default- os::cmd::try_until_text "oc get pods -l deployment-config.name=nginx" 'Running' # only show single pods in status if they are really single -os::cmd::expect_success 'oc create -f test/integration/testdata/test-deployment-config.yaml' +os::cmd::expect_success 'oc create -f test/extended/testdata/test-deployment-config.yaml' os::cmd::try_until_text 'oc status' 'dc\/test-deployment-config deploys docker\.io\/openshift\/origin-pod:latest' "$(( 2 * TIME_MIN ))" os::cmd::try_until_text 'oc status' 'deployment #1 deployed.*- 1 pod' "$(( 2 * TIME_MIN ))" os::cmd::expect_success_and_not_text 'oc status' 'pod\/test-deployment-config-1-[0-9a-z]{5} runs openshift\/origin-pod' @@ -181,7 +181,7 @@ os::cmd::try_until_text "oc get pods/kube-apiserver -o 'jsonpath={.status.condit os::cmd::try_until_text "oc get pods/kube-apiserver -o 'jsonpath={.status.podIP}'" "172" kube_ip="$(oc get pods/kube-apiserver -o 'jsonpath={.status.podIP}')" kube_kubectl="${tmp}/kube-kubeconfig" -os::cmd::try_until_text "oc login --config ${kube_kubectl}../kube-kubeconfig https://${kube_ip}:443 --token=secret --insecure-skip-tls-verify=true --loglevel=8" ' as "secret" using the token provided.' +os::cmd::try_until_text "oc login --kubeconfig ${kube_kubectl}../kube-kubeconfig https://${kube_ip}:443 --token=secret --insecure-skip-tls-verify=true --loglevel=8" ' as "secret" using the token provided.' os::test::junit::declare_suite_end os::test::junit::declare_suite_end diff --git a/test/extended/csi/install.go b/test/extended/csi/install.go deleted file mode 100644 index 5233a2fcc4ae..000000000000 --- a/test/extended/csi/install.go +++ /dev/null @@ -1,112 +0,0 @@ -package csi - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strings" - "text/template" - - "github.com/openshift/origin/test/extended/testdata" - exutil "github.com/openshift/origin/test/extended/util" -) - -const ( - csiBasePath = "test/extended/testdata/csi" - defaultImageFormat = "registry.svc.ci.openshift.org/origin/4.5:${component}" - imageFormatVariable = "IMAGE_FORMAT" -) - -// InstallCSIDriver installs a CSI driver and defines its tests. -// It applies "test/extended/csi//install-template.yaml" and -// returns path to test manifest "test/extended/csi//manifest.yaml" -func InstallCSIDriver(driverName string, dryRun bool) (string, error) { - // The driver name comes from an user and we want a nice error message instead - // of panic in FixturePath(). - templatePath := filepath.Join(csiBasePath, driverName, "install-template.yaml") - if _, err := testdata.AssetInfo(templatePath); err != nil { - return "", fmt.Errorf("failed to install CSI driver %q: %s", driverName, err) - } - - manifestPath := filepath.Join(csiBasePath, driverName, "manifest.yaml") - if _, err := testdata.AssetInfo(manifestPath); err != nil { - return "", fmt.Errorf("failed to install CSI driver %q: %s", driverName, err) - } - - // storageclass.yaml is optional, so we don't return and error if it's absent - scPath := filepath.Join(csiBasePath, driverName, "storageclass.yaml") - if _, err := testdata.AssetInfo(scPath); err == nil { - scFixturePath := strings.Split(scPath, string(os.PathSeparator))[2:] - exutil.FixturePath(scFixturePath...) - } - - // Convert to array and cut "test/extended" for FixturePath() - templateFixturePath := strings.Split(templatePath, string(os.PathSeparator))[2:] - yamlPath, err := executeTemplate(exutil.FixturePath(templateFixturePath...)) - defer os.Remove(yamlPath) - if err != nil { - return "", err - } - - if !dryRun { - // Install the driver - oc := exutil.NewCLIWithoutNamespace("csi-install") - if err := oc.Run("apply").Args("-f", yamlPath).Execute(); err != nil { - return "", fmt.Errorf("failed to apply %s: %s", yamlPath, err) - } - } - - // Cut "test/extended" for FixturePath() - manifestFixturePath := strings.Split(manifestPath, string(os.PathSeparator))[2:] - return exutil.FixturePath(manifestFixturePath...), nil -} - -// ListCSIDrivers returns list of hardcoded CSI drivers, i.e. list of directories in "test/extended/csi". -func ListCSIDrivers() ([]string, error) { - return testdata.AssetDir(csiBasePath) -} - -// Executes given golang template file and returns path to resulting file. -func executeTemplate(templatePath string) (string, error) { - tmpl, err := template.ParseFiles(templatePath) - if err != nil { - return "", err - } - yamlFile, err := ioutil.TempFile("", "openshift-tests-csi-*") - if err != nil { - return "", err - } - yamlPath := yamlFile.Name() - - imageFormat := os.Getenv(imageFormatVariable) - if imageFormat == "" { - imageFormat = defaultImageFormat - } - - variables := struct { - AttacherImage string - ProvisionerImage string - ResizerImage string - SnapshotterImage string - NodeDriverRegistrarImage string - LivenessProbeImage string - ImageFormat string - }{ - AttacherImage: strings.ReplaceAll(imageFormat, "${component}", "csi-external-attacher"), - ProvisionerImage: strings.ReplaceAll(imageFormat, "${component}", "csi-external-provisioner"), - ResizerImage: strings.ReplaceAll(imageFormat, "${component}", "csi-external-resizer"), - SnapshotterImage: strings.ReplaceAll(imageFormat, "${component}", "csi-external-snapshotter"), - NodeDriverRegistrarImage: strings.ReplaceAll(imageFormat, "${component}", "csi-node-driver-registrar"), - LivenessProbeImage: strings.ReplaceAll(imageFormat, "${component}", "csi-livenessprobe"), - ImageFormat: imageFormat, - } - - err = tmpl.Execute(yamlFile, variables) - yamlFile.Close() - if err != nil { - os.Remove(yamlPath) - return "", err - } - return yamlPath, nil -} diff --git a/test/extended/csrapprover/csrapprover.go b/test/extended/csrapprover/csrapprover.go index e0b2c2937fe8..b11de4882b94 100644 --- a/test/extended/csrapprover/csrapprover.go +++ b/test/extended/csrapprover/csrapprover.go @@ -29,6 +29,7 @@ import ( exutil "github.com/openshift/origin/test/extended/util" "github.com/openshift/origin/test/extended/util/ibmcloud" + "github.com/openshift/origin/test/extended/util/image" ) var _ = g.Describe("[sig-cluster-lifecycle]", func() { @@ -45,7 +46,7 @@ var _ = g.Describe("[sig-cluster-lifecycle]", func() { // the /config/master API port+endpoint is only visible from inside the cluster // (-> we need to create a pod to try to reach it) and contains the token // of the node-bootstrapper SA, so no random pods should be able to see it - pod, err := exutil.NewPodExecutor(oc, "get-bootstrap-creds", "docker.io/fedora:32") + pod, err := exutil.NewPodExecutor(oc, "get-bootstrap-creds", image.ShellImage()) o.Expect(err).NotTo(o.HaveOccurred()) // get the API server URL, mutate to internal API (use infra.Status.APIServerURLInternal) once API is bumped diff --git a/test/extended/deployments/deployments.go b/test/extended/deployments/deployments.go index 4a77596ccb55..0bdcb5e7f3bc 100644 --- a/test/extended/deployments/deployments.go +++ b/test/extended/deployments/deployments.go @@ -31,6 +31,7 @@ import ( "github.com/openshift/library-go/pkg/image/imageutil" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" ) const deploymentRunTimeout = 5 * time.Minute @@ -424,8 +425,8 @@ var _ = g.Describe("[sig-apps][Feature:DeploymentConfig] deploymentconfigs", fun o.Expect(dc.Name).To(o.Equal(dcName)) o.Expect(waitForSyncedConfig(oc, dcName, deploymentRunTimeout)).NotTo(o.HaveOccurred()) - g.By("tagging the ubi-minimal:latest as test:v1 image") - _, err = oc.Run("tag").Args("registry.access.redhat.com/ubi8/ubi-minimal:latest", "test:v1").Output() + g.By("tagging the initial test:v1 image") + _, err = oc.Run("tag").Args("image-registry.openshift-image-registry.svc:5000/openshift/cli:latest", "test:v1").Output() o.Expect(err).NotTo(o.HaveOccurred()) expectLatestVersion := func(version int) { @@ -455,8 +456,8 @@ var _ = g.Describe("[sig-apps][Feature:DeploymentConfig] deploymentconfigs", fun o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(waitForSyncedConfig(oc, dcName, deploymentRunTimeout)).NotTo(o.HaveOccurred()) - g.By("tagging the ubi-minimal:8.0-127 as test:v2 image") - _, err = oc.Run("tag").Args("registry.access.redhat.com/ubi8/ubi-minimal:8.0-127", "test:v2").Output() + g.By("tagging a different image as test:v2") + _, err = oc.Run("tag").Args("image-registry.openshift-image-registry.svc:5000/openshift/tools:latest", "test:v2").Output() o.Expect(err).NotTo(o.HaveOccurred()) g.By("ensuring the deployment config latest version is 2 and rollout completed") @@ -502,8 +503,8 @@ var _ = g.Describe("[sig-apps][Feature:DeploymentConfig] deploymentconfigs", fun } o.Expect(pollErr).NotTo(o.HaveOccurred()) - if istag.Tag == nil || istag.Tag.From == nil || istag.Tag.From.Name != "openshift/origin-pod" { - err = fmt.Errorf("expected %q to be part of the image reference in %#v", "openshift/origin-pod", istag) + if istag.Tag == nil || istag.Tag.From == nil || istag.Tag.From.Name != image.ShellImage() { + err = fmt.Errorf("expected %q to be part of the image reference in %#v", image.ShellImage(), istag) o.Expect(err).NotTo(o.HaveOccurred()) } }) @@ -1520,8 +1521,8 @@ var _ = g.Describe("[sig-apps][Feature:DeploymentConfig] deploymentconfigs", fun dc, err = oc.AppsClient().AppsV1().DeploymentConfigs(namespace).Create(context.Background(), dc, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - g.By("tagging the ubi-minimal:latest as test:v1 image to create ImageStream") - out, err := oc.Run("tag").Args("registry.access.redhat.com/ubi8/ubi-minimal:latest", "test:v1").Output() + g.By("tagging the tools image as test:v1 to create ImageStream") + out, err := oc.Run("tag").Args("image-registry.openshift-image-registry.svc:5000/openshift/tools:latest", "test:v1").Output() e2e.Logf("%s", out) o.Expect(err).NotTo(o.HaveOccurred()) diff --git a/test/extended/dr/common.go b/test/extended/dr/common.go index 7d68379aa381..ed051430188b 100644 --- a/test/extended/dr/common.go +++ b/test/extended/dr/common.go @@ -25,7 +25,8 @@ import ( ) const ( - operatorWait = 15 * time.Minute + operatorWait = 15 * time.Minute + defaultSSHTimeout = 5 * time.Minute ) func runCommandAndRetry(command string) string { @@ -196,50 +197,6 @@ func restartSDNPods(oc *exutil.CLI) { o.Expect(err).NotTo(o.HaveOccurred()) } -func restartOpenshiftAPIPods(oc *exutil.CLI) { - e2elog.Logf("Restarting Openshift API server") - - pods, err := oc.AdminKubeClient().CoreV1().Pods("openshift-apiserver").List(context.Background(), metav1.ListOptions{}) - o.Expect(err).NotTo(o.HaveOccurred()) - - for _, pod := range pods.Items { - e2elog.Logf("Deleting pod %s", pod.Name) - err := oc.AdminKubeClient().CoreV1().Pods("openshift-apiserver").Delete(context.Background(), pod.Name, metav1.DeleteOptions{}) - o.Expect(err).NotTo(o.HaveOccurred()) - } - - err = wait.Poll(10*time.Second, 5*time.Minute, func() (done bool, err error) { - apiServerDS, err := oc.AdminKubeClient().AppsV1().DaemonSets("openshift-apiserver").Get(context.Background(), "apiserver", metav1.GetOptions{}) - if err != nil { - return false, nil - } - return apiServerDS.Status.NumberReady == apiServerDS.Status.NumberAvailable, nil - }) - o.Expect(err).NotTo(o.HaveOccurred()) -} - -func restartMCDPods(oc *exutil.CLI) { - e2elog.Logf("Restarting MCD pods") - - pods, err := oc.AdminKubeClient().CoreV1().Pods("openshift-machine-config-operator").List(context.Background(), metav1.ListOptions{}) - o.Expect(err).NotTo(o.HaveOccurred()) - - for _, pod := range pods.Items { - e2elog.Logf("Deleting pod %s", pod.Name) - err := oc.AdminKubeClient().CoreV1().Pods("openshift-machine-config-operator").Delete(context.Background(), pod.Name, metav1.DeleteOptions{}) - o.Expect(err).NotTo(o.HaveOccurred()) - } - - err = wait.Poll(10*time.Second, 5*time.Minute, func() (done bool, err error) { - mcDS, err := oc.AdminKubeClient().AppsV1().DaemonSets("openshift-machine-config-operator").Get(context.Background(), "machine-config-daemon", metav1.GetOptions{}) - if err != nil { - return false, nil - } - return mcDS.Status.NumberReady == mcDS.Status.NumberAvailable, nil - }) - o.Expect(err).NotTo(o.HaveOccurred()) -} - func objects(from *objx.Value) []objx.Map { var values []objx.Map switch { @@ -285,21 +242,42 @@ func countReady(items []corev1.Node) int { func fetchFileContents(node *corev1.Node, path string) string { e2elog.Logf("Fetching %s file contents from %s", path, node.Name) - out, err := ssh(fmt.Sprintf("cat %q", path), node) - o.Expect(err).NotTo(o.HaveOccurred()) - if len(out.Stderr) > 0 { - e2elog.Logf("file content stderr:\n%s", out.Stderr) - } + out := execOnNodeWithOutputOrFail(node, fmt.Sprintf("cat %q", path)) return out.Stdout } -func expectSSH(cmd string, node *corev1.Node) { - e2elog.Logf("cmd[%s]: %s", node.Name, cmd) - out, err := e2essh.IssueSSHCommandWithResult(cmd, e2e.TestContext.Provider, node) - o.Expect(err).NotTo(o.HaveOccurred()) - if len(out.Stderr) > 0 { - e2elog.Logf("command %q stderr:\n%s", cmd, out.Stderr) - } +// execOnNodeWithOutputOrFail executes a command via ssh against a +// node in a poll loop to ensure reliable execution in a disrupted +// environment. The calling test will be failed if the command cannot +// be executed successfully before the provided timeout. +func execOnNodeWithOutputOrFail(node *corev1.Node, cmd string) *e2essh.Result { + var out *e2essh.Result + var err error + waitErr := wait.PollImmediate(5*time.Second, defaultSSHTimeout, func() (bool, error) { + out, err = e2essh.IssueSSHCommandWithResult(cmd, e2e.TestContext.Provider, node) + // IssueSSHCommandWithResult logs output + if err != nil { + e2elog.Logf("Failed to exec cmd [%s] on node %s: %v", cmd, node.Name, err) + } + return err == nil, nil + }) + o.Expect(waitErr).NotTo(o.HaveOccurred()) + return out +} + +// execOnNodeOrFail executes a command via ssh against a node in a +// poll loop until success or timeout. The output is ignored. The +// calling test will be failed if the command cannot be executed +// successfully before the timeout. +func execOnNodeOrFail(node *corev1.Node, cmd string) { + _ = execOnNodeWithOutputOrFail(node, cmd) +} + +// checkSSH repeatedly attempts to establish an ssh connection to a +// node and fails the calling test if unable to establish the +// connection before the default timeout. +func checkSSH(node *corev1.Node) { + _ = execOnNodeWithOutputOrFail(node, "true") } func ssh(cmd string, node *corev1.Node) (*e2essh.Result, error) { diff --git a/test/extended/dr/machine_recover.go b/test/extended/dr/machine_recover.go index a2811cb6ca00..8e034073f7cc 100644 --- a/test/extended/dr/machine_recover.go +++ b/test/extended/dr/machine_recover.go @@ -52,18 +52,18 @@ var _ = g.Describe("[sig-cluster-lifecycle][Feature:DisasterRecovery][Disruptive o.Expect(len(workers)).To(o.BeNumerically(">=", 2)) replacedMaster := masters[rand.Intn(len(masters))] - expectSSH("true", replacedMaster) + checkSSH(replacedMaster) replacedWorker := workers[rand.Intn(len(workers))] - expectSSH("true", replacedWorker) + checkSSH(replacedWorker) disruption.Run(f, "Machine Shutdown and Restore", "machine_failure", disruption.TestData{}, []upgrades.Test{ &upgrades.ServiceUpgradeTest{}, - controlplane.NewKubeAvailableTest(), - controlplane.NewOpenShiftAvailableTest(), - controlplane.NewOAuthAvailableTest(), + controlplane.NewKubeAvailableWithNewConnectionsTest(), + controlplane.NewOpenShiftAvailableNewConnectionsTest(), + controlplane.NewOAuthAvailableNewConnectionsTest(), &frontends.AvailableTest{}, }, func() { diff --git a/test/extended/dr/quorum_restore.go b/test/extended/dr/quorum_restore.go index 43db457eab6a..2bd29fe0ba61 100644 --- a/test/extended/dr/quorum_restore.go +++ b/test/extended/dr/quorum_restore.go @@ -94,7 +94,7 @@ var _ = g.Describe("[sig-etcd][Feature:DisasterRecovery][Disruptive]", func() { o.Expect(len(masters)).To(o.BeNumerically(">=", 1)) survivingNode := masters[rand.Intn(len(masters))] survivingNodeName := survivingNode.Name - expectSSH("true", survivingNode) + checkSSH(survivingNode) err = scaleEtcdQuorum(oc.AdminKubeClient(), 0) o.Expect(err).NotTo(o.HaveOccurred()) @@ -129,6 +129,7 @@ var _ = g.Describe("[sig-etcd][Feature:DisasterRecovery][Disruptive]", func() { err = wait.Poll(5*time.Second, 30*time.Minute, func() (done bool, err error) { _, err = pollClient.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) if err != nil { + framework.Logf("Error seen checking for unresponsive control plane: %v", err) failures++ } else { failures = 0 @@ -137,7 +138,9 @@ var _ = g.Describe("[sig-etcd][Feature:DisasterRecovery][Disruptive]", func() { // there is a small chance the cluster restores the default replica size during // this loop process, so keep forcing quorum guard to be zero, without failing on // errors - scaleEtcdQuorum(pollClient, 0) + if err := scaleEtcdQuorum(pollClient, 0); err != nil { + framework.Logf("Scaling etcd quorum failed: %v", err) + } // wait to see the control plane go down for good to avoid a transient failure return failures > 4, nil @@ -145,9 +148,11 @@ var _ = g.Describe("[sig-etcd][Feature:DisasterRecovery][Disruptive]", func() { } framework.Logf("Perform etcd backup on remaining machine %s (machine %s)", survivingNodeName, survivingMachineName) - expectSSH("sudo -i /bin/bash -cx 'rm -rf /home/core/backup; /usr/local/bin/cluster-backup.sh ~core/backup'", survivingNode) + // Need to supply --force to the backup script to avoid failing on the api check for progressing operators. + execOnNodeOrFail(survivingNode, "sudo -i /bin/bash -cx 'rm -rf /home/core/backup; /usr/local/bin/cluster-backup.sh --force ~core/backup'") + framework.Logf("Restore etcd and control-plane on remaining node %s (machine %s)", survivingNodeName, survivingMachineName) - expectSSH("sudo -i /bin/bash -cx '/usr/local/bin/cluster-restore.sh /home/core/backup'", survivingNode) + execOnNodeOrFail(survivingNode, "sudo -i /bin/bash -cx '/usr/local/bin/cluster-restore.sh /home/core/backup'") framework.Logf("Wait for API server to come up") time.Sleep(30 * time.Second) @@ -188,7 +193,8 @@ var _ = g.Describe("[sig-etcd][Feature:DisasterRecovery][Disruptive]", func() { return false, nil } if err != nil { - return false, err + framework.Logf("Error seen when re-creating machines: %v", err) + return false, nil } return true, nil }) @@ -196,12 +202,13 @@ var _ = g.Describe("[sig-etcd][Feature:DisasterRecovery][Disruptive]", func() { } framework.Logf("Waiting for machines to be created") - err = wait.Poll(30*time.Second, 10*time.Minute, func() (done bool, err error) { + err = wait.Poll(30*time.Second, 20*time.Minute, func() (done bool, err error) { mastersList, err := ms.List(context.Background(), metav1.ListOptions{ LabelSelector: "machine.openshift.io/cluster-api-machine-role=master", }) if err != nil { - return false, err + framework.Logf("Failed to check that machines are created: %v", err) + return false, nil } if mastersList.Items == nil { return false, nil @@ -220,6 +227,7 @@ var _ = g.Describe("[sig-etcd][Feature:DisasterRecovery][Disruptive]", func() { nodes, err := oc.AdminKubeClient().CoreV1().Nodes().List(context.Background(), metav1.ListOptions{LabelSelector: "node-role.kubernetes.io/master="}) if err != nil { // scale up to 2nd etcd will make this error inevitable + framework.Logf("Error seen attempting to list master nodes: %v", err) return false, nil } ready := countReady(nodes.Items) @@ -264,9 +272,10 @@ var _ = g.Describe("[sig-etcd][Feature:DisasterRecovery][Disruptive]", func() { func waitForPodsTolerateClientTimeout(c corev1client.PodInterface, label labels.Selector, predicate func(corev1.Pod) bool, count int, timeout time.Duration) ([]string, error) { var podNames []string - err := wait.Poll(1*time.Second, timeout, func() (bool, error) { + err := wait.Poll(10*time.Second, timeout, func() (bool, error) { p, e := exutil.GetPodNamesByFilter(c, label, predicate) if e != nil { + framework.Logf("Saw an error waiting for etcd pods to become available: %v", e) // TODO tolerate transient etcd timeout only and fail other errors return false, nil } diff --git a/test/extended/dr/restore_from_snapshot.go b/test/extended/dr/restore_from_snapshot.go deleted file mode 100644 index 3cf289e21785..000000000000 --- a/test/extended/dr/restore_from_snapshot.go +++ /dev/null @@ -1,135 +0,0 @@ -package dr - -import ( - "context" - "fmt" - "os" - "strings" - "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/dynamic" - e2e "k8s.io/kubernetes/test/e2e/framework" - - exutil "github.com/openshift/origin/test/extended/util" - - g "github.com/onsi/ginkgo" - o "github.com/onsi/gomega" -) - -const ( - rollBackMachineConfig = "99-rollback-test" -) - -var _ = g.Describe("[sig-etcd][Feature:DisasterRecovery][Disruptive]", func() { - f := e2e.NewDefaultFramework("disaster-recovery") - f.SkipNamespaceCreation = true - f.SkipPrivilegedPSPBinding = true - - oc := exutil.NewCLIWithoutNamespace("disaster-recovery") - - g.It("[dr-etcd-snapshot] Cluster should restore itself from etcd snapshot", func() { - config, err := e2e.LoadConfig() - o.Expect(err).NotTo(o.HaveOccurred()) - dynamicClient := dynamic.NewForConfigOrDie(config) - mcps := dynamicClient.Resource(schema.GroupVersionResource{ - Group: "machineconfiguration.openshift.io", - Version: "v1", - Resource: "machineconfigpools", - }) - mc := dynamicClient.Resource(schema.GroupVersionResource{ - Group: "machineconfiguration.openshift.io", - Version: "v1", - Resource: "machineconfigs", - }) - coc := dynamicClient.Resource(schema.GroupVersionResource{ - Group: "config.openshift.io", - Version: "v1", - Resource: "clusteroperators", - }) - - setMachineConfig("rollback-A.yaml", oc, mcps) - - masters := masterNodes(oc) - masterNames := sets.NewString() - for _, node := range masters { - masterNames.Insert(node.Name) - } - - e2e.Logf("masters: %v", masters) - o.Expect(masters).NotTo(o.BeEmpty()) - firstMaster := masters[0] - e2e.Logf("first master: %v", firstMaster) - - e2e.Logf("Make etcd backup on first master") - expectSSH("sudo -i /bin/bash -x /usr/local/bin/etcd-snapshot-backup.sh /root/assets/backup", firstMaster) - expectSSH("sudo -i /bin/bash -c '/bin/tar -xzf /root/assets/backup/snapshot* -C /root/assets/backup snapshot.db'", firstMaster) - expectSSH("sudo -i install -o core -g core /root/assets/backup/snapshot.db /tmp/snapshot.db", firstMaster) - - setMachineConfig("rollback-B.yaml", oc, mcps) - - masterHosts := strings.Join(masterNames.List(), " ") - restoreScriptPath := exutil.FixturePath("testdata", "disaster-recovery", "restore-etcd.sh") - cmd := fmt.Sprintf("env BASTION_HOST= MASTERHOSTS='%s' KUBE_SSH_KEY_PATH='%s' /bin/bash -x %s ", masterHosts, os.Getenv("KUBE_SSH_KEY_PATH"), restoreScriptPath) - runCommandAndRetry(cmd) - - time.Sleep(30 * time.Second) - waitForAPIServer(oc) - // restartSDNPods(oc) - restartOpenshiftAPIPods(oc) - restartMCDPods(oc) - waitForMastersToUpdate(oc, mcps) - waitForOperatorsToSettle(coc) - - rollBackInMC := getRollbackContentsInMachineConfig(oc, mc, rollBackMachineConfig) - o.Expect(rollBackInMC).To(o.BeEquivalentTo("data:,A")) - - for _, master := range masters { - rollBackFile := fetchFileContents(master, "/etc/rollback-test") - o.Expect(rollBackFile).To(o.BeEquivalentTo("A")) - } - }) -}) - -func setMachineConfig(rollbackFileName string, oc *exutil.CLI, mcps dynamic.NamespaceableResourceInterface) { - e2e.Logf("Update MachineConfig using %s file on masters", rollbackFileName) - machineConfigTemplate := exutil.FixturePath("testdata", "disaster-recovery", rollbackFileName) - err := oc.Run("apply").Args("-f", machineConfigTemplate).Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - - waitForMastersToUpdate(oc, mcps) -} - -func getRollbackContentsInMachineConfig(oc *exutil.CLI, mcs dynamic.NamespaceableResourceInterface, mcName string) string { - e2e.Logf("Reading contents of rollback MachineConfig") - pool, err := mcs.Get(context.Background(), mcName, metav1.GetOptions{}) - o.Expect(err).NotTo(o.HaveOccurred()) - - files, found, err := unstructured.NestedSlice(pool.Object, "spec", "config", "storage", "files") - o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(found).To(o.BeTrue()) - o.Expect(files).NotTo(o.BeEmpty()) - - file := files[0].(map[string]interface{}) - actual, found, err := unstructured.NestedString(file, "contents", "source") - o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(found).To(o.BeTrue()) - - return actual -} - -func waitForAPIServer(oc *exutil.CLI) { - e2e.Logf("Waiting for API server to restore") - err := wait.Poll(10*time.Second, 5*time.Minute, func() (done bool, err error) { - _, err = oc.AdminKubeClient().CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) - if err != nil { - return false, nil - } - return true, nil - }) - o.Expect(err).NotTo(o.HaveOccurred()) -} diff --git a/test/extended/etcd/etcd_storage_path.go b/test/extended/etcd/etcd_storage_path.go index d9c3004d9643..dcc5a3459a16 100644 --- a/test/extended/etcd/etcd_storage_path.go +++ b/test/extended/etcd/etcd_storage_path.go @@ -73,7 +73,7 @@ var OpenshiftEtcdStorageData = map[schema.GroupVersionResource]etcddata.StorageD // github.com/openshift/api/apps/v1 gvr("apps.openshift.io", "v1", "deploymentconfigs"): { - Stub: `{"metadata": {"name": "dc1g"}, "spec": {"selector": {"d": "c"}, "template": {"metadata": {"labels": {"d": "c"}}, "spec": {"containers": [{"image": "fedora:latest", "name": "container2"}]}}}}`, + Stub: `{"metadata": {"name": "dc1g"}, "spec": {"selector": {"d": "c"}, "template": {"metadata": {"labels": {"d": "c"}}, "spec": {"containers": [{"image": "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest", "name": "container2"}]}}}}`, ExpectedEtcdPath: "openshift.io/deploymentconfigs/etcdstoragepathtestnamespace/dc1g", }, // -- @@ -84,7 +84,7 @@ var OpenshiftEtcdStorageData = map[schema.GroupVersionResource]etcddata.StorageD ExpectedEtcdPath: "openshift.io/imagestreams/etcdstoragepathtestnamespace/is1g", }, gvr("image.openshift.io", "v1", "images"): { - Stub: `{"dockerImageReference": "fedora:latest", "metadata": {"name": "image1g"}}`, + Stub: `{"dockerImageReference": "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest", "metadata": {"name": "image1g"}}`, ExpectedEtcdPath: "openshift.io/images/image1g", }, // -- diff --git a/test/extended/etcd/etcd_test_runner.go b/test/extended/etcd/etcd_test_runner.go index 36dd0911af47..80d36fbe07b4 100644 --- a/test/extended/etcd/etcd_test_runner.go +++ b/test/extended/etcd/etcd_test_runner.go @@ -36,7 +36,7 @@ var _ = g.Describe("[sig-api-machinery] API data in etcd", func() { etcdClientCreater := &etcdPortForwardClient{kubeClient: oc.AdminKubeClient()} defer etcdClientCreater.closeAll() - testEtcd3StoragePath(g.GinkgoT(), oc.AdminConfig(), etcdClientCreater.getEtcdClient) + testEtcd3StoragePath(g.GinkgoT(2), oc.AdminConfig(), etcdClientCreater.getEtcdClient) }) }) diff --git a/test/extended/etcd/leader_changes.go b/test/extended/etcd/leader_changes.go index 8c86b3d79001..3ac0e53acca3 100644 --- a/test/extended/etcd/leader_changes.go +++ b/test/extended/etcd/leader_changes.go @@ -15,16 +15,20 @@ import ( var _ = g.Describe("[sig-etcd] etcd", func() { defer g.GinkgoRecover() - oc := exutil.NewCLI("etcd-leader-change").AsAdmin() - g.It("leader changes are not excessive", func() { + oc := exutil.NewCLIWithoutNamespace("etcd-leader-change").AsAdmin() + g.It("leader changes are not excessive [Late]", func() { prometheus, err := client.NewE2EPrometheusRouterClient(oc) o.Expect(err).ToNot(o.HaveOccurred()) - g.By("Examining the rate of increase in the number of etcd leadership changes for last five minutes") - result, _, err := prometheus.Query(context.Background(), "increase((max by (job) (etcd_server_leader_changes_seen_total) or 0*absent(etcd_server_leader_changes_seen_total))[15m:1m])", time.Now()) + + // we only consider series sent since the beginning of the test + testDuration := exutil.DurationSinceStartInSeconds().String() + + g.By("Examining the number of etcd leadership changes over the run") + result, _, err := prometheus.Query(context.Background(), fmt.Sprintf("increase((max(max by (job) (etcd_server_leader_changes_seen_total)) or 0*absent(etcd_server_leader_changes_seen_total))[%s:15s])", testDuration), time.Now()) o.Expect(err).ToNot(o.HaveOccurred()) - leaderChangeLastFiveMinutes := result.(model.Vector)[0].Value - if leaderChangeLastFiveMinutes != 0 { - o.Expect(fmt.Errorf("Leader changes observed last 5m %q: Leader changes are a result of stopping the etcd leader process or from latency (disk or network), review etcd performance metrics", leaderChangeLastFiveMinutes)).ToNot(o.HaveOccurred()) + leaderChanges := result.(model.Vector)[0].Value + if leaderChanges != 0 { + o.Expect(fmt.Errorf("Observed %s leader changes in %s: Leader changes are a result of stopping the etcd leader process or from latency (disk or network), review etcd performance metrics", leaderChanges, testDuration)).ToNot(o.HaveOccurred()) } }) }) diff --git a/test/extended/image_ecosystem/sample_repos.go b/test/extended/image_ecosystem/sample_repos.go index db69d0d34423..6165b0439b44 100644 --- a/test/extended/image_ecosystem/sample_repos.go +++ b/test/extended/image_ecosystem/sample_repos.go @@ -79,7 +79,7 @@ func NewSampleRepoTest(c sampleRepoConfig) func() { o.Expect(err).NotTo(o.HaveOccurred()) g.By("expecting the db service is available") - serviceIP, err := oc.Run("get").Args("service", c.dbServiceName).Template("{{ .spec.clusterIP }}").Output() + serviceIP, err := oc.Run("get").Args("service", c.dbServiceName, "--output=template", "--template={{ .spec.clusterIP }}").Output() o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(serviceIP).ShouldNot(o.Equal("")) @@ -89,7 +89,7 @@ func NewSampleRepoTest(c sampleRepoConfig) func() { } g.By("expecting the app service is available") - serviceIP, err := oc.Run("get").Args("service", c.serviceName).Template("{{ .spec.clusterIP }}").Output() + serviceIP, err := oc.Run("get").Args("service", c.serviceName, "--output=template", "--template={{ .spec.clusterIP }}").Output() o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(serviceIP).ShouldNot(o.Equal("")) @@ -147,20 +147,19 @@ var _ = g.Describe("[sig-devex][Feature:ImageEcosystem][Slow] openshift sample a }, )) - // disable temporarily, to be replaced with a postgresql based example - /*g.Describe("[sig-devex][Feature:ImageEcosystem][nodejs] test nodejs images with nodejs-ex db repo", NewSampleRepoTest( + g.Describe("[sig-devex][Feature:ImageEcosystem][nodejs] test nodejs images with nodejs-rest-http-crud db repo", NewSampleRepoTest( sampleRepoConfig{ - repoName: "nodejs-mongodb", - templateURL: "nodejs-mongodb-example", - buildConfigName: "nodejs-mongodb-example", - serviceName: "nodejs-mongodb-example", - deploymentConfigName: "nodejs-mongodb-example", - expectedString: htmlCountValueNonZeroRegexp, + repoName: "nodejs-postgresql", + templateURL: "nodejs-postgresql-example", + buildConfigName: "nodejs-postgresql-example", + serviceName: "nodejs-postgresql-example", + deploymentConfigName: "nodejs-postgresql-example", + expectedString: "Fruit List", appPath: "", - dbDeploymentConfigName: "mongodb", - dbServiceName: "mongodb", + dbDeploymentConfigName: "postgresql", + dbServiceName: "postgresql", }, - ))*/ + )) var _ = g.Describe("[sig-devex][Feature:ImageEcosystem][php] test php images with cakephp-ex db repo", NewSampleRepoTest( sampleRepoConfig{ diff --git a/test/extended/images/append.go b/test/extended/images/append.go index 57276e314b85..9d3e2c84041d 100644 --- a/test/extended/images/append.go +++ b/test/extended/images/append.go @@ -15,6 +15,7 @@ import ( "github.com/openshift/library-go/pkg/image/imageutil" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" ) func cliPodWithPullSecret(cli *exutil.CLI, shell string) *kapiv1.Pod { @@ -23,8 +24,6 @@ func cliPodWithPullSecret(cli *exutil.CLI, shell string) *kapiv1.Pod { o.Expect(sa.ImagePullSecrets).NotTo(o.BeEmpty()) pullSecretName := sa.ImagePullSecrets[0].Name - cliImage, _ := exutil.FindCLIImage(cli) - return &kapiv1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: "append-test", @@ -36,7 +35,7 @@ func cliPodWithPullSecret(cli *exutil.CLI, shell string) *kapiv1.Pod { Containers: []kapiv1.Container{ { Name: "test", - Image: cliImage, + Image: image.ShellImage(), Command: []string{"/bin/bash", "-c", "set -euo pipefail; " + shell}, Env: []kapiv1.EnvVar{ { @@ -98,8 +97,8 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageAppend] Image append", func # create a second scratch image with fixed date oc image append --insecure --to %[2]s/%[1]s/test:scratch2 --image='{"Cmd":["/bin/sleep"]}' --created-at=0 - # modify a busybox image - oc image append --insecure --from docker.io/library/busybox:latest --to %[2]s/%[1]s/test:busybox1 --image '{"Cmd":["/bin/sleep"]}' + # modify a shell image + oc image append --insecure --from %[3]s --to %[2]s/%[1]s/test:busybox1 --image '{"Cmd":["/bin/sleep"]}' # verify mounting works oc create is test2 @@ -111,9 +110,17 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageAppend] Image append", func touch /tmp/test/dir/2 tar cvzf /tmp/layer.tar.gz -C /tmp/test/ . oc image append --insecure --from=%[2]s/%[1]s/test:busybox1 --to %[2]s/%[1]s/test:busybox2 /tmp/layer.tar.gz - `, ns, registry))) + `, ns, registry, image.ShellImage()))) cli.WaitForSuccess(pod.Name, podStartupTimeout) + // verify that the shell image matches our check - if the shell image changes, we'll need to look up a different image + o.Expect(image.ShellImage()).To(o.HaveSuffix("/openshift/tools:latest")) + baseTools, err := oc.ImageClient().ImageV1().ImageStreamTags("openshift").Get(context.Background(), "tools:latest", metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + // subsequent operations are expected to append to this image + baseLayerCount := len(baseTools.Image.DockerImageLayers) + o.Expect(baseLayerCount).To(o.BeNumerically(">=", 2)) + istag, err := oc.ImageClient().ImageV1().ImageStreamTags(ns).Get(context.Background(), "test:scratch1", metav1.GetOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(istag.Image).NotTo(o.BeNil()) @@ -135,7 +142,7 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageAppend] Image append", func o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(istag.Image).NotTo(o.BeNil()) imageutil.ImageWithMetadataOrDie(&istag.Image) - o.Expect(istag.Image.DockerImageLayers).To(o.HaveLen(1)) + o.Expect(istag.Image.DockerImageLayers).To(o.HaveLen(baseLayerCount)) o.Expect(istag.Image.DockerImageLayers[0].Name).NotTo(o.Equal(GzippedEmptyLayerDigest)) err = imageutil.ImageWithMetadata(&istag.Image) o.Expect(err).NotTo(o.HaveOccurred()) @@ -146,7 +153,7 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageAppend] Image append", func o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(istag.Image).NotTo(o.BeNil()) imageutil.ImageWithMetadataOrDie(&istag.Image) - o.Expect(istag.Image.DockerImageLayers).To(o.HaveLen(2)) + o.Expect(istag.Image.DockerImageLayers).To(o.HaveLen(baseLayerCount + 1)) o.Expect(istag.Image.DockerImageLayers[0].Name).To(o.Equal(busyboxLayer)) err = imageutil.ImageWithMetadata(&istag.Image) o.Expect(err).NotTo(o.HaveOccurred()) diff --git a/test/extended/images/extract.go b/test/extended/images/extract.go index 46e80c484eda..5aa9f70c0a95 100644 --- a/test/extended/images/extract.go +++ b/test/extended/images/extract.go @@ -2,6 +2,7 @@ package images import ( "context" + "fmt" "strings" "github.com/MakeNowJust/heredoc" @@ -10,6 +11,7 @@ import ( kapi "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + k8simage "k8s.io/kubernetes/test/utils/image" imageapi "github.com/openshift/api/image/v1" imageclientset "github.com/openshift/client-go/image/clientset/versioned" @@ -40,7 +42,17 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageExtract] Image extract", fu cli := oc.KubeFramework().PodClient() client := imageclientset.NewForConfigOrDie(oc.UserConfig()).ImageV1() - _, err = client.ImageStreamImports(ns).Create(context.Background(), &imageapi.ImageStreamImport{ + // import tools:latest into this namespace - working around a pull through bug with referenced docker images + // https://bugzilla.redhat.com/show_bug.cgi?id=1843253 + _, err = client.ImageStreamTags(ns).Create(context.Background(), &imageapi.ImageStreamTag{ + ObjectMeta: metav1.ObjectMeta{Name: "1:tools"}, + Tag: &imageapi.TagReference{ + From: &kapi.ObjectReference{Kind: "ImageStreamTag", Namespace: "openshift", Name: "tools:latest"}, + }, + }, metav1.CreateOptions{}) + o.Expect(err).ToNot(o.HaveOccurred()) + + isi, err := client.ImageStreamImports(ns).Create(context.Background(), &imageapi.ImageStreamImport{ ObjectMeta: metav1.ObjectMeta{ Name: "1", }, @@ -48,11 +60,7 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageExtract] Image extract", fu Import: true, Images: []imageapi.ImageImportSpec{ { - From: kapi.ObjectReference{Kind: "DockerImage", Name: "busybox:latest"}, - To: &kapi.LocalObjectReference{Name: "busybox"}, - }, - { - From: kapi.ObjectReference{Kind: "DockerImage", Name: "mysql:latest"}, + From: kapi.ObjectReference{Kind: "DockerImage", Name: k8simage.GetE2EImage(k8simage.Agnhost)}, To: &kapi.LocalObjectReference{Name: "mysql"}, }, }, @@ -60,8 +68,12 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageExtract] Image extract", fu }, metav1.CreateOptions{}) o.Expect(err).ToNot(o.HaveOccurred()) - // busyboxLayers := isi.Status.Images[0].Image.DockerImageLayers - // busyboxLen := len(busyboxLayers) + for i, img := range isi.Status.Images { + o.Expect(img.Status.Status).To(o.Equal("Success"), fmt.Sprintf("imagestreamimport status for spec.image[%d] (message: %s)", i, img.Status.Message)) + } + + // toolsLayers := isi.Status.Images[0].Image.DockerImageLayers + // toolsLen := len(toolsLayers) // mysqlLayers := isi.Status.Images[1].Image.DockerImageLayers // mysqlLen := len(mysqlLayers) @@ -69,25 +81,24 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageExtract] Image extract", fu set -x # command exits if directory doesn't exist - ! oc image extract --insecure %[2]s/%[1]s/1:busybox --path=/:/tmp/doesnotexist + ! oc image extract --insecure %[2]s/%[1]s/1:tools --path=/:/tmp/doesnotexist # command exits if directory isn't empty - ! oc image extract --insecure %[2]s/%[1]s/1:busybox --path=/:/ + ! oc image extract --insecure %[2]s/%[1]s/1:tools --path=/:/ - # extract busybox to a directory, verify the contents + # extract a directory to a directory, verify the contents mkdir -p /tmp/test - oc image extract --insecure %[2]s/%[1]s/1:busybox --path=/:/tmp/test - [ -d /tmp/test/etc ] && [ -d /tmp/test/bin ] - [ -f /tmp/test/etc/passwd ] && grep root /tmp/test/etc/passwd + oc image extract --insecure %[2]s/%[1]s/1:tools --path=/etc/cron.d/:/tmp/test/ + [ -f /tmp/test/0hourly ] && grep root /tmp/test/0hourly # extract multiple individual files mkdir -p /tmp/test2 - oc image extract --insecure %[2]s/%[1]s/1:busybox --path=/etc/shadow:/tmp/test2 --path=/etc/localtime:/tmp/test2 - [ -f /tmp/test2/shadow ] && [ -f /tmp/test2/localtime ] + oc image extract --insecure %[2]s/%[1]s/1:tools --path=/etc/shadow:/tmp/test2 --path=/etc/system-release:/tmp/test2 + [ -f /tmp/test2/shadow ] && [ -L /tmp/test2/system-release ] # extract a single file to the current directory mkdir -p /tmp/test3 cd /tmp/test3 - oc image extract --insecure %[2]s/%[1]s/1:busybox --file=/etc/shadow + oc image extract --insecure %[2]s/%[1]s/1:tools --file=/etc/shadow [ -f /tmp/test3/shadow ] `, ns, registry))) cli.WaitForSuccess(pod.Name, podStartupTimeout) diff --git a/test/extended/images/imagechange_buildtrigger.go b/test/extended/images/imagechange_buildtrigger.go index 2094fa40639c..31384e67d060 100644 --- a/test/extended/images/imagechange_buildtrigger.go +++ b/test/extended/images/imagechange_buildtrigger.go @@ -190,7 +190,7 @@ func imageChangeBuildConfig(namespace, name string, strategy buildv1.BuildStrate CommonSpec: buildv1.CommonSpec{ Source: buildv1.BuildSource{ Git: &buildv1.GitBuildSource{ - URI: "git://github.com/openshift/ruby-hello-world.git", + URI: "https://github.com/openshift/ruby-hello-world.git", }, ContextDir: "contextimage", }, diff --git a/test/extended/images/imagestream_admission.go b/test/extended/images/imagestream_admission.go index 3fd1a5f34d7a..a0bae6f62c1c 100644 --- a/test/extended/images/imagestream_admission.go +++ b/test/extended/images/imagestream_admission.go @@ -522,6 +522,14 @@ func createLimitRangeOfType(t g.GinkgoTInterface, oc *exutil.CLI, lrClient corev t.Logf("creating limit range object %q with %s limited to: %v", limitRangeName, limitType, maxLimits) lr, err := lrClient.Create(context.Background(), lr, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) + + // When we have more than one replica, objects that are created on one + // replica aren't immediately visible to informers on other replicas. + // We don't have mechanisms to check if the LimitRange is observed by all + // replicas. Let's give the informers some time and hope that they'll be + // able to observe this limit. + time.Sleep(5 * time.Second) + return lr } diff --git a/test/extended/images/imagestreamimport.go b/test/extended/images/imagestreamimport.go index 9bd6dda65b26..2eb4579a1082 100644 --- a/test/extended/images/imagestreamimport.go +++ b/test/extended/images/imagestreamimport.go @@ -24,53 +24,71 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/util/retry" + configv1 "github.com/openshift/api/config/v1" imagev1 "github.com/openshift/api/image/v1" - projectv1 "github.com/openshift/api/project/v1" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" ) -// This test is currently disruptive because it doesn't wait for the cluster state to return to a set of stable -// operators (everything available, not progressing, not degraded) and the machine config operator to have finished -// rolling the change to every node. -// This causes instability in the tests that follow it that expect a stable clusters. Examples include scheduling tests -// that require all workers schedulable with functional networking and storage tests which require long running connections -// on both apiservers and kubelets to exec into them. -// After meeting the standard for stability, this test is likely to be [Slow] -var _ = g.Describe("[sig-imageregistry][Feature:ImageStreamImport][Serial][Disruptive] ImageStream API", func() { +var _ = g.Describe("[sig-imageregistry][Feature:ImageStreamImport][Serial][Slow] ImageStream API", func() { defer g.GinkgoRecover() oc := exutil.NewCLI("imagestream-api") + g.BeforeEach(func() { + if err := deployEphemeralImageRegistry(oc); err != nil { + g.GinkgoT().Fatalf("error deploying ephemeral registry: %s", err) + } + }) + + g.AfterEach(func() { + // awaits until all cluster operators are available + if err := wait.PollImmediate(30*time.Second, 10*time.Minute, func() (bool, error) { + coList, err := oc.AdminConfigClient().ConfigV1().ClusterOperators().List( + context.Background(), metav1.ListOptions{}, + ) + if err != nil { + g.GinkgoT().Error("error fetching list of cluster operators: %v", err) + return false, nil + } + for _, operator := range coList.Items { + for _, cond := range operator.Status.Conditions { + stable := true + switch cond.Type { + case configv1.OperatorAvailable: + stable = cond.Status == configv1.ConditionTrue + case configv1.OperatorProgressing: + stable = cond.Status == configv1.ConditionFalse + case configv1.OperatorDegraded: + stable = cond.Status == configv1.ConditionFalse + } + if !stable { + g.GinkgoT().Logf("operator %s not stable, condition: %v", operator.Name, cond) + return false, nil + } + } + } + return true, nil + }); err != nil { + g.GinkgoT().Error("error waiting for operators: %v") + } + }) g.It("TestImportImageFromInsecureRegistry", func() { - TestImportImageFromInsecureRegistry(g.GinkgoT(), oc) + TestImportImageFromInsecureRegistry(oc) }) g.It("TestImportImageFromBlockedRegistry", func() { - TestImportImageFromBlockedRegistry(g.GinkgoT(), oc) + TestImportImageFromBlockedRegistry(oc) }) g.It("TestImportRepositoryFromInsecureRegistry", func() { - TestImportRepositoryFromInsecureRegistry(g.GinkgoT(), oc) + TestImportRepositoryFromInsecureRegistry(oc) }) g.It("TestImportRepositoryFromBlockedRegistry", func() { - TestImportRepositoryFromBlockedRegistry(g.GinkgoT(), oc) + TestImportRepositoryFromBlockedRegistry(oc) }) }) -// createProject creates and returns a new project with a random name. -func createProject(oc *exutil.CLI) (*projectv1.Project, error) { - return oc.AdminProjectClient().ProjectV1().Projects().Create( - context.Background(), - &projectv1.Project{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("image-stream-test-%s", uuid.New().String()), - }, - }, - metav1.CreateOptions{}, - ) -} - -// createRegistryCASecret creates a Secret containing a self signed certificate and key. This -// secret is created inside the provided project. -func createRegistryCASecret(oc *exutil.CLI, proj *projectv1.Project) (*corev1.Secret, error) { +// createRegistryCASecret creates a Secret containing a self signed certificate and key. +func createRegistryCASecret(oc *exutil.CLI) (*corev1.Secret, error) { priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return nil, err @@ -107,7 +125,7 @@ func createRegistryCASecret(oc *exutil.CLI, proj *projectv1.Project) (*corev1.Se Bytes: x509.MarshalPKCS1PrivateKey(priv), }) - return oc.AdminKubeClient().CoreV1().Secrets(proj.Name).Create( + sec, err := oc.AdminKubeClient().CoreV1().Secrets(oc.Namespace()).Create( context.Background(), &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ @@ -120,11 +138,16 @@ func createRegistryCASecret(oc *exutil.CLI, proj *projectv1.Project) (*corev1.Se }, metav1.CreateOptions{}, ) + if err != nil { + return nil, err + } + return sec, nil } // createRegistryService creates a service pointing to deployed ephemeral image registry. -func createRegistryService(oc *exutil.CLI, proj *projectv1.Project, selector map[string]string) error { - if _, err := oc.AdminKubeClient().CoreV1().Services(proj.Name).Create( +func createRegistryService(oc *exutil.CLI, selector map[string]string) error { + t := g.GinkgoT() + if _, err := oc.AdminKubeClient().CoreV1().Services(oc.Namespace()).Create( context.Background(), &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ @@ -146,23 +169,30 @@ func createRegistryService(oc *exutil.CLI, proj *projectv1.Project, selector map return err } - return wait.Poll(time.Second, time.Minute, func() (stop bool, err error) { - if _, err = oc.AdminKubeClient().CoreV1().Endpoints(proj.Name).Get( + return wait.Poll(5*time.Second, 5*time.Minute, func() (stop bool, err error) { + _, err = oc.AdminKubeClient().CoreV1().Endpoints(oc.Namespace()).Get( context.Background(), "image-registry", metav1.GetOptions{}, - ); errors.IsNotFound(err) { + ) + switch { + case err == nil: + return true, nil + case errors.IsNotFound(err): + t.Log("endpoint for image registry service not found, retrying") return false, nil + default: + return true, fmt.Errorf("error getting registry service endpoint: %s", err) } - return true, err }) } // deployEphemeralImageRegistry deploys an ephemeral image registry instance using self signed // certificates, a service is created pointing to image registry. This function awaits until -// the deployment is complete. Registry is configured with no authentication. -func deployEphemeralImageRegistry(oc *exutil.CLI, proj *projectv1.Project) error { +// the deployment is complete. Registry is configured without authentication. +func deployEphemeralImageRegistry(oc *exutil.CLI) error { var replicas int32 = 1 - secret, err := createRegistryCASecret(oc, proj) + t := g.GinkgoT() + secret, err := createRegistryCASecret(oc) if err != nil { return fmt.Errorf("error creating registry secret: %v", err) } @@ -189,7 +219,7 @@ func deployEphemeralImageRegistry(oc *exutil.CLI, proj *projectv1.Project) error containers := []corev1.Container{ { Name: "registry", - Image: "docker.io/registry", + Image: image.LocationFor("docker.io/library/registry:2.7.1"), Ports: []corev1.ContainerPort{ { ContainerPort: 5000, @@ -226,13 +256,12 @@ func deployEphemeralImageRegistry(oc *exutil.CLI, proj *projectv1.Project) error }, } - deploy, err := oc.AdminKubeClient().AppsV1().Deployments(proj.Name).Create( + deploy, err := oc.AdminKubeClient().AppsV1().Deployments(oc.Namespace()).Create( context.Background(), &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: "image-registry", - Namespace: proj.Name, - Labels: map[string]string{"app": "image-registry"}, + Name: "image-registry", + Labels: map[string]string{"app": "image-registry"}, }, Spec: appsv1.DeploymentSpec{ Replicas: &replicas, @@ -253,49 +282,41 @@ func deployEphemeralImageRegistry(oc *exutil.CLI, proj *projectv1.Project) error metav1.CreateOptions{}, ) if err != nil { - return err + return fmt.Errorf("error creating registry deploy: %s", err) } - // awaits for deployment to rollout. - if err := wait.Poll(time.Second, 5*time.Minute, func() (stop bool, err error) { - deploy, err := oc.AdminKubeClient().AppsV1().Deployments(proj.Name).Get( + t.Log("awaiting for registry deployment to rollout") + if err := wait.Poll(5*time.Second, 5*time.Minute, func() (stop bool, err error) { + deploy, err := oc.AdminKubeClient().AppsV1().Deployments(oc.Namespace()).Get( context.Background(), deploy.Name, metav1.GetOptions{}, ) if err != nil { return false, err } - return deploy.Status.AvailableReplicas == replicas, nil + succeed := deploy.Status.AvailableReplicas == replicas + if !succeed { + t.Logf("registry deployment not ready yet, status: %+v", deploy.Status) + } + return succeed, nil }); err != nil { - return err + return fmt.Errorf("error awaiting registry deploy: %s", err) } + t.Log("registry deployment available, moving on") - return createRegistryService(oc, proj, map[string]string{"app": "image-registry"}) + return createRegistryService(oc, map[string]string{"app": "image-registry"}) } // TestImportImageFromInsecureRegistry verifies api capability of importing images from insecure // remote image registries. We support two ways of setting a registry as inscure: by setting it // as insecure directly on an ImageStreamImport request or by setting it as insecure globally by // adding it to InsecureRegistry on images.config.openshift.io/cluster. -func TestImportImageFromInsecureRegistry(t g.GinkgoTInterface, oc *exutil.CLI) { - proj, err := createProject(oc) - if err != nil { - t.Fatalf("unable to create project: %v", err) - } - defer func() { - // defer the project deletion so we can get rid of all resources. - _ = oc.AdminProjectClient().ProjectV1().Projects().Delete( - context.Background(), proj.Name, metav1.DeleteOptions{}, - ) - }() - - if err := deployEphemeralImageRegistry(oc, proj); err != nil { - t.Fatalf("unable to deploy image registry: %v", err) - } +func TestImportImageFromInsecureRegistry(oc *exutil.CLI) { + t := g.GinkgoT() // at this stage our ephemeral registry is available at image-registry.project:5000, // as it uses a self signed certificate if we request a stream import from it API should // fail with a certificate error. - ephemeralRegistry := fmt.Sprintf("image-registry.%s:5000", proj.Name) + ephemeralRegistry := fmt.Sprintf("image-registry.%s:5000", oc.Namespace()) imageOnRegistry := fmt.Sprintf("%s/invalid/invalid", ephemeralRegistry) baseISI := &imagev1.ImageStreamImport{ ObjectMeta: metav1.ObjectMeta{ @@ -314,7 +335,7 @@ func TestImportImageFromInsecureRegistry(t g.GinkgoTInterface, oc *exutil.CLI) { }, }, } - isi, err := oc.AdminImageClient().ImageV1().ImageStreamImports(proj.Name).Create( + isi, err := oc.AdminImageClient().ImageV1().ImageStreamImports(oc.Namespace()).Create( context.Background(), baseISI, metav1.CreateOptions{}, ) if err != nil { @@ -333,7 +354,7 @@ func TestImportImageFromInsecureRegistry(t g.GinkgoTInterface, oc *exutil.CLI) { // test now by setting the remote registry as "insecure" on ImageStreamImport. baseISI.Name = fmt.Sprintf("stream-import-test-%s", uuid.New().String()) baseISI.Spec.Images[0].ImportPolicy.Insecure = true - isi, err = oc.AdminImageClient().ImageV1().ImageStreamImports(proj.Name).Create( + isi, err = oc.AdminImageClient().ImageV1().ImageStreamImports(oc.Namespace()).Create( context.Background(), baseISI, metav1.CreateOptions{}, ) if err != nil { @@ -388,7 +409,7 @@ func TestImportImageFromInsecureRegistry(t g.GinkgoTInterface, oc *exutil.CLI) { // test one more time, now with the registry configured as insecure globally. baseISI.Name = fmt.Sprintf("stream-import-test-%s", uuid.New().String()) baseISI.Spec.Images[0].ImportPolicy.Insecure = false - isi, err = oc.AdminImageClient().ImageV1().ImageStreamImports(proj.Name).Create( + isi, err = oc.AdminImageClient().ImageV1().ImageStreamImports(oc.Namespace()).Create( context.Background(), baseISI, metav1.CreateOptions{}, ) if err != nil { @@ -408,26 +429,13 @@ func TestImportImageFromInsecureRegistry(t g.GinkgoTInterface, oc *exutil.CLI) { // TestImportImageFromBlockedRegistry verifies users can't import images from a registry that // is configured as blocked through images.config.openshift.io/cluster. -func TestImportImageFromBlockedRegistry(t g.GinkgoTInterface, oc *exutil.CLI) { - proj, err := createProject(oc) - if err != nil { - t.Fatalf("unable to create project: %v", err) - } - defer func() { - // defer the project deletion so we can get rid of all resources. - _ = oc.AdminProjectClient().ProjectV1().Projects().Delete( - context.Background(), proj.Name, metav1.DeleteOptions{}, - ) - }() - - if err := deployEphemeralImageRegistry(oc, proj); err != nil { - t.Fatalf("unable to deploy image registry: %v", err) - } +func TestImportImageFromBlockedRegistry(oc *exutil.CLI) { + t := g.GinkgoT() // at this stage our ephemeral registry is available at image-registry.project:5000, // as it uses a self signed certificate if we request a stream import from it API should // fail with a certificate error. - ephemeralRegistry := fmt.Sprintf("image-registry.%s:5000", proj.Name) + ephemeralRegistry := fmt.Sprintf("image-registry.%s:5000", oc.Namespace()) imageOnRegistry := fmt.Sprintf("%s/invalid/invalid", ephemeralRegistry) baseISI := &imagev1.ImageStreamImport{ ObjectMeta: metav1.ObjectMeta{ @@ -449,7 +457,7 @@ func TestImportImageFromBlockedRegistry(t g.GinkgoTInterface, oc *exutil.CLI) { }, }, } - isi, err := oc.AdminImageClient().ImageV1().ImageStreamImports(proj.Name).Create( + isi, err := oc.AdminImageClient().ImageV1().ImageStreamImports(oc.Namespace()).Create( context.Background(), baseISI, metav1.CreateOptions{}, ) if err != nil { @@ -502,7 +510,7 @@ func TestImportImageFromBlockedRegistry(t g.GinkgoTInterface, oc *exutil.CLI) { // test one more time, now with the registry configured as blocked. baseISI.Name = fmt.Sprintf("stream-import-test-%s", uuid.New().String()) - isi, err = oc.AdminImageClient().ImageV1().ImageStreamImports(proj.Name).Create( + isi, err = oc.AdminImageClient().ImageV1().ImageStreamImports(oc.Namespace()).Create( context.Background(), baseISI, metav1.CreateOptions{}, ) if err != nil { @@ -523,26 +531,13 @@ func TestImportImageFromBlockedRegistry(t g.GinkgoTInterface, oc *exutil.CLI) { // TestImportRepositoryFromBlockedRegistry verifies users can't import repositories from a // registry that is configured as blocked through images.config.openshift.io/cluster. -func TestImportRepositoryFromBlockedRegistry(t g.GinkgoTInterface, oc *exutil.CLI) { - proj, err := createProject(oc) - if err != nil { - t.Fatalf("unable to create project: %v", err) - } - defer func() { - // defer the project deletion so we can get rid of all resources. - _ = oc.AdminProjectClient().ProjectV1().Projects().Delete( - context.Background(), proj.Name, metav1.DeleteOptions{}, - ) - }() - - if err := deployEphemeralImageRegistry(oc, proj); err != nil { - t.Fatalf("unable to deploy image registry: %v", err) - } +func TestImportRepositoryFromBlockedRegistry(oc *exutil.CLI) { + t := g.GinkgoT() // at this stage our ephemeral registry is available at image-registry.project:5000, // as it uses a self signed certificate if we request a stream import from it API should // fail with a certificate error. - ephemeralRegistry := fmt.Sprintf("image-registry.%s:5000", proj.Name) + ephemeralRegistry := fmt.Sprintf("image-registry.%s:5000", oc.Namespace()) imageOnRegistry := fmt.Sprintf("%s/invalid/invalid", ephemeralRegistry) baseISI := &imagev1.ImageStreamImport{ ObjectMeta: metav1.ObjectMeta{ @@ -562,7 +557,7 @@ func TestImportRepositoryFromBlockedRegistry(t g.GinkgoTInterface, oc *exutil.CL }, }, } - isi, err := oc.AdminImageClient().ImageV1().ImageStreamImports(proj.Name).Create( + isi, err := oc.AdminImageClient().ImageV1().ImageStreamImports(oc.Namespace()).Create( context.Background(), baseISI, metav1.CreateOptions{}, ) if err != nil { @@ -615,7 +610,7 @@ func TestImportRepositoryFromBlockedRegistry(t g.GinkgoTInterface, oc *exutil.CL // test one more time, now with the registry configured as blocked. baseISI.Name = fmt.Sprintf("stream-import-test-%s", uuid.New().String()) - isi, err = oc.AdminImageClient().ImageV1().ImageStreamImports(proj.Name).Create( + isi, err = oc.AdminImageClient().ImageV1().ImageStreamImports(oc.Namespace()).Create( context.Background(), baseISI, metav1.CreateOptions{}, ) if err != nil { @@ -638,26 +633,13 @@ func TestImportRepositoryFromBlockedRegistry(t g.GinkgoTInterface, oc *exutil.CL // insecure remote registries. We support two ways of setting a registry as insecure: by setting // it as insecure directly on an ImageStreamImport request or by setting it as insecure globally // by adding it to InsecureRegistry config on images.config.openshift.io/cluster. -func TestImportRepositoryFromInsecureRegistry(t g.GinkgoTInterface, oc *exutil.CLI) { - proj, err := createProject(oc) - if err != nil { - t.Fatalf("unable to create project: %v", err) - } - defer func() { - // defer the project deletion so we can get rid of all resources. - _ = oc.AdminProjectClient().ProjectV1().Projects().Delete( - context.Background(), proj.Name, metav1.DeleteOptions{}, - ) - }() - - if err := deployEphemeralImageRegistry(oc, proj); err != nil { - t.Fatalf("unable to deploy image registry: %v", err) - } +func TestImportRepositoryFromInsecureRegistry(oc *exutil.CLI) { + t := g.GinkgoT() // at this stage our ephemeral registry is available at image-registry.project:5000, // as it uses a self signed certificate if we request a stream import from it API should // fail with a certificate error. - ephemeralRegistry := fmt.Sprintf("image-registry.%s:5000", proj.Name) + ephemeralRegistry := fmt.Sprintf("image-registry.%s:5000", oc.Namespace()) imageOnRegistry := fmt.Sprintf("%s/invalid/invalid", ephemeralRegistry) baseISI := &imagev1.ImageStreamImport{ ObjectMeta: metav1.ObjectMeta{ @@ -673,7 +655,7 @@ func TestImportRepositoryFromInsecureRegistry(t g.GinkgoTInterface, oc *exutil.C }, }, } - isi, err := oc.AdminImageClient().ImageV1().ImageStreamImports(proj.Name).Create( + isi, err := oc.AdminImageClient().ImageV1().ImageStreamImports(oc.Namespace()).Create( context.Background(), baseISI, metav1.CreateOptions{}, ) if err != nil { @@ -692,7 +674,7 @@ func TestImportRepositoryFromInsecureRegistry(t g.GinkgoTInterface, oc *exutil.C // test now by setting the remote registry as "insecure" on ImageStreamImport. baseISI.Name = fmt.Sprintf("stream-import-test-%s", uuid.New().String()) baseISI.Spec.Repository.ImportPolicy.Insecure = true - isi, err = oc.AdminImageClient().ImageV1().ImageStreamImports(proj.Name).Create( + isi, err = oc.AdminImageClient().ImageV1().ImageStreamImports(oc.Namespace()).Create( context.Background(), baseISI, metav1.CreateOptions{}, ) if err != nil { @@ -747,7 +729,7 @@ func TestImportRepositoryFromInsecureRegistry(t g.GinkgoTInterface, oc *exutil.C // test one more time, now with the registry configured as insecure globally. baseISI.Name = fmt.Sprintf("stream-import-test-%s", uuid.New().String()) baseISI.Spec.Repository.ImportPolicy.Insecure = false - isi, err = oc.AdminImageClient().ImageV1().ImageStreamImports(proj.Name).Create( + isi, err = oc.AdminImageClient().ImageV1().ImageStreamImports(oc.Namespace()).Create( context.Background(), baseISI, metav1.CreateOptions{}, ) if err != nil { diff --git a/test/extended/images/info.go b/test/extended/images/info.go index 6c6ca1713345..dac8a1a040d5 100644 --- a/test/extended/images/info.go +++ b/test/extended/images/info.go @@ -30,9 +30,6 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageInfo] Image info", func() { # display info about an image on quay.io oc image info quay.io/coreos/etcd:latest - # display info about an image on quay.io - oc image info docker.io/library/mysql:latest - # display info about an image in json format oc image info quay.io/coreos/etcd:latest -o json `))) diff --git a/test/extended/images/layers.go b/test/extended/images/layers.go index 35637592f8c6..c604689ef185 100644 --- a/test/extended/images/layers.go +++ b/test/extended/images/layers.go @@ -13,12 +13,14 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" e2e "k8s.io/kubernetes/test/e2e/framework" + k8simage "k8s.io/kubernetes/test/utils/image" buildv1 "github.com/openshift/api/build/v1" imagev1 "github.com/openshift/api/image/v1" buildv1client "github.com/openshift/client-go/build/clientset/versioned" imagev1client "github.com/openshift/client-go/image/clientset/versioned" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" ) var _ = g.Describe("[sig-imageregistry][Feature:ImageLayers] Image layer subresource", func() { @@ -85,11 +87,11 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLayers] Image layer subreso Import: true, Images: []imagev1.ImageImportSpec{ { - From: corev1.ObjectReference{Kind: "DockerImage", Name: "busybox:latest"}, + From: corev1.ObjectReference{Kind: "DockerImage", Name: image.ShellImage()}, To: &corev1.LocalObjectReference{Name: "busybox"}, }, { - From: corev1.ObjectReference{Kind: "DockerImage", Name: "mysql:latest"}, + From: corev1.ObjectReference{Kind: "DockerImage", Name: k8simage.GetE2EImage(k8simage.Agnhost)}, To: &corev1.LocalObjectReference{Name: "mysql"}, }, }, diff --git a/test/extended/images/mirror.go b/test/extended/images/mirror.go index bb7defc74c34..1d2fc50d85d8 100644 --- a/test/extended/images/mirror.go +++ b/test/extended/images/mirror.go @@ -21,10 +21,13 @@ import ( frameworkpod "k8s.io/kubernetes/test/e2e/framework/pod" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" ) const podStartupTimeout = 3 * time.Minute -const testPod1 = `kind: Pod + +var testPod1 = fmt.Sprintf( + `kind: Pod id: oc-image-mirror-test-1 apiVersion: v1 metadata: @@ -34,7 +37,7 @@ metadata: spec: containers: - name: registry-1 - image: docker.io/library/registry + image: %[1]s env: - name: REGISTRY_HTTP_ADDR value: :5001 @@ -45,13 +48,17 @@ spec: - name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY value: /tmp - name: shell - image: openshift/origin:latest + image: %[2]s command: - /bin/sleep - infinity -` +`, + image.LocationFor("docker.io/library/registry:2.7.1"), + image.ShellImage(), +) -const testPod2 = `kind: Pod +var testPod2 = fmt.Sprintf( + `kind: Pod id: oc-image-mirror-test-2 apiVersion: v1 metadata: @@ -61,7 +68,7 @@ metadata: spec: containers: - name: registry-1 - image: docker.io/library/registry + image: %[1]s env: - name: REGISTRY_HTTP_ADDR value: :5002 @@ -72,7 +79,7 @@ spec: - name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY value: /tmp - name: registry-2 - image: docker.io/library/registry + image: %[1]s env: - name: REGISTRY_HTTP_ADDR value: :5003 @@ -83,11 +90,14 @@ spec: - name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY value: /tmp - name: shell - image: openshift/origin:latest + image: %[2]s command: - /bin/sleep - infinity -` +`, + image.LocationFor("docker.io/library/registry:2.7.1"), + image.ShellImage(), +) func getRandName() string { c := 20 @@ -158,11 +168,11 @@ func (pod *testPod) syncRunning(c kclientset.Interface, ns string, timeout time. return err } -func (pod *testPod) NotErr(err error) { +func (pod *testPod) NotErr(err error) error { if err != nil { exutil.DumpPodLogsStartingWithInNamespace(pod.name, pod.oc.Namespace(), pod.oc) } - o.Expect(err).NotTo(o.HaveOccurred()) + return err } func (pod *testPod) Run() *testPod { @@ -171,7 +181,7 @@ func (pod *testPod) Run() *testPod { err := pod.oc.Run("create").Args("-f", "-").InputString(pod.spec).Execute() o.Expect(err).NotTo(o.HaveOccurred()) - pod.NotErr(pod.syncRunning(pod.oc.AdminKubeClient(), pod.oc.Namespace(), podStartupTimeout)) + o.Expect(pod.NotErr(pod.syncRunning(pod.oc.AdminKubeClient(), pod.oc.Namespace(), podStartupTimeout))).NotTo(o.HaveOccurred()) return pod } @@ -188,7 +198,7 @@ func (pod *testPod) ShellExec(command ...string) *exutil.CLI { func genDockerConfig(pod *testPod, registryURL, user, token string) { config := fmt.Sprintf(`{"auths":{%q:{"auth":%q}}}`, registryURL, base64.StdEncoding.EncodeToString([]byte(user+":"+token))) - + framework.Logf("Config file: %s", config) err := pod.ShellExec("bash", "-c", "cd /tmp; cat > config.json").InputString(config).Execute() o.Expect(err).NotTo(o.HaveOccurred()) } @@ -223,25 +233,26 @@ func requestHasStatusCode(pod *testPod, URL, token, statusCode string) { out, err := runHTTPRequest(pod, URL, headers) o.Expect(err).NotTo(o.HaveOccurred()) - m := regexp.MustCompile(fmt.Sprintf(`(?m)^< HTTP/1\.1 %s `, statusCode)).FindString(out) + m := regexp.MustCompile(fmt.Sprintf(`(?m)^< HTTP/(?:1\.1|2) %s `, statusCode)).FindString(out) if len(m) == 0 { err = fmt.Errorf("unexpected status code (expected %s): %s", statusCode, out) } - pod.NotErr(err) + o.Expect(pod.NotErr(err)).NotTo(o.HaveOccurred()) } func testNewBuild(oc *exutil.CLI) (string, string) { isName := "mirror-" + getRandName() istName := isName + ":latest" - testDockerfile := fmt.Sprintf(`FROM busybox:latest -RUN echo %s > /1 -RUN echo %s > /2 -RUN echo %s > /3 + testDockerfile := fmt.Sprintf(`FROM %[4]s +RUN echo %[1]s > /1 +RUN echo %[2]s > /2 +RUN echo %[3]s > /3 `, getRandName(), getRandName(), getRandName(), + image.ShellImage(), ) err := oc.Run("new-build").Args("-D", "-", "--to", istName).InputString(testDockerfile).Execute() @@ -281,7 +292,7 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageMirror][Slow] Image mirror" g.By("get the protocol of integrated registry server") schema, err := getRegistrySchema(pod, registryHost) - pod.NotErr(err) + o.Expect(pod.NotErr(err)).NotTo(o.HaveOccurred()) framework.Logf("the protocol is %s://%s", schema, registryHost) @@ -300,11 +311,11 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageMirror][Slow] Image mirror" requestHasStatusCode(pod, fmt.Sprintf("http://127.0.0.1:5001/v2/%s/manifests/%s", repoName, imgName), "", "404") g.By("Mirror image from the integrated registry server to the external registry server") - command := fmt.Sprintf("cd /tmp; oc --loglevel=8 image mirror %s/%s:latest %s/%s:stable --insecure=true", + command := fmt.Sprintf("cd /tmp; oc image mirror %s/%s:latest %s/%s:stable --insecure=true --registry-config config.json", registryHost, repoName, "127.0.0.1:5001", repoName, ) err = pod.ShellExec([]string{"bash", "-c", command}...).Execute() - pod.NotErr(err) + o.Expect(pod.NotErr(err)).NotTo(o.HaveOccurred()) g.By("Check that we have it in the external registry server") requestHasStatusCode(pod, fmt.Sprintf("http://127.0.0.1:5001/v2/%s/manifests/%s", repoName, imgName), "", "200") @@ -327,7 +338,7 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageMirror][Slow] Image mirror" g.By("get the protocol of integrated registry server") schema, err := getRegistrySchema(pod, registryHost) - pod.NotErr(err) + o.Expect(pod.NotErr(err)).NotTo(o.HaveOccurred()) framework.Logf("the protocol is %s://%s", schema, registryHost) @@ -349,13 +360,13 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageMirror][Slow] Image mirror" requestHasStatusCode(pod, fmt.Sprintf("http://127.0.0.1:5003/v2/%s/manifests/%s", repoName, imgName), "", "404") g.By("Mirror image from the integrated registry server to the external registry server") - command := fmt.Sprintf("cd /tmp; oc image mirror %s/%s:latest %s/%s:stable %s/%s:prod --insecure=true", + command := fmt.Sprintf("cd /tmp; oc image mirror %s/%s:latest %s/%s:stable %s/%s:prod --insecure=true --registry-config config.json", registryHost, repoName, "127.0.0.1:5002", repoName, "127.0.0.1:5003", repoName, ) err = pod.ShellExec([]string{"bash", "-c", command}...).Execute() - pod.NotErr(err) + o.Expect(pod.NotErr(err)).NotTo(o.HaveOccurred()) g.By("Check that we have it in the first external registry server") requestHasStatusCode(pod, fmt.Sprintf("http://127.0.0.1:5002/v2/%s/manifests/%s", repoName, imgName), "", "200") diff --git a/test/extended/images/oc_copy.go b/test/extended/images/oc_copy.go index 8fb693e77cd4..28bf331a0aaf 100644 --- a/test/extended/images/oc_copy.go +++ b/test/extended/images/oc_copy.go @@ -21,7 +21,7 @@ import ( "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/reference" watchtools "k8s.io/client-go/tools/watch" - "k8s.io/klog" + "k8s.io/klog/v2" kapi "k8s.io/kubernetes/pkg/apis/core" appsv1 "github.com/openshift/api/apps/v1" diff --git a/test/extended/images/oc_tag.go b/test/extended/images/oc_tag.go index 416ad92a5b19..a713b5e305b0 100644 --- a/test/extended/images/oc_tag.go +++ b/test/extended/images/oc_tag.go @@ -10,10 +10,12 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" e2e "k8s.io/kubernetes/test/e2e/framework" + k8simage "k8s.io/kubernetes/test/utils/image" authorizationv1 "github.com/openshift/api/authorization/v1" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" ) var _ = g.Describe("[sig-imageregistry][Feature:Image] oc tag", func() { @@ -22,13 +24,17 @@ var _ = g.Describe("[sig-imageregistry][Feature:Image] oc tag", func() { ctx := context.Background() g.It("should preserve image reference for external images", func() { - const ( - externalRepository = "busybox" - externalImage = "busybox:latest" - isName = "busybox" - isName2 = "busybox2" + var ( + externalImage = k8simage.GetE2EImage(k8simage.BusyBox) + isName = "busybox" + isName2 = "busybox2" ) + externalRepository := externalImage + if i := strings.LastIndex(externalRepository, ":"); i != -1 { + externalRepository = externalRepository[:i] + } + g.By("import an external image") err := oc.Run("tag").Args("--source=docker", externalImage, isName+":latest").Execute() @@ -65,12 +71,12 @@ var _ = g.Describe("[sig-imageregistry][Feature:Image] oc tag", func() { }) g.It("should change image reference for internal images", func() { - const ( + var ( isName = "localimage" isName2 = "localimage2" - dockerfile = `FROM busybox:latest + dockerfile = fmt.Sprintf(`FROM %s RUN touch /test-image -` +`, image.ShellImage()) ) g.By("determine the name of the integrated registry") @@ -119,7 +125,7 @@ RUN touch /test-image }) g.It("should work when only imagestreams api is available", func() { - err := oc.Run("tag").Args("--source=docker", "busybox:latest", "testis:latest").Execute() + err := oc.Run("tag").Args("--source=docker", image.ShellImage(), "testis:latest").Execute() o.Expect(err).NotTo(o.HaveOccurred()) err = exutil.WaitForAnImageStreamTag(oc, oc.Namespace(), "testis", "latest") diff --git a/test/extended/images/resolve.go b/test/extended/images/resolve.go index b2c46f49846c..ff9ef1b4d9e0 100644 --- a/test/extended/images/resolve.go +++ b/test/extended/images/resolve.go @@ -2,6 +2,8 @@ package images import ( "context" + "fmt" + "time" g "github.com/onsi/ginkgo" o "github.com/onsi/gomega" @@ -12,6 +14,8 @@ import ( kapiv1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + k8simage "k8s.io/kubernetes/test/utils/image" exutil "github.com/openshift/origin/test/extended/util" ) @@ -23,13 +27,27 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLookup] Image policy", func ctx := context.Background() g.It("should update standard Kube object image fields when local names are on", func() { - err := oc.Run("import-image").Args("busybox:latest", "--confirm").Execute() + err := oc.Run("tag").Args(k8simage.GetE2EImage(k8simage.BusyBox), "busybox:latest").Execute() o.Expect(err).NotTo(o.HaveOccurred()) err = oc.Run("set", "image-lookup").Args("busybox").Execute() o.Expect(err).NotTo(o.HaveOccurred()) - tag, err := oc.ImageClient().ImageV1().ImageStreamTags(oc.Namespace()).Get(ctx, "busybox:latest", metav1.GetOptions{}) + + is, err := oc.ImageClient().ImageV1().ImageStreams(oc.Namespace()).Get(ctx, "busybox", metav1.GetOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(tag.LookupPolicy.Local).To(o.BeTrue()) + o.Expect(is.Spec.LookupPolicy.Local).To(o.BeTrue()) + + var internalImageReference string + var lastErr error + err = wait.PollImmediate(5*time.Second, 2*time.Minute, func() (bool, error) { + tag, err := oc.ImageClient().ImageV1().ImageTags(oc.Namespace()).Get(ctx, "busybox:latest", metav1.GetOptions{}) + if err != nil || tag.Image == nil { + lastErr = err + return false, nil + } + internalImageReference = tag.Image.DockerImageReference + return true, nil + }) + o.Expect(err).NotTo(o.HaveOccurred(), fmt.Sprintf("unable to wait for image to be imported: %v", lastErr)) // pods should auto replace local references pod, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Create(ctx, &kapiv1.Pod{ @@ -45,11 +63,11 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLookup] Image policy", func }, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - if pod.Spec.Containers[0].Image != tag.Image.DockerImageReference { + if pod.Spec.Containers[0].Image != internalImageReference { g.Skip("default image resolution is not configured, can't verify pod resolution") } - o.Expect(pod.Spec.Containers[0].Image).To(o.Equal(tag.Image.DockerImageReference)) + o.Expect(pod.Spec.Containers[0].Image).To(o.Equal(internalImageReference)) o.Expect(pod.Spec.Containers[1].Image).To(o.HaveSuffix("/" + oc.Namespace() + "/busybox:unknown")) defer func() { oc.KubeClient().CoreV1().Pods(oc.Namespace()).Delete(ctx, pod.Name, metav1.DeleteOptions{}) }() @@ -74,18 +92,29 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLookup] Image policy", func }, }, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(rs.Spec.Template.Spec.Containers[0].Image).To(o.Equal(tag.Image.DockerImageReference)) + o.Expect(rs.Spec.Template.Spec.Containers[0].Image).To(o.Equal(internalImageReference)) defer func() { oc.KubeClient().AppsV1().ReplicaSets(oc.Namespace()).Delete(ctx, rs.Name, metav1.DeleteOptions{}) }() }) g.It("should perform lookup when the object has the resolve-names annotation", func() { - err := oc.Run("import-image").Args("busybox:latest", "--confirm").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - tag, err := oc.ImageClient().ImageV1().ImageStreamTags(oc.Namespace()).Get(ctx, "busybox:latest", metav1.GetOptions{}) + err := oc.Run("tag").Args(k8simage.GetE2EImage(k8simage.BusyBox), "busybox:latest").Execute() o.Expect(err).NotTo(o.HaveOccurred()) + var internalImageReference string + var lastErr error + err = wait.PollImmediate(5*time.Second, 2*time.Minute, func() (bool, error) { + tag, err := oc.ImageClient().ImageV1().ImageTags(oc.Namespace()).Get(ctx, "busybox:latest", metav1.GetOptions{}) + if err != nil || tag.Image == nil { + lastErr = err + return false, nil + } + internalImageReference = tag.Image.DockerImageReference + return true, nil + }) + o.Expect(err).NotTo(o.HaveOccurred(), fmt.Sprintf("unable to wait for image to be imported: %v", lastErr)) + g.By("auto replacing local references on Pods") pod, err := oc.KubeClient().CoreV1().Pods(oc.Namespace()).Create(ctx, &kapiv1.Pod{ ObjectMeta: metav1.ObjectMeta{ @@ -105,11 +134,11 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLookup] Image policy", func }, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - if pod.Spec.Containers[0].Image != tag.Image.DockerImageReference { + if pod.Spec.Containers[0].Image != internalImageReference { g.Skip("default image resolution is not configured, can't verify pod resolution") } - o.Expect(pod.Spec.Containers[0].Image).To(o.Equal(tag.Image.DockerImageReference)) + o.Expect(pod.Spec.Containers[0].Image).To(o.Equal(internalImageReference)) o.Expect(pod.Spec.Containers[1].Image).To(o.HaveSuffix("/" + oc.Namespace() + "/busybox:unknown")) g.By("auto replacing local references on ReplicaSets") @@ -136,7 +165,7 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLookup] Image policy", func }, }, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(rs.Spec.Template.Spec.Containers[0].Image).To(o.Equal(tag.Image.DockerImageReference)) + o.Expect(rs.Spec.Template.Spec.Containers[0].Image).To(o.Equal(internalImageReference)) g.By("auto replacing local references on Deployments") deployment, err := oc.KubeClient().AppsV1().Deployments(oc.Namespace()).Create(ctx, &appsv1.Deployment{ @@ -162,7 +191,7 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLookup] Image policy", func }, }, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(deployment.Spec.Template.Spec.Containers[0].Image).To(o.Equal(tag.Image.DockerImageReference)) + o.Expect(deployment.Spec.Template.Spec.Containers[0].Image).To(o.Equal(internalImageReference)) g.By("auto replacing local references on Deployments (in pod template)") deployment, err = oc.KubeClient().AppsV1().Deployments(oc.Namespace()).Create(ctx, &appsv1.Deployment{ @@ -190,7 +219,7 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLookup] Image policy", func }, }, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(deployment.Spec.Template.Spec.Containers[0].Image).To(o.Equal(tag.Image.DockerImageReference)) + o.Expect(deployment.Spec.Template.Spec.Containers[0].Image).To(o.Equal(internalImageReference)) g.By("auto replacing local references on DaemonSets") daemonset, err := oc.KubeClient().AppsV1().DaemonSets(oc.Namespace()).Create(ctx, &appsv1.DaemonSet{ @@ -218,7 +247,7 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLookup] Image policy", func }, }, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(daemonset.Spec.Template.Spec.Containers[0].Image).To(o.Equal(tag.Image.DockerImageReference)) + o.Expect(daemonset.Spec.Template.Spec.Containers[0].Image).To(o.Equal(internalImageReference)) g.By("auto replacing local references on DaemonSets (in pod template)") daemonset, err = oc.KubeClient().AppsV1().DaemonSets(oc.Namespace()).Create(ctx, &appsv1.DaemonSet{ @@ -246,7 +275,7 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLookup] Image policy", func }, }, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(daemonset.Spec.Template.Spec.Containers[0].Image).To(o.Equal(tag.Image.DockerImageReference)) + o.Expect(daemonset.Spec.Template.Spec.Containers[0].Image).To(o.Equal(internalImageReference)) g.By("auto replacing local references on StatefulSets") statefulset, err := oc.KubeClient().AppsV1().StatefulSets(oc.Namespace()).Create(ctx, &appsv1.StatefulSet{ @@ -274,7 +303,7 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLookup] Image policy", func }, }, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(statefulset.Spec.Template.Spec.Containers[0].Image).To(o.Equal(tag.Image.DockerImageReference)) + o.Expect(statefulset.Spec.Template.Spec.Containers[0].Image).To(o.Equal(internalImageReference)) g.By("auto replacing local references on StatefulSets (in pod template)") statefulset, err = oc.KubeClient().AppsV1().StatefulSets(oc.Namespace()).Create(ctx, &appsv1.StatefulSet{ @@ -302,7 +331,7 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLookup] Image policy", func }, }, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(statefulset.Spec.Template.Spec.Containers[0].Image).To(o.Equal(tag.Image.DockerImageReference)) + o.Expect(statefulset.Spec.Template.Spec.Containers[0].Image).To(o.Equal(internalImageReference)) g.By("auto replacing local references on Jobs") job, err := oc.KubeClient().BatchV1().Jobs(oc.Namespace()).Create(ctx, &kbatchv1.Job{ @@ -328,7 +357,7 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLookup] Image policy", func }, }, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(job.Spec.Template.Spec.Containers[0].Image).To(o.Equal(tag.Image.DockerImageReference)) + o.Expect(job.Spec.Template.Spec.Containers[0].Image).To(o.Equal(internalImageReference)) g.By("auto replacing local references on Jobs (in pod template)") job, err = oc.KubeClient().BatchV1().Jobs(oc.Namespace()).Create(ctx, &kbatchv1.Job{ @@ -353,7 +382,7 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLookup] Image policy", func }, }, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(job.Spec.Template.Spec.Containers[0].Image).To(o.Equal(tag.Image.DockerImageReference)) + o.Expect(job.Spec.Template.Spec.Containers[0].Image).To(o.Equal(internalImageReference)) g.By("auto replacing local references on CronJobs") cronjob, err := oc.KubeClient().BatchV1beta1().CronJobs(oc.Namespace()).Create(ctx, &kbatchv1beta1.CronJob{ @@ -381,7 +410,7 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLookup] Image policy", func }, }, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(cronjob.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Image).To(o.Equal(tag.Image.DockerImageReference)) + o.Expect(cronjob.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Image).To(o.Equal(internalImageReference)) g.By("auto replacing local references on CronJobs (in pod template)") cronjob, err = oc.KubeClient().BatchV1beta1().CronJobs(oc.Namespace()).Create(ctx, &kbatchv1beta1.CronJob{ @@ -411,15 +440,27 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLookup] Image policy", func }, }, metav1.CreateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(cronjob.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Image).To(o.Equal(tag.Image.DockerImageReference)) + o.Expect(cronjob.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Image).To(o.Equal(internalImageReference)) }) g.It("should perform lookup when the Deployment gets the resolve-names annotation later", func() { - err := oc.Run("import-image").Args("busybox:latest", "--confirm").Execute() - o.Expect(err).NotTo(o.HaveOccurred()) - tag, err := oc.ImageClient().ImageV1().ImageStreamTags(oc.Namespace()).Get(ctx, "busybox:latest", metav1.GetOptions{}) + imageReference := k8simage.GetE2EImage(k8simage.BusyBox) + err := oc.Run("tag").Args(imageReference, "busybox:latest").Execute() o.Expect(err).NotTo(o.HaveOccurred()) + var internalImageReference string + var lastErr error + err = wait.PollImmediate(5*time.Second, 2*time.Minute, func() (bool, error) { + tag, err := oc.ImageClient().ImageV1().ImageTags(oc.Namespace()).Get(ctx, "busybox:latest", metav1.GetOptions{}) + if err != nil || tag.Image == nil { + lastErr = err + return false, nil + } + internalImageReference = tag.Image.DockerImageReference + return true, nil + }) + o.Expect(err).NotTo(o.HaveOccurred(), fmt.Sprintf("unable to wait for image to be imported: %v", lastErr)) + deployment, err := oc.KubeClient().AppsV1().Deployments(oc.Namespace()).Create(ctx, &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: "resolve", @@ -452,6 +493,6 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageLookup] Image policy", func deployment, err = oc.KubeClient().AppsV1().Deployments(deployment.Namespace).Patch(ctx, deployment.Name, types.StrategicMergePatchType, []byte(`{"metadata": {"annotations": {"alpha.image.policy.openshift.io/resolve-names": "*"}}}`), metav1.PatchOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(deployment.ObjectMeta.Annotations["alpha.image.policy.openshift.io/resolve-names"]).To(o.Equal("*")) - o.Expect(deployment.Spec.Template.Spec.Containers[0].Image).To(o.Equal(tag.Image.DockerImageReference)) + o.Expect(deployment.Spec.Template.Spec.Containers[0].Image).To(o.Equal(internalImageReference)) }) }) diff --git a/test/extended/images/trigger/annotation.go b/test/extended/images/trigger/annotation.go index a3b705499366..00d818ea83a7 100644 --- a/test/extended/images/trigger/annotation.go +++ b/test/extended/images/trigger/annotation.go @@ -41,8 +41,8 @@ var _ = g.Describe("[sig-imageregistry][Feature:ImageTriggers] Annotation trigge o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(deployment.Spec.Template.Spec.Containers[0].Image).To(o.Equal(" ")) - g.By("tagging the docker.io/library/centos:latest as test:v1 image to create ImageStream") - out, err := oc.Run("tag").Args("docker.io/library/centos:latest", "test:v1").Output() + g.By("tagging the image-registry.openshift-image-registry.svc:5000/openshift/tools:latest as test:v1 image to create ImageStream") + out, err := oc.Run("tag").Args("image-registry.openshift-image-registry.svc:5000/openshift/tools:latest", "test:v1").Output() framework.Logf("%s", out) o.Expect(err).NotTo(o.HaveOccurred()) diff --git a/test/extended/include.go b/test/extended/include.go index ad6d82ced88e..3364790ee828 100644 --- a/test/extended/include.go +++ b/test/extended/include.go @@ -32,6 +32,7 @@ import ( _ "github.com/openshift/origin/test/extended/networking" _ "github.com/openshift/origin/test/extended/oauth" _ "github.com/openshift/origin/test/extended/operators" + _ "github.com/openshift/origin/test/extended/pods" _ "github.com/openshift/origin/test/extended/project" _ "github.com/openshift/origin/test/extended/prometheus" _ "github.com/openshift/origin/test/extended/quota" diff --git a/test/extended/machines/cluster.go b/test/extended/machines/cluster.go index e9390e6d0dbd..92d88c7ef2cf 100644 --- a/test/extended/machines/cluster.go +++ b/test/extended/machines/cluster.go @@ -2,6 +2,7 @@ package operators import ( "context" + "fmt" g "github.com/onsi/ginkgo" o "github.com/onsi/gomega" @@ -12,6 +13,9 @@ import ( "k8s.io/client-go/dynamic" e2e "k8s.io/kubernetes/test/e2e/framework" e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper" + + exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/prometheus" ) var _ = g.Describe("[sig-cluster-lifecycle][Feature:Machines][Early] Managed cluster should", func() { @@ -52,3 +56,37 @@ var _ = g.Describe("[sig-cluster-lifecycle][Feature:Machines][Early] Managed clu o.Expect(len(nodeItems)).To(o.Equal(len(machineItems))) }) }) + +var _ = g.Describe("[sig-node] Managed cluster", func() { + defer g.GinkgoRecover() + var ( + oc = exutil.NewCLIWithoutNamespace("managed-cluster-node") + + url, bearerToken string + ) + g.BeforeEach(func() { + var ok bool + url, bearerToken, ok = prometheus.LocatePrometheus(oc) + if !ok { + e2e.Failf("Prometheus could not be located on this cluster, failing prometheus test") + } + }) + + g.It("should report ready nodes the entire duration of the test run [Late]", func() { + ns := oc.SetupNamespace() + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") + defer func() { + oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) + }() + + // we only consider samples since the beginning of the test + testDuration := exutil.DurationSinceStartInSeconds().String() + + tests := map[string]bool{ + // all nodes should be reporting ready throughout the entire run, as long as they are older than 6m + fmt.Sprintf(`(min_over_time((max by (node) (kube_node_status_condition{condition="Ready",status="true"}) and (((max by (node) (kube_node_status_condition))) and (0*max by (node) (kube_node_status_condition offset 6m))))[%s:1s])) < 1`, testDuration): false, + } + err := prometheus.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + o.Expect(err).NotTo(o.HaveOccurred()) + }) +}) diff --git a/test/extended/networking/multicast.go b/test/extended/networking/multicast.go index a7b2689513f9..9caed1bcda84 100644 --- a/test/extended/networking/multicast.go +++ b/test/extended/networking/multicast.go @@ -10,6 +10,7 @@ import ( networkclient "github.com/openshift/client-go/network/clientset/versioned/typed/network/v1" "github.com/openshift/library-go/pkg/network/networkutils" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" kapiv1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -167,7 +168,7 @@ func launchTestMulticastPod(f *e2e.Framework, nodeName string, podName string) e Containers: []kapiv1.Container{ { Name: contName, - Image: "quay.io/openshift/community-e2e-images:e2e-docker-io-openshift-test-multicast-latest-4AxcBBxKg_prX34z", + Image: image.LocationFor("docker.io/openshift/test-multicast:latest"), Command: []string{"sleep", "1000"}, }, }, diff --git a/test/extended/oauth/oauth_ldap.go b/test/extended/oauth/oauth_ldap.go index ea5971c9eb84..9e335bc67640 100644 --- a/test/extended/oauth/oauth_ldap.go +++ b/test/extended/oauth/oauth_ldap.go @@ -17,6 +17,7 @@ import ( osinv1 "github.com/openshift/api/osin/v1" userv1client "github.com/openshift/client-go/user/clientset/versioned/typed/user/v1" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" oauthutil "github.com/openshift/origin/test/extended/util/oauthserver" ) @@ -97,7 +98,7 @@ var _ = g.Describe("[sig-auth][Feature:LDAP] LDAP IDP", func() { g.By("configuring LDAP users") volumeMounts, volumes := exutil.LDAPClientMounts() - _, errs := exutil.RunOneShotCommandPod(oc, "oneshot-ldappasswd", exutil.OpenLDAPTestImage, fmt.Sprintf("ldappasswd -x -H ldap://%s -Z -D %s -w %s -s %s cn=%s,%s -vvv", ldapService, bindDN, bindPassword, goodPass, userName, searchDN), volumeMounts, volumes, nil, 5*time.Minute) + _, errs := exutil.RunOneShotCommandPod(oc, "oneshot-ldappasswd", image.OpenLDAPTestImage(), fmt.Sprintf("ldappasswd -x -H ldap://%s -Z -D %s -w %s -s %s cn=%s,%s -vvv", ldapService, bindDN, bindPassword, goodPass, userName, searchDN), volumeMounts, volumes, nil, 5*time.Minute) o.Expect(errs).To(o.BeEmpty()) g.By("ensuring that you cannot authenticate with a bad password") diff --git a/test/extended/operators/olm.go b/test/extended/operators/olm.go index 3c78050088a5..8cf7235c43a7 100644 --- a/test/extended/operators/olm.go +++ b/test/extended/operators/olm.go @@ -130,8 +130,7 @@ var _ = g.Describe("[sig-arch] ocp payload should be based on existing source", g.By(fmt.Sprintf("get olm version from the %s pod", v)) oc.SetNamespace("openshift-operator-lifecycle-manager") - commands := []string{"exec", podName, "--", "olm", "--version"} - olmVersion, err := oc.AsAdmin().Run(commands...).Args().Output() + olmVersion, err := oc.AsAdmin().Run("exec").Args("-n", "openshift-operator-lifecycle-manager", podName, "--", "olm", "--version").Output() o.Expect(err).NotTo(o.HaveOccurred()) idSlice := strings.Split(olmVersion, ":") gitCommitID := strings.TrimSpace(idSlice[len(idSlice)-1]) diff --git a/test/extended/pods/systemd.go b/test/extended/pods/systemd.go new file mode 100644 index 000000000000..8de275fcd3d6 --- /dev/null +++ b/test/extended/pods/systemd.go @@ -0,0 +1,38 @@ +package pods + +import ( + "context" + "fmt" + "strings" + + g "github.com/onsi/ginkgo" + "github.com/openshift/origin/pkg/test/ginkgo/result" + exutil "github.com/openshift/origin/test/extended/util" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = g.Describe("[sig-node][Late]", func() { + defer g.GinkgoRecover() + + oc := exutil.NewCLIWithoutNamespace("no-systemd-timeouts") + + g.It("should not have pod creation failures due to systemd timeouts", func() { + kubeClient := oc.AdminKubeClient() + + events, err := kubeClient.CoreV1().Events("").List(context.TODO(), metav1.ListOptions{}) + if err != nil { + g.Fail(fmt.Sprintf("Unexpected error: %v", err)) + } + + timeoutStrings := []string{} + errorMsg := "Timed out while waiting for StartTransientUnit" + for _, event := range events.Items { + if !strings.Contains(event.Message, errorMsg) { + continue + } + timeoutString := fmt.Sprintf("systemd timed out for pod %v/%v", event.InvolvedObject.Namespace, event.InvolvedObject.Name) + timeoutStrings = append(timeoutStrings, timeoutString) + } + result.Flakef(strings.Join(timeoutStrings, "\n")) + }) +}) diff --git a/test/extended/prometheus/prometheus.go b/test/extended/prometheus/prometheus.go index ad2c84d21d45..2d6bda4966d7 100644 --- a/test/extended/prometheus/prometheus.go +++ b/test/extended/prometheus/prometheus.go @@ -55,35 +55,41 @@ var _ = g.Describe("[sig-instrumentation][Late] Alerts", func() { if len(os.Getenv("TEST_UNSUPPORTED_ALLOW_VERSION_SKEW")) > 0 { e2eskipper.Skipf("Test is disabled to allow cluster components to have different versions, and skewed versions trigger multiple other alerts") } - oc.SetupProject() - ns := oc.Namespace() - execPod := exutil.CreateUbiExecPodOrFail(oc.AdminKubeClient(), ns, "execpod", nil) + ns := oc.SetupNamespace() + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() + // we only consider samples since the beginning of the test + testDuration := exutil.DurationSinceStartInSeconds().String() + tests := map[string]bool{ // Checking Watchdog alert state is done in "should have a Watchdog alert in firing state". // TODO: remove KubePodCrashLooping subtraction logic once https://bugzilla.redhat.com/show_bug.cgi?id=1842002 // is fixed, but for now we are ignoring KubePodCrashLooping alerts in the openshift-kube-controller-manager namespace. - `count_over_time(ALERTS{alertname!~"Watchdog|AlertmanagerReceiversNotConfigured|KubeAPILatencyHigh",alertstate="firing",severity!="info"}[2h]) - count_over_time(ALERTS{alertname="KubePodCrashLooping",namespace="openshift-kube-controller-manager",alertstate="firing",severity!="info"}[2h]) >= 1`: false, + fmt.Sprintf(`count_over_time(ALERTS{alertname!~"Watchdog|AlertmanagerReceiversNotConfigured|KubeAPILatencyHigh",alertstate="firing",severity!="info"}[%[1]s]) - count_over_time(ALERTS{alertname="KubePodCrashLooping",namespace="openshift-kube-controller-manager",alertstate="firing",severity!="info"}[%[1]s]) >= 1`, testDuration): false, } - helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + err := helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + o.Expect(err).NotTo(o.HaveOccurred()) }) g.It("should have a Watchdog alert in firing state the entire cluster run", func() { - oc.SetupProject() - ns := oc.Namespace() - execPod := exutil.CreateUbiExecPodOrFail(oc.AdminKubeClient(), ns, "execpod", nil) + ns := oc.SetupNamespace() + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() + // we only consider series sent since the beginning of the test + testDuration := exutil.DurationSinceStartInSeconds().String() + tests := map[string]bool{ // should have constantly firing a watchdog alert - `count_over_time(ALERTS{alertstate="firing",alertname="Watchdog", severity="none"}[1h])`: true, + fmt.Sprintf(`count_over_time(ALERTS{alertstate="firing",alertname="Watchdog", severity="none"}[%s])`, testDuration): true, } - helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + err := helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + o.Expect(err).NotTo(o.HaveOccurred()) e2e.Logf("Watchdog alert is firing") }) @@ -92,24 +98,29 @@ var _ = g.Describe("[sig-instrumentation][Late] Alerts", func() { if !hasPullSecret(oc.AdminKubeClient(), "cloud.openshift.com") { e2eskipper.Skipf("Telemetry is disabled") } - oc.SetupProject() - ns := oc.Namespace() + ns := oc.SetupNamespace() - execPod := exutil.CreateUbiExecPodOrFail(oc.AdminKubeClient(), ns, "execpod", nil) + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() + // we only consider series sent since the beginning of the test + testDuration := exutil.DurationSinceStartInSeconds().String() + tests := map[string]bool{ // We want to limit the number of total series sent, the cluster:telemetry_selected_series:count - // rule contains the count of the all the series that are sent via telemetry. - `max_over_time(cluster:telemetry_selected_series:count[2h]) >= 500`: false, + // rule contains the count of the all the series that are sent via telemetry. It is permissible + // for some scenarios to generate more series than 600, we just want the basic state to be below + // a threshold. + fmt.Sprintf(`avg_over_time(cluster:telemetry_selected_series:count[%s]) >= 600`, testDuration): false, + fmt.Sprintf(`max_over_time(cluster:telemetry_selected_series:count[%s]) >= 1200`, testDuration): false, } - helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + err := helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + o.Expect(err).NotTo(o.HaveOccurred()) e2e.Logf("Total number of series sent via telemetry is below the limit") }) - }) var _ = g.Describe("[sig-instrumentation] Prometheus", func() { @@ -129,14 +140,13 @@ var _ = g.Describe("[sig-instrumentation] Prometheus", func() { }) g.Describe("when installed on the cluster", func() { - g.It("should report telemetry if a cloud.openshift.com token is present", func() { + g.It("should report telemetry if a cloud.openshift.com token is present [Late]", func() { if !hasPullSecret(oc.AdminKubeClient(), "cloud.openshift.com") { e2eskipper.Skipf("Telemetry is disabled") } - oc.SetupProject() - ns := oc.Namespace() + ns := oc.SetupNamespace() - execPod := exutil.CreateUbiExecPodOrFail(oc.AdminKubeClient(), ns, "execpod", nil) + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() @@ -152,15 +162,15 @@ var _ = g.Describe("[sig-instrumentation] Prometheus", func() { // should have scraped some metrics from prometheus `federate_samples{job="telemeter-client"} >= 10`: true, } - helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + err := helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + o.Expect(err).NotTo(o.HaveOccurred()) e2e.Logf("Telemetry is enabled: %s", bearerToken) }) g.It("should start and expose a secured proxy and unsecured metrics", func() { - oc.SetupProject() - ns := oc.Namespace() - execPod := exutil.CreateUbiExecPodOrFail(oc.AdminKubeClient(), ns, "execpod", nil) + ns := oc.SetupNamespace() + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() @@ -285,9 +295,8 @@ var _ = g.Describe("[sig-instrumentation] Prometheus", func() { o.Expect(insecureTargets).To(o.BeEmpty(), "some services expose metrics over insecure channel") }) g.It("should have a AlertmanagerReceiversNotConfigured alert in firing state", func() { - oc.SetupProject() - ns := oc.Namespace() - execPod := exutil.CreateUbiExecPodOrFail(oc.AdminKubeClient(), ns, "execpod", nil) + ns := oc.SetupNamespace() + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() @@ -295,14 +304,15 @@ var _ = g.Describe("[sig-instrumentation] Prometheus", func() { tests := map[string]bool{ `ALERTS{alertstate=~"firing|pending",alertname="AlertmanagerReceiversNotConfigured"} == 1`: true, } - helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + err := helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + o.Expect(err).NotTo(o.HaveOccurred()) e2e.Logf("AlertmanagerReceiversNotConfigured alert is firing") }) g.It("should have important platform topology metrics", func() { oc.SetupProject() ns := oc.Namespace() - execPod := exutil.CreateUbiExecPodOrFail(oc.AdminKubeClient(), ns, "execpod", nil) + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() @@ -322,12 +332,12 @@ var _ = g.Describe("[sig-instrumentation] Prometheus", func() { `sum(node_role_os_version_machine:cpu_capacity_cores:sum{label_kubernetes_io_arch!="",label_node_role_kubernetes_io_master!=""}) > 0`: true, `sum(node_role_os_version_machine:cpu_capacity_sockets:sum{label_kubernetes_io_arch!="",label_node_hyperthread_enabled!="",label_node_role_kubernetes_io_master!=""}) > 0`: true, } - helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + err := helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + o.Expect(err).NotTo(o.HaveOccurred()) }) g.It("should have non-Pod host cAdvisor metrics", func() { - oc.SetupProject() - ns := oc.Namespace() - execPod := exutil.CreateUbiExecPodOrFail(oc.AdminKubeClient(), ns, "execpod", nil) + ns := oc.SetupNamespace() + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() @@ -335,26 +345,30 @@ var _ = g.Describe("[sig-instrumentation] Prometheus", func() { tests := map[string]bool{ `container_cpu_usage_seconds_total{id!~"/kubepods.slice/.*"} >= 1`: true, } - helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + err := helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + o.Expect(err).NotTo(o.HaveOccurred()) }) g.It("shouldn't have failing rules evaluation", func() { oc.SetupProject() ns := oc.Namespace() - execPod := exutil.CreateUbiExecPodOrFail(oc.AdminKubeClient(), ns, "execpod", nil) + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() + // we only consider samples since the beginning of the test + testDuration := exutil.DurationSinceStartInSeconds().String() + tests := map[string]bool{ - `prometheus_rule_evaluation_failures_total >= 1`: false, + fmt.Sprintf(`increase(prometheus_rule_evaluation_failures_total[%s]) >= 1`, testDuration): false, } - helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + err := helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + o.Expect(err).NotTo(o.HaveOccurred()) }) networking.InOpenShiftSDNContext(func() { g.It("should be able to get the sdn ovs flows", func() { - oc.SetupProject() - ns := oc.Namespace() - execPod := exutil.CreateUbiExecPodOrFail(oc.AdminKubeClient(), ns, "execpod", nil) + ns := oc.SetupNamespace() + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() @@ -363,16 +377,16 @@ var _ = g.Describe("[sig-instrumentation] Prometheus", func() { //something `openshift_sdn_ovs_flows >= 1`: true, } - helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + err := helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + o.Expect(err).NotTo(o.HaveOccurred()) }) }) g.It("shouldn't report any alerts in firing state apart from Watchdog and AlertmanagerReceiversNotConfigured [Early]", func() { if len(os.Getenv("TEST_UNSUPPORTED_ALLOW_VERSION_SKEW")) > 0 { e2eskipper.Skipf("Test is disabled to allow cluster components to have different versions, and skewed versions trigger multiple other alerts") } - oc.SetupProject() - ns := oc.Namespace() - execPod := exutil.CreateUbiExecPodOrFail(oc.AdminKubeClient(), ns, "execpod", nil) + ns := oc.SetupNamespace() + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() @@ -381,13 +395,13 @@ var _ = g.Describe("[sig-instrumentation] Prometheus", func() { // Checking Watchdog alert state is done in "should have a Watchdog alert in firing state". `ALERTS{alertname!~"Watchdog|AlertmanagerReceiversNotConfigured|PrometheusRemoteWriteDesiredShards",alertstate="firing",severity!="info"} >= 1`: false, } - helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + err := helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + o.Expect(err).NotTo(o.HaveOccurred()) }) g.It("should provide ingress metrics", func() { - oc.SetupProject() - ns := oc.Namespace() + ns := oc.SetupNamespace() - execPod := exutil.CreateUbiExecPodOrFail(oc.AdminKubeClient(), ns, "execpod", nil) + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() @@ -418,11 +432,11 @@ var _ = g.Describe("[sig-instrumentation] Prometheus", func() { `template_router_reload_seconds_count{job="router-internal-default"} >= 1`: true, `haproxy_server_up{job="router-internal-default"} >= 1`: true, } - helper.RunQueries(queries, oc, ns, execPod.Name, url, bearerToken) + err := helper.RunQueries(queries, oc, ns, execPod.Name, url, bearerToken) + o.Expect(err).NotTo(o.HaveOccurred()) }) g.It("should provide named network metrics", func() { - oc.SetupProject() - ns := oc.Namespace() + ns := oc.SetupNamespace() cs, err := newDynClientSet() o.Expect(err).NotTo(o.HaveOccurred()) @@ -434,7 +448,7 @@ var _ = g.Describe("[sig-instrumentation] Prometheus", func() { o.Expect(err).NotTo(o.HaveOccurred()) }() - execPod := exutil.CreateUbiExecPodOrFail(oc.AdminKubeClient(), ns, "execpod", func(pod *v1.Pod) { + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod", func(pod *v1.Pod) { pod.Annotations = map[string]string{ "k8s.v1.cni.cncf.io/networks": "secondary", } @@ -449,7 +463,8 @@ var _ = g.Describe("[sig-instrumentation] Prometheus", func() { fmt.Sprintf(`pod_network_name_info{pod="%s",namespace="%s",interface="eth0"} == 0`, execPod.Name, execPod.Namespace): true, fmt.Sprintf(`pod_network_name_info{pod="%s",namespace="%s",network_name="%s/secondary"} == 0`, execPod.Name, execPod.Namespace, ns): true, } - helper.RunQueries(queries, oc, ns, execPod.Name, url, bearerToken) + err = helper.RunQueries(queries, oc, ns, execPod.Name, url, bearerToken) + o.Expect(err).NotTo(o.HaveOccurred()) }) }) }) diff --git a/test/extended/prometheus/prometheus_builds.go b/test/extended/prometheus/prometheus_builds.go index 7d4464c4f569..5be6d0927750 100644 --- a/test/extended/prometheus/prometheus_builds.go +++ b/test/extended/prometheus/prometheus_builds.go @@ -52,7 +52,7 @@ var _ = g.Describe("[sig-instrumentation][sig-builds][Feature:Builds] Prometheus ns := oc.Namespace() appTemplate := exutil.FixturePath("testdata", "builds", "build-pruning", "successful-build-config.yaml") - execPod := exutil.CreateUbiExecPodOrFail(oc.AdminKubeClient(), ns, "execpod", nil) + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() @@ -79,7 +79,8 @@ var _ = g.Describe("[sig-instrumentation][sig-builds][Feature:Builds] Prometheus terminalTests := map[string]bool{ buildCountMetricName: true, } - helper.RunQueries(terminalTests, oc, ns, execPod.Name, url, bearerToken) + err = helper.RunQueries(terminalTests, oc, ns, execPod.Name, url, bearerToken) + o.Expect(err).NotTo(o.HaveOccurred()) // NOTE: in manual testing on a laptop, starting several serial builds in succession was sufficient for catching // at least a few builds in new/pending state with the default prometheus query interval; but that has not diff --git a/test/extended/prometheus/storage.go b/test/extended/prometheus/storage.go new file mode 100644 index 000000000000..492ba57bcc1e --- /dev/null +++ b/test/extended/prometheus/storage.go @@ -0,0 +1,76 @@ +package prometheus + +import ( + "context" + "fmt" + + g "github.com/onsi/ginkgo" + "github.com/openshift/origin/pkg/test/ginkgo/result" + exutil "github.com/openshift/origin/test/extended/util" + helper "github.com/openshift/origin/test/extended/util/prometheus" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + e2e "k8s.io/kubernetes/test/e2e/framework" +) + +const ( + // storage_operation_duration_seconds_bucket with the mount operations that are considered acceptable. + expectedMountTimeSeconds = 120 + // storage_operation_duration_seconds_bucket with the attach operations that are considered acceptable. + expectedAttachTimeSeconds = 120 +) + +var _ = g.Describe("[sig-storage][Late] Metrics", func() { + defer g.GinkgoRecover() + var ( + oc = exutil.NewCLIWithoutNamespace("prometheus") + + url, bearerToken string + ) + + g.BeforeEach(func() { + var ok bool + url, bearerToken, ok = helper.LocatePrometheus(oc) + if !ok { + e2e.Failf("Prometheus could not be located on this cluster, failing prometheus test") + } + }) + g.It("should report short attach times", func() { + checkOperation(oc, url, bearerToken, "kube-controller-manager", "volume_attach", expectedAttachTimeSeconds) + }) + g.It("should report short mount times", func() { + checkOperation(oc, url, bearerToken, "kubelet", "volume_mount", expectedMountTimeSeconds) + }) +}) + +func checkOperation(oc *exutil.CLI, url string, bearerToken string, component string, name string, threshold int) { + plugins := []string{"kubernetes.io/azure-disk", "kubernetes.io/aws-ebs", "kubernetes.io/gce-pd", "kubernetes.io/cinder", "kubernetes.io/vsphere-volume"} + ns := oc.SetupNamespace() + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") + defer func() { + oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) + }() + + // we only consider series sent since the beginning of the test + testDuration := exutil.DurationSinceStartInSeconds().String() + + tests := map[string]bool{} + // Check "[total nr. of ops] - [nr. of ops < threshold] > 0' and expect failure (all ops should be < threshold). + // Using sum(max(...)) to sum all kubelets / controller-managers + // Adding a comment to make the failure more readable. + e2e.Logf("Checking that Operation %s time of plugin %s should be <= %d seconds", name, plugins, threshold) + queryTemplate := ` +# Operation %[4]s time of plugin %[1]s should be < %[2]d seconds + sum(max_over_time(storage_operation_duration_seconds_bucket{job="%[3]s",le="+Inf",operation_name="%[4]s",volume_plugin="%[1]s"}[%[5]s])) +- sum(max_over_time(storage_operation_duration_seconds_bucket{job="%[3]s",le="%[2]d",operation_name="%[4]s",volume_plugin="%[1]s"}[%[5]s])) +> 0` + for _, plugin := range plugins { + query := fmt.Sprintf(queryTemplate, plugin, threshold, component, name, testDuration) + // Expect failure of the query (the result should be 0, all ops are expected to take < threshold) + tests[query] = false + } + + err := helper.RunQueries(tests, oc, ns, execPod.Name, url, bearerToken) + if err != nil { + result.Flakef("Operation %s of plugin %s took more than %d seconds: %s", name, plugins, threshold, err) + } +} diff --git a/test/extended/quota/clusterquota.go b/test/extended/quota/clusterquota.go index a0f39379a6f5..07ebe2a53c34 100644 --- a/test/extended/quota/clusterquota.go +++ b/test/extended/quota/clusterquota.go @@ -12,8 +12,10 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilversion "k8s.io/apimachinery/pkg/util/version" utilwait "k8s.io/apimachinery/pkg/util/wait" corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + "k8s.io/kubernetes/test/e2e/framework" imagev1 "github.com/openshift/api/image/v1" quotav1 "github.com/openshift/api/quota/v1" @@ -27,7 +29,23 @@ var _ = g.Describe("[sig-api-machinery][Feature:ClusterResourceQuota]", func() { g.Describe("Cluster resource quota", func() { g.It(fmt.Sprintf("should control resource limits across namespaces"), func() { - t := g.GinkgoT() + t := g.GinkgoT(1) + + versionInfo, err := oc.KubeClient().Discovery().ServerVersion() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + const kubeRootCAName = "kube-root-ca.crt" + version, err := utilversion.ParseSemantic(versionInfo.String()) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + expectKubeRootCACM := version.AtLeast(utilversion.MustParseGeneric("1.20")) + namespaceInitialCMCount := 0 + if expectKubeRootCACM { + framework.Logf("server version %q is higher or equal to 1.20, expecting ConfigMap %q to be present", versionInfo, kubeRootCAName) + namespaceInitialCMCount = 1 + } clusterAdminKubeClient := oc.AdminKubeClient() clusterAdminQuotaClient := oc.AdminQuotaClient() @@ -48,6 +66,13 @@ var _ = g.Describe("[sig-api-machinery][Feature:ClusterResourceQuota]", func() { }, }, } + + if expectKubeRootCACM { + q := cq.Spec.Quota.Hard[corev1.ResourceConfigMaps] + q.Add(resource.MustParse("2")) + cq.Spec.Quota.Hard[corev1.ResourceConfigMaps] = q + } + if _, err := clusterAdminQuotaClient.QuotaV1().ClusterResourceQuotas().Create(context.Background(), cq, metav1.CreateOptions{}); err != nil { t.Fatalf("unexpected error: %v", err) } @@ -55,6 +80,14 @@ var _ = g.Describe("[sig-api-machinery][Feature:ClusterResourceQuota]", func() { firstProjectName := oc.CreateProject() secondProjectName := oc.CreateProject() + if expectKubeRootCACM { + for _, ns := range []string{firstProjectName, secondProjectName} { + _, err = exutil.WaitForCMState(context.Background(), oc.KubeClient().CoreV1(), ns, kubeRootCAName, func(cm *corev1.ConfigMap) (bool, error) { + // Any event means the CM is present + return true, nil + }) + } + } if err := labelNamespace(clusterAdminKubeClient.CoreV1(), labelSelectorKey, firstProjectName); err != nil { t.Fatalf("unexpected error: %v", err) @@ -83,12 +116,13 @@ var _ = g.Describe("[sig-api-machinery][Feature:ClusterResourceQuota]", func() { t.Fatalf("unexpected error: %v", err) } if err := waitForQuotaStatus(clusterAdminQuotaClient, cq.Name, func(quota *quotav1.ClusterResourceQuota) error { + expectedCount := int64(2*namespaceInitialCMCount + 1) q := quota.Status.Total.Used[corev1.ResourceConfigMaps] if i, ok := q.AsInt64(); ok { - if i == 1 { + if i == expectedCount { return nil } - return fmt.Errorf("%d != 1", i) + return fmt.Errorf("%d != %d", i, expectedCount) } return fmt.Errorf("quota=%+v AsInt64() failed", q) }); err != nil { @@ -98,12 +132,13 @@ var _ = g.Describe("[sig-api-machinery][Feature:ClusterResourceQuota]", func() { t.Fatalf("unexpected error: %v", err) } if err := waitForQuotaStatus(clusterAdminQuotaClient, cq.Name, func(quota *quotav1.ClusterResourceQuota) error { + expectedCount := int64(2*namespaceInitialCMCount + 2) q := quota.Status.Total.Used[corev1.ResourceConfigMaps] if i, ok := q.AsInt64(); ok { - if i == 2 { + if i == expectedCount { return nil } - return fmt.Errorf("%d != 1", i) + return fmt.Errorf("%d != %d", i, expectedCount) } return fmt.Errorf("quota=%+v AsInt64() failed", q) }); err != nil { diff --git a/test/extended/quota/resourcequota.go b/test/extended/quota/resourcequota.go new file mode 100644 index 000000000000..f3a37d3565e1 --- /dev/null +++ b/test/extended/quota/resourcequota.go @@ -0,0 +1,110 @@ +package quota + +import ( + "context" + "fmt" + "time" + + g "github.com/onsi/ginkgo" + o "github.com/onsi/gomega" + + imagev1 "github.com/openshift/api/image/v1" + exutil "github.com/openshift/origin/test/extended/util" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilwait "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" +) + +var _ = g.Describe("[sig-api-machinery][Feature:ResourceQuota]", func() { + defer g.GinkgoRecover() + oc := exutil.NewCLI("object-count-rq") + + g.Describe("Object count", func() { + g.It(fmt.Sprintf("should properly count the number of imagestreams resources"), func() { + clusterAdminKubeClient := oc.AdminKubeClient() + clusterAdminImageClient := oc.AdminImageClient().ImageV1() + testProject := oc.CreateProject() + testResourceQuotaName := "count-imagestreams" + + rq := &corev1.ResourceQuota{ + ObjectMeta: metav1.ObjectMeta{Name: testResourceQuotaName, Namespace: testProject}, + Spec: corev1.ResourceQuotaSpec{ + Hard: corev1.ResourceList{ + "openshift.io/imagestreams": resource.MustParse("10"), + }, + }, + } + + _, err := clusterAdminKubeClient.CoreV1().ResourceQuotas(testProject).Create(context.Background(), rq, metav1.CreateOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + waitForResourceQuotaStatus(clusterAdminKubeClient, testResourceQuotaName, testProject, func(actualResourceQuota *corev1.ResourceQuota) error { + if !equality.Semantic.DeepEqual(actualResourceQuota.Spec.Hard, actualResourceQuota.Status.Hard) { + return fmt.Errorf("%#v != %#v", actualResourceQuota.Spec.Hard, actualResourceQuota.Status.Hard) + } + expectedUsedStatus := corev1.ResourceList{ + "openshift.io/imagestreams": resource.MustParse("0"), + } + if !equality.Semantic.DeepEqual(actualResourceQuota.Status.Used, expectedUsedStatus) { + return fmt.Errorf("unexpected current total usage: actul: %#v, expected: %#v", actualResourceQuota.Status.Used, expectedUsedStatus) + } + return nil + }) + + g.By("creating an image stream and checking the usage") + imageStream := &imagev1.ImageStream{ + ObjectMeta: metav1.ObjectMeta{Name: "empty-is"}, + } + _, err = clusterAdminImageClient.ImageStreams(testProject).Create(context.Background(), imageStream, metav1.CreateOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + err = waitForResourceQuotaStatus(clusterAdminKubeClient, testResourceQuotaName, testProject, func(actualResourceQuota *corev1.ResourceQuota) error { + expectedUsedStatus := corev1.ResourceList{ + "openshift.io/imagestreams": resource.MustParse("1"), + } + if !equality.Semantic.DeepEqual(actualResourceQuota.Status.Used, expectedUsedStatus) { + return fmt.Errorf("unexpected current total usage: actual: %#v, expected: %#v", actualResourceQuota.Status.Used, expectedUsedStatus) + } + return nil + }) + o.Expect(err).NotTo(o.HaveOccurred()) + + g.By("deleting the image stream and checking the usage") + err = clusterAdminImageClient.ImageStreams(testProject).Delete(context.Background(), imageStream.Name, metav1.DeleteOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + err = waitForResourceQuotaStatus(clusterAdminKubeClient, testResourceQuotaName, testProject, func(actualResourceQuota *corev1.ResourceQuota) error { + expectedUsedStatus := corev1.ResourceList{ + "openshift.io/imagestreams": resource.MustParse("0"), + } + if !equality.Semantic.DeepEqual(actualResourceQuota.Status.Used, expectedUsedStatus) { + return fmt.Errorf("unexpected current total usage: actual: %v, expected: %v", actualResourceQuota.Status.Used, expectedUsedStatus) + } + return nil + }) + o.Expect(err).NotTo(o.HaveOccurred()) + }) + }) +}) + +func waitForResourceQuotaStatus(clusterAdminKubeClient kubernetes.Interface, name string, namespace string, conditionFn func(*corev1.ResourceQuota) error) error { + var pollErr error + err := utilwait.PollImmediate(100*time.Millisecond, 30*time.Second, func() (done bool, err error) { + quota, err := clusterAdminKubeClient.CoreV1().ResourceQuotas(namespace).Get(context.Background(), name, metav1.GetOptions{}) + if err != nil { + pollErr = err + return false, nil + } + err = conditionFn(quota) + if err == nil { + return true, nil + } + pollErr = err + return false, nil + }) + if err != nil { + err = fmt.Errorf("%s: %s", err, pollErr) + } + return err +} diff --git a/test/extended/router/config_manager.go b/test/extended/router/config_manager.go index 9269a4bc5caa..a1bb7da85fb8 100644 --- a/test/extended/router/config_manager.go +++ b/test/extended/router/config_manager.go @@ -55,9 +55,9 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { g.It("should serve the correct routes when running with the haproxy config manager", func() { g.Skip("TODO: This test is flaking, fix it") ns := oc.KubeFramework().Namespace.Name - execPodName := exutil.CreateExecPodOrFail(oc.AdminKubeClient().CoreV1(), ns, "execpod") + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { - oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPodName, *metav1.NewDeleteOptions(1)) + oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() g.By(fmt.Sprintf("creating a router with haproxy config manager from a config file %q", configPath)) @@ -78,15 +78,15 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { g.By("waiting for the healthz endpoint to respond") healthzURI := fmt.Sprintf("http://%s:1936/healthz", routerIP) - err = waitForRouterOKResponseExec(ns, execPodName, healthzURI, routerIP, timeoutSeconds) + err = waitForRouterOKResponseExec(ns, execPod.Name, healthzURI, routerIP, timeoutSeconds) o.Expect(err).NotTo(o.HaveOccurred()) g.By("waiting for the valid routes to respond") - err = waitForRouteToRespond(ns, execPodName, "http", "insecure.hapcm.test", "/", routerIP, 0) + err = waitForRouteToRespond(ns, execPod.Name, "http", "insecure.hapcm.test", "/", routerIP, 0) o.Expect(err).NotTo(o.HaveOccurred()) for _, host := range []string{"edge.allow.hapcm.test", "reencrypt.hapcm.test", "passthrough.hapcm.test"} { - err = waitForRouteToRespond(ns, execPodName, "https", host, "/", routerIP, 0) + err = waitForRouteToRespond(ns, execPod.Name, "https", host, "/", routerIP, 0) o.Expect(err).NotTo(o.HaveOccurred()) } @@ -97,7 +97,7 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { err := oc.AsAdmin().Run("expose").Args("service", "insecure-service", "--name", name, "--hostname", hostName, "--labels", "select=haproxy-cfgmgr").Execute() o.Expect(err).NotTo(o.HaveOccurred()) - err = waitForRouteToRespond(ns, execPodName, "http", hostName, "/", routerIP, 0) + err = waitForRouteToRespond(ns, execPod.Name, "http", hostName, "/", routerIP, 0) o.Expect(err).NotTo(o.HaveOccurred()) err = oc.AsAdmin().Run("delete").Args("route", name).Execute() @@ -117,7 +117,7 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { err = oc.AsAdmin().Run("label").Args("route", name, "select=haproxy-cfgmgr").Execute() o.Expect(err).NotTo(o.HaveOccurred()) - err = waitForRouteToRespond(ns, execPodName, "https", hostName, "/", routerIP, 0) + err = waitForRouteToRespond(ns, execPod.Name, "https", hostName, "/", routerIP, 0) o.Expect(err).NotTo(o.HaveOccurred()) err = oc.AsAdmin().Run("delete").Args("route", name).Execute() diff --git a/test/extended/router/headers.go b/test/extended/router/headers.go index 3158a3beee9c..0b16ef2defab 100644 --- a/test/extended/router/headers.go +++ b/test/extended/router/headers.go @@ -68,9 +68,9 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { }() ns := oc.KubeFramework().Namespace.Name - execPodName := exutil.CreateExecPodOrFail(oc.AdminKubeClient().CoreV1(), ns, "execpod") + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { - oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPodName, *metav1.NewDeleteOptions(1)) + oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() g.By(fmt.Sprintf("creating an http echo server from a config file %q", configPath)) @@ -98,17 +98,17 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { g.By("waiting for the healthz endpoint to respond") healthzURI := fmt.Sprintf("http://%s:1936/healthz", metricsIP) - err = waitForRouterOKResponseExec(ns, execPodName, healthzURI, metricsIP, changeTimeoutSeconds) + err = waitForRouterOKResponseExec(ns, execPod.Name, healthzURI, metricsIP, changeTimeoutSeconds) o.Expect(err).NotTo(o.HaveOccurred()) host := "router-headers.example.com" g.By(fmt.Sprintf("waiting for the route to become active")) - err = waitForRouterOKResponseExec(ns, execPodName, routerURL, host, changeTimeoutSeconds) + err = waitForRouterOKResponseExec(ns, execPod.Name, routerURL, host, changeTimeoutSeconds) o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("making a request and reading back the echoed headers")) var payload string - payload, err = getRoutePayloadExec(ns, execPodName, routerURL, host) + payload, err = getRoutePayloadExec(ns, execPod.Name, routerURL, host) o.Expect(err).NotTo(o.HaveOccurred()) // The trailing \n is being stripped, so add it back diff --git a/test/extended/router/metrics.go b/test/extended/router/metrics.go index cd6b5f0e669b..482782fe6c85 100644 --- a/test/extended/router/metrics.go +++ b/test/extended/router/metrics.go @@ -96,7 +96,7 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { g.Describe("The HAProxy router", func() { g.It("should expose a health check on the metrics port", func() { - execPodName = exutil.CreateExecPodOrFail(oc.AdminKubeClient().CoreV1(), ns, "execpod") + execPodName = exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod").Name defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPodName, *metav1.NewDeleteOptions(1)) }() @@ -112,7 +112,7 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { err := oc.Run("create").Args("-f", configPath).Execute() o.Expect(err).NotTo(o.HaveOccurred()) - execPodName = exutil.CreateExecPodOrFail(oc.AdminKubeClient().CoreV1(), ns, "execpod") + execPodName = exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod").Name defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPodName, *metav1.NewDeleteOptions(1)) }() @@ -288,7 +288,7 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { }) g.It("should expose the profiling endpoints", func() { - execPodName = exutil.CreateExecPodOrFail(oc.AdminKubeClient().CoreV1(), ns, "execpod") + execPodName = exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod").Name defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPodName, *metav1.NewDeleteOptions(1)) }() @@ -309,7 +309,7 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { g.Skip("prometheus not found on this cluster") } - execPod := exutil.CreateUbiExecPodOrFail(oc.AdminKubeClient(), ns, "execpod", nil) + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() diff --git a/test/extended/router/reencrypt.go b/test/extended/router/reencrypt.go index 67ef4fc6242f..de5f098347f1 100644 --- a/test/extended/router/reencrypt.go +++ b/test/extended/router/reencrypt.go @@ -50,9 +50,9 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { g.It("should support reencrypt to services backed by a serving certificate automatically", func() { routerURL := fmt.Sprintf("https://%s", ip) - execPodName := exutil.CreateExecPodOrFail(oc.AdminKubeClient().CoreV1(), ns, "execpod") + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { - oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPodName, *metav1.NewDeleteOptions(1)) + oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() g.By(fmt.Sprintf("deploying a service using a reencrypt route without a destinationCACertificate")) err := oc.Run("create").Args("-f", configPath).Execute() @@ -73,7 +73,7 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { o.Expect(err).NotTo(o.HaveOccurred()) // don't assume the router is available via external DNS, because of complexity - err = waitForRouterOKResponseExec(ns, execPodName, routerURL, hostname, changeTimeoutSeconds) + err = waitForRouterOKResponseExec(ns, execPod.Name, routerURL, hostname, changeTimeoutSeconds) o.Expect(err).NotTo(o.HaveOccurred()) }) }) diff --git a/test/extended/router/scoped.go b/test/extended/router/scoped.go index bf5817d32e02..b73c38572bcf 100644 --- a/test/extended/router/scoped.go +++ b/test/extended/router/scoped.go @@ -67,9 +67,9 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { o.Expect(err).NotTo(o.HaveOccurred()) ns := oc.KubeFramework().Namespace.Name - execPodName := exutil.CreateExecPodOrFail(oc.AdminKubeClient().CoreV1(), ns, "execpod") + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { - oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPodName, *metav1.NewDeleteOptions(1)) + oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() var routerIP string @@ -91,16 +91,16 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { g.By("waiting for the healthz endpoint to respond") healthzURI := fmt.Sprintf("http://%s:1936/healthz", routerIP) - err = waitForRouterOKResponseExec(ns, execPodName, healthzURI, routerIP, changeTimeoutSeconds) + err = waitForRouterOKResponseExec(ns, execPod.Name, healthzURI, routerIP, changeTimeoutSeconds) o.Expect(err).NotTo(o.HaveOccurred()) g.By("waiting for the valid route to respond") - err = waitForRouterOKResponseExec(ns, execPodName, routerURL+"/Letter", "FIRST.example.com", changeTimeoutSeconds) + err = waitForRouterOKResponseExec(ns, execPod.Name, routerURL+"/Letter", "FIRST.example.com", changeTimeoutSeconds) o.Expect(err).NotTo(o.HaveOccurred()) for _, host := range []string{"second.example.com", "third.example.com"} { g.By(fmt.Sprintf("checking that %s does not match a route", host)) - err = expectRouteStatusCodeExec(ns, execPodName, routerURL+"/Letter", host, http.StatusServiceUnavailable) + err = expectRouteStatusCodeExec(ns, execPod.Name, routerURL+"/Letter", host, http.StatusServiceUnavailable) o.Expect(err).NotTo(o.HaveOccurred()) } }) @@ -113,9 +113,9 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { o.Expect(err).NotTo(o.HaveOccurred()) ns := oc.KubeFramework().Namespace.Name - execPodName := exutil.CreateExecPodOrFail(oc.AdminKubeClient().CoreV1(), ns, "execpod") + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { - oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPodName, *metav1.NewDeleteOptions(1)) + oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() var routerIP string @@ -139,22 +139,22 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { g.By("waiting for the healthz endpoint to respond") healthzURI := fmt.Sprintf("http://%s:1936/healthz", routerIP) - err = waitForRouterOKResponseExec(ns, execPodName, healthzURI, routerIP, changeTimeoutSeconds) + err = waitForRouterOKResponseExec(ns, execPod.Name, healthzURI, routerIP, changeTimeoutSeconds) o.Expect(err).NotTo(o.HaveOccurred()) g.By("waiting for the valid route to respond") - err = waitForRouterOKResponseExec(ns, execPodName, routerURL+"/Letter", fmt.Sprintf(pattern, "route-1", ns), changeTimeoutSeconds) + err = waitForRouterOKResponseExec(ns, execPod.Name, routerURL+"/Letter", fmt.Sprintf(pattern, "route-1", ns), changeTimeoutSeconds) o.Expect(err).NotTo(o.HaveOccurred()) g.By("checking that the stored domain name does not match a route") host := "first.example.com" - err = expectRouteStatusCodeExec(ns, execPodName, routerURL+"/Letter", host, http.StatusServiceUnavailable) + err = expectRouteStatusCodeExec(ns, execPod.Name, routerURL+"/Letter", host, http.StatusServiceUnavailable) o.Expect(err).NotTo(o.HaveOccurred()) for _, host := range []string{"route-1", "route-2"} { host = fmt.Sprintf(pattern, host, ns) g.By(fmt.Sprintf("checking that %s matches a route", host)) - err = expectRouteStatusCodeExec(ns, execPodName, routerURL+"/Letter", host, http.StatusOK) + err = expectRouteStatusCodeExec(ns, execPod.Name, routerURL+"/Letter", host, http.StatusOK) o.Expect(err).NotTo(o.HaveOccurred()) } @@ -178,9 +178,9 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { o.Expect(err).NotTo(o.HaveOccurred()) ns := oc.KubeFramework().Namespace.Name - execPodName := exutil.CreateExecPodOrFail(oc.AdminKubeClient().CoreV1(), ns, "execpod") + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { - oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPodName, *metav1.NewDeleteOptions(1)) + oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() g.By(fmt.Sprintf("creating a scoped router with overridden domains from a config file %q", configPath)) @@ -206,22 +206,22 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { g.By("waiting for the healthz endpoint to respond") healthzURI := fmt.Sprintf("http://%s:1936/healthz", routerIP) - err = waitForRouterOKResponseExec(ns, execPodName, healthzURI, routerIP, changeTimeoutSeconds) + err = waitForRouterOKResponseExec(ns, execPod.Name, healthzURI, routerIP, changeTimeoutSeconds) o.Expect(err).NotTo(o.HaveOccurred()) g.By("waiting for the valid route to respond") - err = waitForRouterOKResponseExec(ns, execPodName, routerURL+"/Letter", fmt.Sprintf(pattern, "route-override-domain-1", ns), changeTimeoutSeconds) + err = waitForRouterOKResponseExec(ns, execPod.Name, routerURL+"/Letter", fmt.Sprintf(pattern, "route-override-domain-1", ns), changeTimeoutSeconds) o.Expect(err).NotTo(o.HaveOccurred()) g.By("checking that the stored domain name does not match a route") host := "y.a.null.ptr" - err = expectRouteStatusCodeExec(ns, execPodName, routerURL+"/Letter", host, http.StatusServiceUnavailable) + err = expectRouteStatusCodeExec(ns, execPod.Name, routerURL+"/Letter", host, http.StatusServiceUnavailable) o.Expect(err).NotTo(o.HaveOccurred()) for _, host := range []string{"route-override-domain-1", "route-override-domain-2"} { host = fmt.Sprintf(pattern, host, ns) g.By(fmt.Sprintf("checking that %s matches a route", host)) - err = expectRouteStatusCodeExec(ns, execPodName, routerURL+"/Letter", host, http.StatusOK) + err = expectRouteStatusCodeExec(ns, execPod.Name, routerURL+"/Letter", host, http.StatusOK) o.Expect(err).NotTo(o.HaveOccurred()) } @@ -241,24 +241,31 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { func waitForRouterOKResponseExec(ns, execPodName, url, host string, timeoutSeconds int) error { cmd := fmt.Sprintf(` set -e - STOP=$(($(date '+%%s') + %d)) + pass=%[4]d + STOP=$(($(date '+%%s') + %[1]d)) while [ $(date '+%%s') -lt $STOP ]; do rc=0 - code=$( curl -k -s -m 5 -o /dev/null -w '%%{http_code}\n' --header 'Host: %s' %q ) || rc=$? + code=$( curl -k -s -m 5 -o /dev/null -w '%%{http_code}\n' --header 'Host: %[2]s' %[3]q ) || rc=$? if [[ "${rc:-0}" -eq 0 ]]; then echo $code if [[ $code -eq 200 ]]; then - exit 0 + pass=$(( pass - 1 )) + if [[ $pass -le 0 ]]; then + exit 0 + fi + sleep 1 + continue fi if [[ $code -ne 503 ]]; then exit 1 fi + pass=%[4]d else echo "error ${rc}" 1>&2 fi sleep 1 done - `, timeoutSeconds, host, url) + `, timeoutSeconds, host, url, 5) output, err := e2e.RunHostCmd(ns, execPodName, cmd) if err != nil { return fmt.Errorf("host command failed: %v\n%s", err, output) diff --git a/test/extended/router/unprivileged.go b/test/extended/router/unprivileged.go index e4de8018075d..c9725cf00894 100644 --- a/test/extended/router/unprivileged.go +++ b/test/extended/router/unprivileged.go @@ -64,9 +64,9 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { o.Expect(err).NotTo(o.HaveOccurred()) ns := oc.KubeFramework().Namespace.Name - execPodName := exutil.CreateExecPodOrFail(oc.AdminKubeClient().CoreV1(), ns, "execpod") + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { - oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPodName, *metav1.NewDeleteOptions(1)) + oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() var routerIP string @@ -88,16 +88,16 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { g.By("waiting for the healthz endpoint to respond") healthzURI := fmt.Sprintf("http://%s:1936/healthz", routerIP) - err = waitForRouterOKResponseExec(ns, execPodName, healthzURI, routerIP, changeTimeoutSeconds) + err = waitForRouterOKResponseExec(ns, execPod.Name, healthzURI, routerIP, changeTimeoutSeconds) o.Expect(err).NotTo(o.HaveOccurred()) g.By("waiting for the valid route to respond") - err = waitForRouterOKResponseExec(ns, execPodName, routerURL+"/Letter", "FIRST.example.com", changeTimeoutSeconds) + err = waitForRouterOKResponseExec(ns, execPod.Name, routerURL+"/Letter", "FIRST.example.com", changeTimeoutSeconds) o.Expect(err).NotTo(o.HaveOccurred()) for _, host := range []string{"second.example.com", "third.example.com"} { g.By(fmt.Sprintf("checking that %s does not match a route", host)) - err = expectRouteStatusCodeExec(ns, execPodName, routerURL+"/Letter", host, http.StatusServiceUnavailable) + err = expectRouteStatusCodeExec(ns, execPod.Name, routerURL+"/Letter", host, http.StatusServiceUnavailable) o.Expect(err).NotTo(o.HaveOccurred()) } diff --git a/test/extended/router/weighted.go b/test/extended/router/weighted.go index 1ae4e9359127..ecf04494ba2c 100644 --- a/test/extended/router/weighted.go +++ b/test/extended/router/weighted.go @@ -44,9 +44,9 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { }() ns := oc.KubeFramework().Namespace.Name - execPodName := exutil.CreateExecPodOrFail(oc.AdminKubeClient().CoreV1(), ns, "execpod") + execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), ns, "execpod") defer func() { - oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPodName, *metav1.NewDeleteOptions(1)) + oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() g.By(fmt.Sprintf("creating a weighted router from a config file %q", configPath)) @@ -71,24 +71,24 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { g.By("waiting for the healthz endpoint to respond") healthzURI := fmt.Sprintf("http://%s:1936/healthz", routerIP) - err = waitForRouterOKResponseExec(ns, execPodName, healthzURI, routerIP, changeTimeoutSeconds) + err = waitForRouterOKResponseExec(ns, execPod.Name, healthzURI, routerIP, changeTimeoutSeconds) o.Expect(err).NotTo(o.HaveOccurred()) host := "weighted.example.com" times := 100 g.By(fmt.Sprintf("checking that %d requests go through successfully", times)) // wait for the request to stabilize - err = waitForRouterOKResponseExec(ns, execPodName, routerURL, "weighted.example.com", changeTimeoutSeconds) + err = waitForRouterOKResponseExec(ns, execPod.Name, routerURL, "weighted.example.com", changeTimeoutSeconds) o.Expect(err).NotTo(o.HaveOccurred()) // all requests should now succeed - err = expectRouteStatusCodeRepeatedExec(ns, execPodName, routerURL, "weighted.example.com", http.StatusOK, times, false) + err = expectRouteStatusCodeRepeatedExec(ns, execPod.Name, routerURL, "weighted.example.com", http.StatusOK, times, false) o.Expect(err).NotTo(o.HaveOccurred()) g.By(fmt.Sprintf("checking that there are three weighted backends in the router stats")) var trafficValues []string err = wait.PollImmediate(100*time.Millisecond, changeTimeoutSeconds*time.Second, func() (bool, error) { statsURL := fmt.Sprintf("http://%s:1936/;csv", routerIP) - stats, err := getAuthenticatedRouteURLViaPod(ns, execPodName, statsURL, host, "admin", "password") + stats, err := getAuthenticatedRouteURLViaPod(ns, execPod.Name, statsURL, host, "admin", "password") o.Expect(err).NotTo(o.HaveOccurred()) trafficValues, err = parseStats(stats, "weightedroute", 7) o.Expect(err).NotTo(o.HaveOccurred()) @@ -108,7 +108,7 @@ var _ = g.Describe("[sig-network][Feature:Router]", func() { g.By(fmt.Sprintf("checking that zero weights are also respected by the router")) host = "zeroweight.example.com" - err = expectRouteStatusCodeExec(ns, execPodName, routerURL, host, http.StatusServiceUnavailable) + err = expectRouteStatusCodeExec(ns, execPod.Name, routerURL, host, http.StatusServiceUnavailable) o.Expect(err).NotTo(o.HaveOccurred()) }) }) diff --git a/test/extended/security/fips.go b/test/extended/security/fips.go new file mode 100644 index 000000000000..9728825374a6 --- /dev/null +++ b/test/extended/security/fips.go @@ -0,0 +1,64 @@ +package security + +import ( + "context" + "fmt" + "strconv" + "strings" + + g "github.com/onsi/ginkgo" + o "github.com/onsi/gomega" + exutil "github.com/openshift/origin/test/extended/util" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + installConfigName = "cluster-config-v1" + fipsFile = "/proc/sys/crypto/fips_enabled" +) + +func validateFIPSOnNode(oc *exutil.CLI, fipsExpected bool, node *corev1.Node) error { + command := []string{"cat", fipsFile} + out, err := exutil.ExecCommandOnMachineConfigDaemon(oc.AdminKubeClient(), oc, node, command) + if err != nil { + return err + } + nodeFips, err := strconv.ParseBool(strings.TrimSuffix(string(out), "\n")) + if err != nil { + return fmt.Errorf("Error parsing %s on node %s: %v", fipsFile, node.Name, err) + } + if nodeFips != fipsExpected { + return fmt.Errorf("Expected FIPS state %v, found %v", fipsExpected, nodeFips) + } + return nil +} + +var _ = g.Describe("[sig-arch] [Conformance] FIPS", func() { + defer g.GinkgoRecover() + oc := exutil.NewCLI("fips") + + g.It("TestFIPS", func() { + clusterAdminKubeClientset := oc.AdminKubeClient() + isFIPS, err := exutil.IsFIPS(clusterAdminKubeClientset.CoreV1()) + o.Expect(err).NotTo(o.HaveOccurred()) + + // fetch one control plane and one worker, and validate FIPS state on it + masterNodes, err := clusterAdminKubeClientset.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{ + LabelSelector: "node-role.kubernetes.io/master", + }) + o.Expect(err).NotTo(o.HaveOccurred()) + masterNode := &masterNodes.Items[0] + err = validateFIPSOnNode(oc, isFIPS, masterNode) + o.Expect(err).NotTo(o.HaveOccurred()) + workerNodes, err := clusterAdminKubeClientset.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{ + LabelSelector: "node-role.kubernetes.io/worker", + }) + o.Expect(err).NotTo(o.HaveOccurred()) + if len(workerNodes.Items) > 0 { + workerNode := &workerNodes.Items[0] + err = validateFIPSOnNode(oc, isFIPS, workerNode) + o.Expect(err).NotTo(o.HaveOccurred()) + } + }) +}) diff --git a/test/extended/security/scc.go b/test/extended/security/scc.go index f26063f42122..3e8b15b00c63 100644 --- a/test/extended/security/scc.go +++ b/test/extended/security/scc.go @@ -5,10 +5,13 @@ import ( "strings" g "github.com/onsi/ginkgo" + o "github.com/onsi/gomega" + securityv1 "github.com/openshift/api/security/v1" securityv1client "github.com/openshift/client-go/security/clientset/versioned/typed/security/v1" "github.com/openshift/origin/test/extended/authorization" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" kubeauthorizationv1 "k8s.io/api/authorization/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -16,6 +19,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" rbacv1helpers "k8s.io/kubernetes/pkg/apis/rbac/v1" + "k8s.io/kubernetes/test/e2e/framework" ) var _ = g.Describe("[sig-auth][Feature:SecurityContextConstraints] ", func() { @@ -257,6 +261,32 @@ var _ = g.Describe("[sig-auth][Feature:SecurityContextConstraints] ", func() { }) }) +var _ = g.Describe("[sig-auth][Feature:SecurityContextConstraints] ", func() { + defer g.GinkgoRecover() + oc := exutil.NewCLI("ssc") + + g.It("TestPodDefaultCapabilities", func() { + g.By("Running a restricted pod and getting it's inherited capabilities") + pod, err := exutil.NewPodExecutor(oc, "restrictedcapsh", image.ShellImage()) + o.Expect(err).NotTo(o.HaveOccurred()) + + desiredCapabilities := "000000000000051b" + + capabilities, err := pod.Exec("cat /proc/1/status | grep CapInh | cut -f 2") + o.Expect(err).NotTo(o.HaveOccurred()) + + capString, err := pod.Exec("capsh --decode=" + capabilities) + o.Expect(err).NotTo(o.HaveOccurred()) + + desiredCapString, err := pod.Exec("capsh --decode=" + desiredCapabilities) + o.Expect(err).NotTo(o.HaveOccurred()) + + framework.Logf("comparing capabilities: %s with desired: %s", capabilities, desiredCapabilities) + framework.Logf("which translates to: %s compared with desired: %s", capString, desiredCapString) + o.Expect(capabilities).To(o.Equal(desiredCapabilities)) + }) +}) + func isForbiddenBySCC(err error) bool { return kapierror.IsForbidden(err) && strings.Contains(err.Error(), "unable to validate against any security context constraint") } @@ -269,6 +299,9 @@ func getPrivilegedPod(name string) *corev1.Pod { return &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{Name: name}, Spec: corev1.PodSpec{ + NodeSelector: map[string]string{ + "e2e.openshift.io/unschedulable": "should-not-run", + }, Containers: []corev1.Container{ {Name: "first", Image: "something-innocuous"}, }, diff --git a/test/extended/security/supplemental_groups.go b/test/extended/security/supplemental_groups.go index 5afd1f191e57..b2360a08d929 100644 --- a/test/extended/security/supplemental_groups.go +++ b/test/extended/security/supplemental_groups.go @@ -18,6 +18,7 @@ import ( e2epod "k8s.io/kubernetes/test/e2e/framework/pod" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" ) const ( @@ -103,7 +104,7 @@ func supGroupPod(fsGroup int64, supGroup int64) *kapiv1.Pod { Containers: []kapiv1.Container{ { Name: supplementalGroupsPod, - Image: "openshift/origin-pod", + Image: image.ShellImage(), }, }, }, diff --git a/test/extended/testdata/bindata.go b/test/extended/testdata/bindata.go index 6f34672b6ced..b0f3de192eec 100644 --- a/test/extended/testdata/bindata.go +++ b/test/extended/testdata/bindata.go @@ -11,7 +11,6 @@ // examples/db-templates/redis-ephemeral-template.json // examples/db-templates/redis-persistent-template.json // examples/image-streams/image-streams-centos7.json -// examples/image-streams/image-streams-rhel7.json // examples/sample-app/application-template-dockerbuild.json // examples/sample-app/application-template-pullspecbuild.json // examples/sample-app/application-template-stibuild.json @@ -131,6 +130,7 @@ // test/extended/testdata/builds/test-docker-build.json // test/extended/testdata/builds/test-docker-no-outputname.json // test/extended/testdata/builds/test-env-build.json +// test/extended/testdata/builds/test-image-stream.json // test/extended/testdata/builds/test-imagechangetriggers.yaml // test/extended/testdata/builds/test-imageresolution-custom-build.yaml // test/extended/testdata/builds/test-imageresolution-docker-build.yaml @@ -189,9 +189,7 @@ // test/extended/testdata/cmd/test/cmd/builds.sh // test/extended/testdata/cmd/test/cmd/completions.sh // test/extended/testdata/cmd/test/cmd/config.sh -// test/extended/testdata/cmd/test/cmd/convert.sh // test/extended/testdata/cmd/test/cmd/create.sh -// test/extended/testdata/cmd/test/cmd/debug.sh // test/extended/testdata/cmd/test/cmd/deployments.sh // test/extended/testdata/cmd/test/cmd/describer.sh // test/extended/testdata/cmd/test/cmd/edit.sh @@ -205,15 +203,12 @@ // test/extended/testdata/cmd/test/cmd/login.sh // test/extended/testdata/cmd/test/cmd/migrate.sh // test/extended/testdata/cmd/test/cmd/newapp.sh -// test/extended/testdata/cmd/test/cmd/observe.sh -// test/extended/testdata/cmd/test/cmd/policy-storage-admin.sh // test/extended/testdata/cmd/test/cmd/policy.sh // test/extended/testdata/cmd/test/cmd/printer.sh // test/extended/testdata/cmd/test/cmd/projects.sh // test/extended/testdata/cmd/test/cmd/quota.sh // test/extended/testdata/cmd/test/cmd/registry.sh // test/extended/testdata/cmd/test/cmd/routes.sh -// test/extended/testdata/cmd/test/cmd/rsync.sh // test/extended/testdata/cmd/test/cmd/run.sh // test/extended/testdata/cmd/test/cmd/secrets.sh // test/extended/testdata/cmd/test/cmd/services.sh @@ -224,22 +219,6 @@ // test/extended/testdata/cmd/test/cmd/setbuildsecret.sh // test/extended/testdata/cmd/test/cmd/status.sh // test/extended/testdata/cmd/test/cmd/templates.sh -// test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/app/Dockerfile -// test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.generated.yaml -// test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.imported.yaml -// test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.yml -// test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/nginx/Dockerfile -// test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/wordpress/docker-compose.yml -// test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-lonely-pod.json -// test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-sample-app.json -// test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-service-pod-no-rc.json -// test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-service-with-nothing.json -// test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-unserviced-rc.json -// test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-deployed-app.yaml -// test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-no-build.yaml -// test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-one-build.yaml -// test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-two-deployment-configs.yaml -// test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/petset.yaml // test/extended/testdata/cmd/test/cmd/testdata/application-template-custombuild.json // test/extended/testdata/cmd/test/cmd/testdata/application-template-dockerbuild.json // test/extended/testdata/cmd/test/cmd/testdata/application-template-stibuild.json @@ -278,13 +257,9 @@ // test/extended/testdata/cmd/test/cmd/testdata/resource-builder/directory/yml-with-extension.yml // test/extended/testdata/cmd/test/cmd/testdata/resource-builder/json-no-extension // test/extended/testdata/cmd/test/cmd/testdata/resource-builder/yml-no-extension -// test/extended/testdata/cmd/test/cmd/testdata/roles/empty-role.yaml -// test/extended/testdata/cmd/test/cmd/testdata/roles/policy-clusterroles.yaml -// test/extended/testdata/cmd/test/cmd/testdata/roles/policy-roles.yaml // test/extended/testdata/cmd/test/cmd/testdata/rollingupdate-daemonset.yaml // test/extended/testdata/cmd/test/cmd/testdata/services.yaml // test/extended/testdata/cmd/test/cmd/testdata/simple-deployment.yaml -// test/extended/testdata/cmd/test/cmd/testdata/stable-busybox.yaml // test/extended/testdata/cmd/test/cmd/testdata/statefulset.yaml // test/extended/testdata/cmd/test/cmd/testdata/templateinstance_objectkinds.yaml // test/extended/testdata/cmd/test/cmd/testdata/templates/basic-users-binding.json @@ -307,14 +282,10 @@ // test/extended/testdata/cmd/test/cmd/testdata/test-s2i-build.json // test/extended/testdata/cmd/test/cmd/testdata/test-service.json // test/extended/testdata/cmd/test/cmd/testdata/test-stream.yaml -// test/extended/testdata/cmd/test/cmd/timeout.sh // test/extended/testdata/cmd/test/cmd/triggers.sh // test/extended/testdata/cmd/test/cmd/volumes.sh // test/extended/testdata/cmd/test/cmd/whoami.sh // test/extended/testdata/config-map-jenkins-slave-pods.yaml -// test/extended/testdata/csi/aws-ebs/install-template.yaml -// test/extended/testdata/csi/aws-ebs/manifest.yaml -// test/extended/testdata/csi/aws-ebs/storageclass.yaml // test/extended/testdata/custom-secret-builder/Dockerfile // test/extended/testdata/custom-secret-builder/build.sh // test/extended/testdata/deployments/custom-deployment.yaml @@ -335,19 +306,6 @@ // test/extended/testdata/deployments/tag-images-deployment.yaml // test/extended/testdata/deployments/test-deployment-broken.yaml // test/extended/testdata/deployments/test-deployment-test.yaml -// test/extended/testdata/disaster-recovery/restore-etcd.sh -// test/extended/testdata/disaster-recovery/rollback-A.yaml -// test/extended/testdata/disaster-recovery/rollback-B.yaml -// test/extended/testdata/disaster-recovery/ssh-bastion/clusterrole.yaml -// test/extended/testdata/disaster-recovery/ssh-bastion/clusterrolebinding.yaml -// test/extended/testdata/disaster-recovery/ssh-bastion/deployment.yaml -// test/extended/testdata/disaster-recovery/ssh-bastion/namespace.yaml -// test/extended/testdata/disaster-recovery/ssh-bastion/role.yaml -// test/extended/testdata/disaster-recovery/ssh-bastion/rolebinding.yaml -// test/extended/testdata/disaster-recovery/ssh-bastion/service.yaml -// test/extended/testdata/disaster-recovery/ssh-bastion/serviceaccount.yaml -// test/extended/testdata/disaster-recovery/ssh-bastion/sshd_config -// test/extended/testdata/disaster-recovery/update_route_53.py // test/extended/testdata/forcepull-test.json // test/extended/testdata/gssapi/config/kubeconfig // test/extended/testdata/gssapi/config/oauth_config.json @@ -466,6 +424,7 @@ // test/extended/testdata/ldap/groupsync/rfc2307/valid_whitelist_union_sync.yaml // test/extended/testdata/ldap/groupsync/rfc2307/whitelist_ldap.txt // test/extended/testdata/ldap/groupsync/rfc2307/whitelist_openshift.txt +// test/extended/testdata/ldap/groupsync.sh // test/extended/testdata/ldap/ldapserver-config-cm.yaml // test/extended/testdata/ldap/ldapserver-deployment.yaml // test/extended/testdata/ldap/ldapserver-scripts-cm.yaml @@ -516,6 +475,7 @@ // test/extended/testdata/samplepipeline-withenvs.yaml // test/extended/testdata/service-serving-cert/nginx-serving-cert.conf // test/extended/testdata/signer-buildconfig.yaml +// test/extended/testdata/stable-busybox.yaml // test/extended/testdata/templates/crunchydata-pod.json // test/extended/testdata/templates/guestbook.json // test/extended/testdata/templates/guestbook_list.json @@ -524,21 +484,12 @@ // test/extended/testdata/templates/templateinstance_readiness.yaml // test/extended/testdata/templates/templateservicebroker_bind.yaml // test/extended/testdata/test-cli-debug.yaml +// test/extended/testdata/test-deployment-config.yaml // test/extended/testdata/test-env-pod.json // test/extended/testdata/test-gitserver.yaml +// test/extended/testdata/test-replication-controller.yaml // test/extended/testdata/test-secret.json // test/extended/testdata/verifyservice-pipeline-template.yaml -// test/integration/testdata/project-request-template-with-quota.yaml -// test/integration/testdata/test-buildcli-beta2.json -// test/integration/testdata/test-buildcli.json -// test/integration/testdata/test-deployment-config.yaml -// test/integration/testdata/test-image-stream-mapping.json -// test/integration/testdata/test-image-stream.json -// test/integration/testdata/test-image.json -// test/integration/testdata/test-replication-controller.yaml -// test/integration/testdata/test-route.json -// test/integration/testdata/test-service-with-finalizer.json -// test/integration/testdata/test-service.json package testdata import ( @@ -3452,56 +3403,59 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ "tags": [ { "annotations": { - "description": "Build and run .NET Core applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.1/build/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of .NET Core available on OpenShift, including major versions updates.", + "description": "Build and run .NET Core applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of .NET Core available on OpenShift, including major versions updates.", "iconClass": "icon-dotnet", "openshift.io/display-name": ".NET Core (Latest)", "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.1", + "sampleRef": "dotnetcore-3.1", "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", "supports": "dotnet", "tags": "builder,.net,dotnet,dotnetcore" }, "from": { "kind": "ImageStreamTag", - "name": "2.1" + "name": "3.1" }, - "name": "latest" + "name": "latest", + "referencePolicy": { + "type": "Local" + } }, { "annotations": { - "description": "Build and run .NET Core 2.1 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.0/build/README.md.", + "description": "Build and run .NET Core 2.2 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/blob/master/2.2/build/README.md.", "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 2.1", + "openshift.io/display-name": ".NET Core 2.2", "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.1", + "sampleRef": "dotnetcore-2.2", "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:2.1,dotnet", + "supports": "dotnet:2.2,dotnet", "tags": "builder,.net,dotnet,dotnetcore,rh-dotnet21", - "version": "2.1" + "version": "2.2" }, "from": { "kind": "DockerImage", - "name": "registry.centos.org/dotnet/dotnet-21-centos7:latest" + "name": "registry.centos.org/dotnet/dotnet-22-centos7:latest" }, - "name": "2.1" + "name": "2.2" }, { "annotations": { - "description": "RETIRED: Build and run .NET Core 2.0 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.0/build/README.md.", + "description": "Build and run .NET Core 3.1 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/blob/master/3.1/build/README.md.", "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 2.0", + "openshift.io/display-name": ".NET Core 3.1", "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.0", + "sampleRef": "dotnetcore-3.1", "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:2.0,dotnet", - "tags": "hidden,builder,.net,dotnet,dotnetcore,rh-dotnet20", - "version": "2.0" + "supports": "dotnet:3.1,dotnet", + "tags": "builder,.net,dotnet,dotnetcore,rh-dotnet21", + "version": "3.1" }, "from": { "kind": "DockerImage", - "name": "registry.centos.org/dotnet/dotnet-20-centos7:latest" + "name": "registry.centos.org/dotnet/dotnet-31-centos7:latest" }, - "name": "2.0" + "name": "3.1" } ] } @@ -3519,7 +3473,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ "tags": [ { "annotations": { - "description": "Build and serve static content via Apache HTTP Server (httpd) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/httpd-container/blob/master/2.4/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Httpd available on OpenShift, including major versions updates.", + "description": "Build and serve static content via Apache HTTP Server (httpd) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/httpd-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Httpd available on OpenShift, including major versions updates.", "iconClass": "icon-apache", "openshift.io/display-name": "Apache HTTP Server (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -3549,7 +3503,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/httpd-24-centos7:latest" + "name": "registry.centos.org/centos/httpd-24-centos7:latest" }, "name": "2.4", "referencePolicy": { @@ -3621,7 +3575,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ "tags": [ { "annotations": { - "description": "Provides a MariaDB database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.2/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MariaDB available on OpenShift, including major versions updates.", + "description": "Provides a MariaDB database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/blob/master/10.2/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MariaDB available on OpenShift, including major versions updates.", "iconClass": "icon-mariadb", "openshift.io/display-name": "MariaDB (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -3638,7 +3592,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, { "annotations": { - "description": "Provides a MariaDB 10.1 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.1/README.md.", + "description": "Provides a MariaDB 10.1 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/blob/master/10.1/README.md.", "iconClass": "icon-mariadb", "openshift.io/display-name": "MariaDB 10.1", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -3647,7 +3601,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mariadb-101-centos7:latest" + "name": "registry.centos.org/centos/mariadb-101-centos7:latest" }, "name": "10.1", "referencePolicy": { @@ -3656,7 +3610,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, { "annotations": { - "description": "Provides a MariaDB 10.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.2/README.md.", + "description": "Provides a MariaDB 10.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/blob/master/10.2/README.md.", "iconClass": "icon-mariadb", "openshift.io/display-name": "MariaDB 10.2", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -3665,7 +3619,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mariadb-102-centos7:latest" + "name": "registry.centos.org/centos/mariadb-102-centos7:latest" }, "name": "10.2", "referencePolicy": { @@ -3688,7 +3642,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ "tags": [ { "annotations": { - "description": "Provides a MongoDB database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.4/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MongoDB available on OpenShift, including major versions updates.", + "description": "Provides a MongoDB database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MongoDB available on OpenShift, including major versions updates.", "iconClass": "icon-mongodb", "openshift.io/display-name": "MongoDB (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -3696,7 +3650,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "ImageStreamTag", - "name": "3.6" + "name": "3.4" }, "name": "latest", "referencePolicy": { @@ -3705,25 +3659,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, { "annotations": { - "description": "Provides a MongoDB 2.4 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/2.4/README.md.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB 2.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,mongodb", - "version": "2.4" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/mongodb-24-centos7:latest" - }, - "name": "2.4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a MongoDB 2.6 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/2.6/README.md.", + "description": "Provides a MongoDB 2.6 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/blob/master/2.6/README.md.", "iconClass": "icon-mongodb", "openshift.io/display-name": "MongoDB 2.6", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -3732,7 +3668,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mongodb-26-centos7:latest" + "name": "registry.centos.org/centos/mongodb-26-centos7:latest" }, "name": "2.6", "referencePolicy": { @@ -3741,7 +3677,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, { "annotations": { - "description": "Provides a MongoDB 3.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.2/README.md.", + "description": "Provides a MongoDB 3.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/blob/master/3.2/README.md.", "iconClass": "icon-mongodb", "openshift.io/display-name": "MongoDB 3.2", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -3750,7 +3686,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mongodb-32-centos7:latest" + "name": "registry.centos.org/centos/mongodb-32-centos7:latest" }, "name": "3.2", "referencePolicy": { @@ -3759,7 +3695,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, { "annotations": { - "description": "Provides a MongoDB 3.4 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.4/README.md.", + "description": "Provides a MongoDB 3.4 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/blob/master/3.4/README.md.", "iconClass": "icon-mongodb", "openshift.io/display-name": "MongoDB 3.4", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -3768,30 +3704,12 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mongodb-34-centos7:latest" + "name": "registry.centos.org/centos/mongodb-34-centos7:latest" }, "name": "3.4", "referencePolicy": { "type": "Local" } - }, - { - "annotations": { - "description": "Provides a MongoDB 3.6 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.6/README.md.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB 3.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,mongodb", - "version": "3.6" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/mongodb-36-centos7:latest" - }, - "name": "3.6", - "referencePolicy": { - "type": "Local" - } } ] } @@ -3824,24 +3742,6 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ "type": "Local" } }, - { - "annotations": { - "description": "Provides a MySQL 5.5 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/README.md.", - "iconClass": "icon-mysql-database", - "openshift.io/display-name": "MySQL 5.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,mysql", - "version": "5.5" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/mysql-55-centos7:latest" - }, - "name": "5.5", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Provides a MySQL 5.6 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/README.md.", @@ -3853,7 +3753,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mysql-56-centos7:latest" + "name": "registry.centos.org/centos/mysql-56-centos7:latest" }, "name": "5.6", "referencePolicy": { @@ -3871,7 +3771,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mysql-57-centos7:latest" + "name": "registry.centos.org/centos/mysql-57-centos7:latest" }, "name": "5.7", "referencePolicy": { @@ -3894,60 +3794,40 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ "tags": [ { "annotations": { - "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.8/README.md.", - "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.8", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nginx-ex.git", - "supports": "nginx", - "tags": "builder,nginx", - "version": "1.8" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/nginx-18-centos7:latest" - }, - "name": "1.8", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.10/README.md.", + "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.14/README.md.", "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.10", + "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.14", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/sclorg/nginx-ex.git", "supports": "nginx", "tags": "builder,nginx", - "version": "1.10" + "version": "1.14" }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/nginx-110-centos7:latest" + "name": "registry.centos.org/centos/nginx-114-centos7:latest" }, - "name": "1.10", + "name": "1.14", "referencePolicy": { "type": "Local" } }, { "annotations": { - "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.12/README.md.", + "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.16/README.md.", "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.12", + "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.16", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/sclorg/nginx-ex.git", "supports": "nginx", "tags": "builder,nginx", - "version": "1.12" + "version": "1.16" }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/nginx-112-centos7:latest" + "name": "registry.centos.org/centos/nginx-116-centos7:latest" }, - "name": "1.12", + "name": "1.16", "referencePolicy": { "type": "Local" } @@ -3964,7 +3844,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "ImageStreamTag", - "name": "1.12" + "name": "1.16" }, "name": "latest", "referencePolicy": { @@ -3997,7 +3877,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "ImageStreamTag", - "name": "11" + "name": "12" }, "name": "latest", "referencePolicy": { @@ -4006,105 +3886,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, { "annotations": { - "description": "DEPRECATED: Build and run Node.js 0.10 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/0.10/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 0.10", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:0.10,nodejs:0.1,nodejs", - "tags": "hidden,nodejs", - "version": "0.10" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/nodejs-010-centos7:latest" - }, - "name": "0.10", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 4 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/4/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:4,nodejs", - "tags": "hidden,builder,nodejs", - "version": "4" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/nodejs-4-centos7:latest" - }, - "name": "4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 6 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/6/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:6,nodejs", - "tags": "builder,nodejs", - "version": "6" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/nodejs-6-centos7:latest" - }, - "name": "6", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 8 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/8/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 8", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "tags": "builder,nodejs", - "version": "8" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/nodejs-8-centos7:latest" - }, - "name": "8", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 8 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 8 (RHOAR)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "tags": "builder,nodejs", - "version": "8" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/nodeshift/centos7-s2i-nodejs:8.x" - }, - "name": "8-RHOAR", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 10 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.", + "description": "Build and run Node.js 10 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/10/README.md.", "iconClass": "icon-nodejs", "openshift.io/display-name": "Node.js 10", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -4114,7 +3896,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/nodeshift/centos7-s2i-nodejs:10.x" + "name": "registry.centos.org/centos/nodejs-10-centos7:latest" }, "name": "10", "referencePolicy": { @@ -4123,19 +3905,19 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, { "annotations": { - "description": "Build and run Node.js 11 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.", + "description": "Build and run Node.js 12 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/12/README.md.", "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 11", + "openshift.io/display-name": "Node.js 12", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", "tags": "builder,nodejs", - "version": "11" + "version": "12" }, "from": { "kind": "DockerImage", - "name": "docker.io/nodeshift/centos7-s2i-nodejs:11.x" + "name": "registry.centos.org/centos/nodejs-12-centos7:latest" }, - "name": "11", + "name": "12", "referencePolicy": { "type": "Local" } @@ -4173,46 +3955,6 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ "type": "Local" } }, - { - "annotations": { - "description": "Build and run Perl 5.16 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.16/README.md.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl 5.16", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl:5.16,perl", - "tags": "hidden,builder,perl", - "version": "5.16" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/perl-516-centos7:latest" - }, - "name": "5.16", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Perl 5.20 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.20/README.md.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl 5.20", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl:5.20,perl", - "tags": "hidden,builder,perl", - "version": "5.20" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/perl-520-centos7:latest" - }, - "name": "5.20", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Build and run Perl 5.24 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.24/README.md.", @@ -4226,7 +3968,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/perl-524-centos7:latest" + "name": "registry.centos.org/centos/perl-524-centos7:latest" }, "name": "5.24", "referencePolicy": { @@ -4246,7 +3988,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/perl-526-centos7:latest" + "name": "registry.centos.org/centos/perl-526-centos7:latest" }, "name": "5.26", "referencePolicy": { @@ -4286,46 +4028,6 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ "type": "Local" } }, - { - "annotations": { - "description": "Build and run PHP 5.5 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/5.5/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP 5.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php:5.5,php", - "tags": "hidden,builder,php", - "version": "5.5" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/php-55-centos7:latest" - }, - "name": "5.5", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run PHP 5.6 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/5.6/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP 5.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php:5.6,php", - "tags": "hidden,builder,php", - "version": "5.6" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/php-56-centos7:latest" - }, - "name": "5.6", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Build and run PHP 7.0 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/7.0/README.md.", @@ -4339,7 +4041,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/php-70-centos7:latest" + "name": "registry.centos.org/centos/php-70-centos7:latest" }, "name": "7.0", "referencePolicy": { @@ -4359,7 +4061,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/php-71-centos7:latest" + "name": "registry.centos.org/centos/php-71-centos7:latest" }, "name": "7.1", "referencePolicy": { @@ -4390,49 +4092,13 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "ImageStreamTag", - "name": "10" + "name": "9.6" }, "name": "latest", "referencePolicy": { "type": "Local" } }, - { - "annotations": { - "description": "Provides a PostgreSQL 9.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 9.2", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,postgresql", - "version": "9.2" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/postgresql-92-centos7:latest" - }, - "name": "9.2", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 9.4 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 9.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,database,postgresql", - "version": "9.4" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/postgresql-94-centos7:latest" - }, - "name": "9.4", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Provides a PostgreSQL 9.5 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", @@ -4444,7 +4110,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/postgresql-95-centos7:latest" + "name": "registry.centos.org/centos/postgresql-95-centos7:latest" }, "name": "9.5", "referencePolicy": { @@ -4462,30 +4128,12 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/postgresql-96-centos7:latest" + "name": "registry.centos.org/centos/postgresql-96-centos7:latest" }, "name": "9.6", "referencePolicy": { "type": "Local" } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 10 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 10", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,postgresql", - "version": "10" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/postgresql-10-centos7:latest" - }, - "name": "10", - "referencePolicy": { - "type": "Local" - } } ] } @@ -4520,26 +4168,6 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ "type": "Local" } }, - { - "annotations": { - "description": "Build and run Python 3.3 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.3/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.3", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.3,python", - "tags": "hidden,builder,python", - "version": "3.3" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/python-33-centos7:latest" - }, - "name": "3.3", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Build and run Python 2.7 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/2.7/README.md.", @@ -4553,53 +4181,13 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/python-27-centos7:latest" + "name": "registry.centos.org/centos/python-27-centos7:latest" }, "name": "2.7", "referencePolicy": { "type": "Local" } }, - { - "annotations": { - "description": "Build and run Python 3.4 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.4/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.4,python", - "tags": "hidden,builder,python", - "version": "3.4" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/python-34-centos7:latest" - }, - "name": "3.4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Python 3.5 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.5/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.5,python", - "tags": "builder,python", - "version": "3.5" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/python-35-centos7:latest" - }, - "name": "3.5", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Build and run Python 3.6 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.6/README.md.", @@ -4613,7 +4201,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/python-36-centos7:latest" + "name": "registry.centos.org/centos/python-36-centos7:latest" }, "name": "3.6", "referencePolicy": { @@ -4636,7 +4224,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ "tags": [ { "annotations": { - "description": "Provides a Redis database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/tree/master/3.2/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Redis available on OpenShift, including major versions updates.", + "description": "Provides a Redis database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Redis available on OpenShift, including major versions updates.", "iconClass": "icon-redis", "openshift.io/display-name": "Redis (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -4644,7 +4232,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "ImageStreamTag", - "name": "3.2" + "name": "5" }, "name": "latest", "referencePolicy": { @@ -4653,18 +4241,18 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, { "annotations": { - "description": "Provides a Redis 3.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/tree/master/3.2/README.md.", + "description": "Provides a Redis 5 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/blob/master/5/README.md.", "iconClass": "icon-redis", - "openshift.io/display-name": "Redis 3.2", + "openshift.io/display-name": "Redis 5", "openshift.io/provider-display-name": "Red Hat, Inc.", "tags": "redis", - "version": "3.2" + "version": "5" }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/redis-32-centos7:latest" + "name": "registry.centos.org/centos/redis-5-centos7:latest" }, - "name": "3.2", + "name": "5", "referencePolicy": { "type": "Local" } @@ -4685,7 +4273,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ "tags": [ { "annotations": { - "description": "Build and run Ruby applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/tree/master/2.3/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Ruby available on OpenShift, including major versions updates.", + "description": "Build and run Ruby applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Ruby available on OpenShift, including major versions updates.", "iconClass": "icon-ruby", "openshift.io/display-name": "Ruby (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -4721,6 +4309,26 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ "referencePolicy": { "type": "Local" } + }, + { + "annotations": { + "description": "Build and run Ruby 2.6 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/blob/master/2.6/README.md.", + "iconClass": "icon-ruby", + "openshift.io/display-name": "Ruby 2.6", + "openshift.io/provider-display-name": "Red Hat, Inc.", + "sampleRepo": "https://github.com/sclorg/ruby-ex.git", + "supports": "ruby:2.6,ruby", + "tags": "builder,ruby", + "version": "2.6" + }, + "from": { + "kind": "DockerImage", + "name": "registry.centos.org/centos/ruby-26-centos7:latest" + }, + "name": "2.6", + "referencePolicy": { + "type": "Local" + } } ] } @@ -4748,7 +4356,7 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, "from": { "kind": "ImageStreamTag", - "name": "15.0" + "name": "21.0" }, "name": "latest", "referencePolicy": { @@ -4757,180 +4365,40 @@ var _examplesImageStreamsImageStreamsCentos7Json = []byte(`{ }, { "annotations": { - "description": "Build and run WildFly 8.1 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 8.1", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:8.1,jee,java", - "tags": "builder,wildfly,java", - "version": "8.1" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-81-centos7:latest" - }, - "name": "8.1", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 9.0 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 9.0", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:9.0,jee,java", - "tags": "builder,wildfly,java", - "version": "9.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-90-centos7:latest" - }, - "name": "9.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 10.0 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 10.0", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:10.0,jee,java", - "tags": "builder,wildfly,java", - "version": "10.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-100-centos7:latest" - }, - "name": "10.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 10.1 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 10.1", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:10.1,jee,java", - "tags": "builder,wildfly,java", - "version": "10.1" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-101-centos7:latest" - }, - "name": "10.1", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 11 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 11", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:11,jee,java", - "tags": "builder,wildfly,java", - "version": "11.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-110-centos7:latest" - }, - "name": "11.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 12 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 12", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:12,jee,java", - "tags": "builder,wildfly,java", - "version": "12.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-120-centos7:latest" - }, - "name": "12.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 13 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 13", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:13,jee,java", - "tags": "builder,wildfly,java", - "version": "13.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-130-centos7:latest" - }, - "name": "13.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 14 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", + "description": "Build and run WildFly 20 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 14", + "openshift.io/display-name": "WildFly 20", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:14,jee,java", + "supports": "wildfly:20,jee,java", "tags": "builder,wildfly,java", - "version": "14.0" + "version": "20.0" }, "from": { "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-140-centos7:latest" + "name": "quay.io/wildfly/wildfly-centos7:20.0" }, - "name": "14.0", + "name": "20.0", "referencePolicy": { "type": "Local" } }, { "annotations": { - "description": "Build and run WildFly 15 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", + "description": "Build and run WildFly 21 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 15", + "openshift.io/display-name": "WildFly 21", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:15,jee,java", + "supports": "wildfly:21,jee,java", "tags": "builder,wildfly,java", - "version": "15.0" + "version": "21.0" }, "from": { "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-150-centos7:latest" + "name": "quay.io/wildfly/wildfly-centos7:21.0.0" }, - "name": "15.0", + "name": "21.0", "referencePolicy": { "type": "Local" } @@ -4957,1449 +4425,962 @@ func examplesImageStreamsImageStreamsCentos7Json() (*asset, error) { return a, nil } -var _examplesImageStreamsImageStreamsRhel7Json = []byte(`{ - "kind": "ImageStreamList", +var _examplesSampleAppApplicationTemplateDockerbuildJson = []byte(`{ + "kind": "Template", "apiVersion": "v1", - "items": [ + "metadata": { + "name": "ruby-helloworld-sample", + "annotations": { + "description": "This example shows how to create a simple ruby application in openshift origin v3", + "iconClass": "icon-ruby", + "tags": "instant-app,ruby,mysql" + } + }, + "objects": [ { + "kind": "Secret", "apiVersion": "v1", - "kind": "ImageStream", "metadata": { - "annotations": { - "openshift.io/display-name": ".NET Core" - }, - "name": "dotnet" + "name": "dbsecret" }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Build and run .NET Core applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.2/build/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of .NET Core available on OpenShift, including major versions updates.", - "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core (Latest)", - "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.2", - "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet", - "tags": "builder,.net,dotnet,dotnetcore" - }, - "from": { - "kind": "ImageStreamTag", - "name": "2.2" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run .NET Core 2.2 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.2/build/README.md.", - "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 2.2", - "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.2", - "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:2.2,dotnet", - "tags": "builder,.net,dotnet,dotnetcore,rh-dotnet22", - "version": "2.2" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/dotnet/dotnet-22-rhel7:2.2" - }, - "name": "2.2", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run .NET Core 2.1 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.1/build/README.md.", - "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 2.1", - "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.1", - "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:2.1,dotnet", - "tags": "builder,.net,dotnet,dotnetcore,rh-dotnet21", - "version": "2.1" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/dotnet/dotnet-21-rhel7:2.1" - }, - "name": "2.1", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "RETIRED: Build and run .NET Core 2.0 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.0/build/README.md.", - "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 2.0", - "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.0", - "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:2.0,dotnet", - "tags": "hidden,builder,.net,dotnet,dotnetcore,rh-dotnet20", - "version": "2.0" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/dotnet/dotnet-20-rhel7:2.0" - }, - "name": "2.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run .NET Core 1.1 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/1.1/README.md.", - "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 1.1", - "sampleContextDir": "app", - "sampleRef": "dotnetcore-1.1", - "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:1.1,dotnet", - "tags": "builder,.net,dotnet,dotnetcore,rh-dotnetcore11", - "version": "1.1" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/dotnet/dotnetcore-11-rhel7:1.1" - }, - "name": "1.1", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run .NET Core 1.0 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/1.0/README.md.", - "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 1.0", - "sampleContextDir": "app", - "sampleRef": "dotnetcore-1.0", - "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:1.0,dotnet", - "tags": "builder,.net,dotnet,dotnetcore,rh-dotnetcore10", - "version": "1.0" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/dotnet/dotnetcore-10-rhel7:1.0" - }, - "name": "1.0", - "referencePolicy": { - "type": "Local" - } - } - ] + "stringData" : { + "mysql-user" : "${MYSQL_USER}", + "mysql-password" : "${MYSQL_PASSWORD}" } }, { + "kind": "Service", "apiVersion": "v1", - "kind": "ImageStream", "metadata": { - "annotations": { - "openshift.io/display-name": "Apache HTTP Server (httpd)" - }, - "name": "httpd" + "name": "frontend" }, "spec": { - "tags": [ - { - "annotations": { - "description": "Build and serve static content via Apache HTTP Server (httpd) on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/httpd-container/blob/master/2.4/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Httpd available on OpenShift, including major versions updates.", - "iconClass": "icon-apache", - "openshift.io/display-name": "Apache HTTP Server (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/httpd-ex.git", - "supports": "httpd", - "tags": "builder,httpd" - }, - "from": { - "kind": "ImageStreamTag", - "name": "2.4" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, + "ports": [ { - "annotations": { - "description": "Build and serve static content via Apache HTTP Server (httpd) 2.4 on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/httpd-container/blob/master/2.4/README.md.", - "iconClass": "icon-apache", - "openshift.io/display-name": "Apache HTTP Server 2.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/httpd-ex.git", - "supports": "httpd", - "tags": "builder,httpd", - "version": "2.4" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/httpd-24-rhel7" - }, - "name": "2.4", - "referencePolicy": { - "type": "Local" - } + "name": "web", + "protocol": "TCP", + "port": 5432, + "targetPort": 8080, + "nodePort": 0 } - ] + ], + "selector": { + "name": "frontend" + }, + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} } }, { + "kind": "Route", "apiVersion": "v1", - "kind": "ImageStream", "metadata": { + "name": "route-edge", "annotations": { - "openshift.io/display-name": "Jenkins" + "template.openshift.io/expose-uri": "http://{.spec.host}{.spec.path}" + } + }, + "spec": { + "host": "www.example.com", + "to": { + "kind": "Service", + "name": "frontend" }, - "name": "jenkins" + "tls": { + "termination": "edge" + } + }, + "status": {} + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "origin-ruby-sample" + }, + "spec": {}, + "status": { + "dockerImageRepository": "" + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "ruby-27-centos7" }, "spec": { "tags": [ { - "annotations": { - "description": "Provides a Jenkins server on RHEL 7. For more information about using this container image, including OpenShift considerations, see https://github.com/openshift/jenkins/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Jenkins available on OpenShift, including major versions updates.", - "iconClass": "icon-jenkins", - "openshift.io/display-name": "Jenkins (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "jenkins" - }, - "from": { - "kind": "ImageStreamTag", - "name": "2" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a Jenkins 2.X server on RHEL 7. For more information about using this container image, including OpenShift considerations, see https://github.com/openshift/jenkins/blob/master/README.md.", - "iconClass": "icon-jenkins", - "openshift.io/display-name": "Jenkins 2.X", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "jenkins", - "version": "2.x" - }, "from": { "kind": "DockerImage", - "name": "registry.redhat.io/openshift/jenkins-2-rhel7:v4.0" + "name": "docker.io/centos/ruby-27-centos7:latest" }, - "name": "2", - "referencePolicy": { - "type": "Local" - } + "name": "latest" } ] } }, { + "kind": "BuildConfig", "apiVersion": "v1", - "kind": "ImageStream", "metadata": { - "annotations": { - "openshift.io/display-name": "MariaDB" + "name": "ruby-sample-build", + "labels": { + "name": "ruby-sample-build" }, - "name": "mariadb" + "annotations": { + "template.alpha.openshift.io/wait-for-ready": "true" + } }, "spec": { - "tags": [ + "triggers": [ { - "annotations": { - "description": "Provides a MariaDB database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.2/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MariaDB available on OpenShift, including major versions updates.", - "iconClass": "icon-mariadb", - "openshift.io/display-name": "MariaDB (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,mariadb" - }, - "from": { - "kind": "ImageStreamTag", - "name": "10.2" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" + "type": "GitHub", + "github": { + "secret": "secret101" } }, { - "annotations": { - "description": "Provides a MariaDB 10.1 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.1/README.md.", - "iconClass": "icon-mariadb", - "openshift.io/display-name": "MariaDB 10.1", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,mariadb", - "version": "10.1" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/mariadb-101-rhel7:latest" - }, - "name": "10.1", - "referencePolicy": { - "type": "Local" + "type": "Generic", + "generic": { + "secret": "secret101", + "allowEnv": true } }, { - "annotations": { - "description": "Provides a MariaDB 10.2 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.2/README.md.", - "iconClass": "icon-mariadb", - "openshift.io/display-name": "MariaDB 10.2", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,mariadb", - "version": "10.2" - }, + "type": "ImageChange", + "imageChange": {} + }, + { + "type": "ConfigChange" + } + ], + "source": { + "type": "Git", + "git": { + "uri": "https://github.com/openshift/ruby-hello-world.git" + } + }, + "strategy": { + "type": "Docker", + "dockerStrategy": { "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/mariadb-102-rhel7:latest" + "kind": "ImageStreamTag", + "name": "ruby-27-centos7:latest" }, - "name": "10.2", - "referencePolicy": { - "type": "Local" - } + "env": [ + { + "name": "EXAMPLE", + "value": "sample-app" + } + ] } - ] + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "origin-ruby-sample:latest" + } + }, + "postCommit": { + "script": "bundle exec rake test" + }, + "resources": {} + }, + "status": { + "lastVersion": 0 } }, { + "kind": "DeploymentConfig", "apiVersion": "v1", - "kind": "ImageStream", "metadata": { + "name": "frontend", "annotations": { - "openshift.io/display-name": "MongoDB" - }, - "name": "mongodb" + "template.alpha.openshift.io/wait-for-ready": "true" + } }, "spec": { - "tags": [ - { - "annotations": { - "description": "Provides a MongoDB database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.4/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MongoDB available on OpenShift, including major versions updates.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "mongodb" - }, - "from": { - "kind": "ImageStreamTag", - "name": "3.6" + "strategy": { + "type": "Rolling", + "rollingParams": { + "updatePeriodSeconds": 1, + "intervalSeconds": 1, + "timeoutSeconds": 120, + "pre": { + "failurePolicy": "Abort", + "execNewPod": { + "command": [ + "/bin/true" + ], + "env": [ + { + "name": "CUSTOM_VAR1", + "value": "custom_value1" + } + ], + "containerName": "ruby-helloworld" + } }, - "name": "latest", - "referencePolicy": { - "type": "Local" + "post": { + "failurePolicy": "Ignore", + "execNewPod": { + "command": [ + "/bin/true" + ], + "env": [ + { + "name": "CUSTOM_VAR2", + "value": "custom_value2" + } + ], + "containerName": "ruby-helloworld" + } } }, + "resources": {} + }, + "triggers": [ { - "annotations": { - "description": "Provides a MongoDB 2.4 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/2.4/README.md.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB 2.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,mongodb", - "version": "2.4" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift3/mongodb-24-rhel7:latest" - }, - "name": "2.4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a MongoDB 2.6 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/2.6/README.md.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB 2.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,database,mongodb", - "version": "2.6" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/mongodb-26-rhel7:latest" - }, - "name": "2.6", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a MongoDB 3.2 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.2/README.md.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB 3.2", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,mongodb", - "version": "3.2" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/mongodb-32-rhel7:latest" - }, - "name": "3.2", - "referencePolicy": { - "type": "Local" + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "ruby-helloworld" + ], + "from": { + "kind": "ImageStreamTag", + "name": "origin-ruby-sample:latest" + } } }, { - "annotations": { - "description": "Provides a MongoDB 3.4 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.4/README.md.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB 3.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,mongodb", - "version": "3.4" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/mongodb-34-rhel7:latest" - }, - "name": "3.4", - "referencePolicy": { - "type": "Local" + "type": "ConfigChange" + } + ], + "replicas": 2, + "selector": { + "name": "frontend" + }, + "template": { + "metadata": { + "labels": { + "name": "frontend" } }, + "spec": { + "containers": [ + { + "name": "ruby-helloworld", + "image": "origin-ruby-sample", + "ports": [ + { + "containerPort": 8080, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "MYSQL_USER", + "valueFrom": { + "secretKeyRef" : { + "name" : "dbsecret", + "key" : "mysql-user" + } + } + }, + { + "name": "MYSQL_PASSWORD", + "valueFrom": { + "secretKeyRef" : { + "name" : "dbsecret", + "key" : "mysql-password" + } + } + }, + { + "name": "MYSQL_DATABASE", + "value": "${MYSQL_DATABASE}" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "imagePullPolicy": "IfNotPresent", + "securityContext": { + "capabilities": {}, + "privileged": false + } + } + ], + "restartPolicy": "Always", + "dnsPolicy": "ClusterFirst" + } + } + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "database" + }, + "spec": { + "ports": [ { - "annotations": { - "description": "Provides a MongoDB 3.6 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.6/README.md.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB 3.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,mongodb", - "version": "3.6" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/mongodb-36-rhel7:latest" - }, - "name": "3.6", - "referencePolicy": { - "type": "Local" - } + "name": "db", + "protocol": "TCP", + "port": 5434, + "targetPort": 3306, + "nodePort": 0 } - ] + ], + "selector": { + "name": "database" + }, + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} } }, { + "kind": "DeploymentConfig", "apiVersion": "v1", - "kind": "ImageStream", "metadata": { + "name": "database", "annotations": { - "openshift.io/display-name": "MySQL" - }, - "name": "mysql" + "template.alpha.openshift.io/wait-for-ready": "true" + } }, "spec": { - "tags": [ - { - "annotations": { - "description": "Provides a MySQL database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MySQL available on OpenShift, including major versions updates.", - "iconClass": "icon-mysql-database", - "openshift.io/display-name": "MySQL (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "mysql" - }, - "from": { - "kind": "ImageStreamTag", - "name": "5.7" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a MySQL 5.5 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/README.md.", - "iconClass": "icon-mysql-database", - "openshift.io/display-name": "MySQL 5.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,mysql", - "version": "5.5" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift3/mysql-55-rhel7:latest" - }, - "name": "5.5", - "referencePolicy": { - "type": "Local" - } - }, + "strategy": { + "type": "Recreate", + "resources": {} + }, + "triggers": [ { - "annotations": { - "description": "Provides a MySQL 5.6 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/README.md.", - "iconClass": "icon-mysql-database", - "openshift.io/display-name": "MySQL 5.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,mysql", - "version": "5.6" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/mysql-56-rhel7:latest" - }, - "name": "5.6", - "referencePolicy": { - "type": "Local" + "type": "ConfigChange" + } + ], + "replicas": 1, + "selector": { + "name": "database" + }, + "template": { + "metadata": { + "labels": { + "name": "database" } }, + "spec": { + "containers": [ + { + "name": "ruby-helloworld-database", + "image": "centos/mysql-57-centos7:latest", + "ports": [ + { + "containerPort": 3306, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "MYSQL_USER", + "valueFrom": { + "secretKeyRef" : { + "name" : "dbsecret", + "key" : "mysql-user" + } + } + }, + { + "name": "MYSQL_PASSWORD", + "valueFrom": { + "secretKeyRef" : { + "name" : "dbsecret", + "key" : "mysql-password" + } + } + }, + { + "name": "MYSQL_DATABASE", + "value": "${MYSQL_DATABASE}" + } + ], + "resources": {}, + "volumeMounts": [ + { + "name": "ruby-helloworld-data", + "mountPath": "/var/lib/mysql/data" + } + ], + "terminationMessagePath": "/dev/termination-log", + "imagePullPolicy": "Always", + "securityContext": { + "capabilities": {}, + "privileged": false + } + } + ], + "volumes": [ + { + "name": "ruby-helloworld-data", + "emptyDir": { + "medium": "" + } + } + ], + "restartPolicy": "Always", + "dnsPolicy": "ClusterFirst" + } + } + } + } + ], + "parameters": [ + { + "name": "MYSQL_USER", + "description": "database username", + "generate": "expression", + "from": "user[A-Z0-9]{3}", + "required": true + }, + { + "name": "MYSQL_PASSWORD", + "description": "database password", + "generate": "expression", + "from": "[a-zA-Z0-9]{8}", + "required": true + }, + { + "name": "MYSQL_DATABASE", + "description": "database name", + "value": "root", + "required": true + } + ], + "labels": { + "template": "application-template-dockerbuild" + } +} +`) + +func examplesSampleAppApplicationTemplateDockerbuildJsonBytes() ([]byte, error) { + return _examplesSampleAppApplicationTemplateDockerbuildJson, nil +} + +func examplesSampleAppApplicationTemplateDockerbuildJson() (*asset, error) { + bytes, err := examplesSampleAppApplicationTemplateDockerbuildJsonBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "examples/sample-app/application-template-dockerbuild.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _examplesSampleAppApplicationTemplatePullspecbuildJson = []byte(`{ + "kind": "Template", + "apiVersion": "v1", + "metadata": { + "name": "ruby-helloworld-sample", + "annotations": { + "description": "This example shows how to create a simple ruby application in openshift origin v3", + "iconClass": "icon-ruby", + "tags": "instant-app,ruby,mysql" + } + }, + "objects": [ + { + "kind": "Secret", + "apiVersion": "v1", + "metadata": { + "name": "dbsecret" + }, + "stringData" : { + "mysql-user" : "${MYSQL_USER}", + "mysql-password" : "${MYSQL_PASSWORD}" + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "frontend" + }, + "spec": { + "ports": [ { - "annotations": { - "description": "Provides a MySQL 5.7 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/README.md.", - "iconClass": "icon-mysql-database", - "openshift.io/display-name": "MySQL 5.7", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "mysql", - "version": "5.7" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/mysql-57-rhel7:latest" - }, - "name": "5.7", - "referencePolicy": { - "type": "Local" - } + "name": "web", + "protocol": "TCP", + "port": 5432, + "targetPort": 8080, + "nodePort": 0 } - ] + ], + "selector": { + "name": "frontend" + }, + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} } }, { + "kind": "Route", "apiVersion": "v1", - "kind": "ImageStream", "metadata": { + "name": "route-edge", "annotations": { - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy (nginx)" + "template.openshift.io/expose-uri": "http://{.spec.host}{.spec.path}" + } + }, + "spec": { + "host": "www.example.com", + "to": { + "kind": "Service", + "name": "frontend" }, - "name": "nginx" + "tls": { + "termination": "edge" + } + }, + "status": {} + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "origin-ruby-sample" + }, + "spec": {}, + "status": { + "dockerImageRepository": "" + } + }, + { + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "ruby-27-centos7" }, "spec": { - "tags": [ + "dockerImageRepository": "centos/ruby-27-centos7" + }, + "status": { + "dockerImageRepository": "" + } + }, + { + "kind": "BuildConfig", + "apiVersion": "v1", + "metadata": { + "name": "ruby-sample-build", + "labels": { + "name": "ruby-sample-build" + }, + "annotations": { + "template.alpha.openshift.io/wait-for-ready": "true" + } + }, + "spec": { + "triggers": [ { - "annotations": { - "description": "Build and serve static content via Nginx HTTP server and a reverse proxy (nginx) on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.8/README.md.", - "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.8", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nginx-ex.git", - "supports": "nginx", - "tags": "builder,nginx", - "version": "1.8" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/nginx-18-rhel7:latest" - }, - "name": "1.8", - "referencePolicy": { - "type": "Local" + "type": "GitHub", + "github": { + "secret": "secret101" } }, { - "annotations": { - "description": "Build and serve static content via Nginx HTTP server and a reverse proxy (nginx) on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.10/README.md.", - "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.10", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nginx-ex.git", - "supports": "nginx", - "tags": "builder,nginx", - "version": "1.10" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/nginx-110-rhel7:latest" - }, - "name": "1.10", - "referencePolicy": { - "type": "Local" + "type": "Generic", + "generic": { + "secret": "secret101", + "allowEnv": true } }, { - "annotations": { - "description": "Build and serve static content via Nginx HTTP server and a reverse proxy (nginx) on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.12/README.md.", - "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.12", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nginx-ex.git", - "supports": "nginx", - "tags": "builder,nginx", - "version": "1.12" - }, + "type": "ConfigChange" + } + ], + "source": { + "type": "Git", + "git": { + "uri": "https://github.com/openshift/ruby-hello-world.git" + } + }, + "strategy": { + "type": "Source", + "sourceStrategy": { "from": { "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/nginx-112-rhel7:latest" - }, - "name": "1.12", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and serve static content via Nginx HTTP server and a reverse proxy (nginx) on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.12/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Nginx available on OpenShift, including major versions updates.", - "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nginx-ex.git", - "supports": "nginx", - "tags": "builder,nginx" - }, - "from": { - "kind": "ImageStreamTag", - "name": "1.12" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" + "name": "centos/ruby-27-centos7:latest" } } - ] + }, + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "origin-ruby-sample:latest" + } + }, + "postCommit": { + "script": "bundle exec rake test" + }, + "resources": {} + }, + "status": { + "lastVersion": 0 } }, { + "kind": "DeploymentConfig", "apiVersion": "v1", - "kind": "ImageStream", "metadata": { + "name": "frontend", "annotations": { - "openshift.io/display-name": "Node.js" - }, - "name": "nodejs" + "template.alpha.openshift.io/wait-for-ready": "true" + } }, "spec": { - "tags": [ - { - "annotations": { - "description": "Build and run Node.js 10 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Node.js available on OpenShift, including major versions updates.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs", - "tags": "builder,nodejs" - }, - "from": { - "kind": "ImageStreamTag", - "name": "10" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "DEPRECATED: Build and run Node.js 0.10 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/0.10/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 0.10", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:0.10,nodejs:0.1,nodejs", - "tags": "hidden,nodejs", - "version": "0.10" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift3/nodejs-010-rhel7:latest" - }, - "name": "0.10", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 4 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/4/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:4,nodejs", - "tags": "hidden,builder,nodejs", - "version": "4" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/nodejs-4-rhel7:latest" - }, - "name": "4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 6 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:6,nodejs", - "tags": "builder,nodejs", - "version": "6" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/nodejs-6-rhel7:latest" + "strategy": { + "type": "Rolling", + "rollingParams": { + "updatePeriodSeconds": 1, + "intervalSeconds": 1, + "timeoutSeconds": 120, + "pre": { + "failurePolicy": "Abort", + "execNewPod": { + "command": [ + "/bin/true" + ], + "env": [ + { + "name": "CUSTOM_VAR1", + "value": "custom_value1" + } + ], + "containerName": "ruby-helloworld" + } }, - "name": "6", - "referencePolicy": { - "type": "Local" + "post": { + "failurePolicy": "Ignore", + "execNewPod": { + "command": [ + "/bin/true" + ], + "env": [ + { + "name": "CUSTOM_VAR2", + "value": "custom_value2" + } + ], + "containerName": "ruby-helloworld" + } } }, + "resources": {} + }, + "triggers": [ { - "annotations": { - "description": "Build and run Node.js 8 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 8", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "tags": "builder,nodejs", - "version": "8" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/nodejs-8-rhel7:latest" - }, - "name": "8", - "referencePolicy": { - "type": "Local" + "type": "ImageChange", + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "ruby-helloworld" + ], + "from": { + "kind": "ImageStreamTag", + "name": "origin-ruby-sample:latest" + } } }, { - "annotations": { - "description": "Build and run Node.js 8 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "OpenShift Application Runtimes Node.js 8", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "tags": "builder,nodejs", - "version": "8" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhoar-nodejs/nodejs-8" - }, - "name": "8-RHOAR", - "referencePolicy": { - "type": "Local" + "type": "ConfigChange" + } + ], + "replicas": 2, + "selector": { + "name": "frontend" + }, + "template": { + "metadata": { + "labels": { + "name": "frontend" } }, - { - "annotations": { - "description": "Build and run Node.js 10 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "OpenShift Application Runtimes Node.js 10", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "tags": "builder,nodejs", - "version": "10" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhoar-nodejs/nodejs-10" - }, - "name": "10", - "referencePolicy": { - "type": "Local" - } + "spec": { + "containers": [ + { + "name": "ruby-helloworld", + "image": "origin-ruby-sample", + "ports": [ + { + "containerPort": 8080, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "MYSQL_USER", + "valueFrom": { + "secretKeyRef" : { + "name" : "dbsecret", + "key" : "mysql-user" + } + } + }, + { + "name": "MYSQL_PASSWORD", + "valueFrom": { + "secretKeyRef" : { + "name" : "dbsecret", + "key" : "mysql-password" + } + } + }, + { + "name": "MYSQL_DATABASE", + "value": "${MYSQL_DATABASE}" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "imagePullPolicy": "IfNotPresent", + "securityContext": { + "capabilities": {}, + "privileged": false + } + } + ], + "restartPolicy": "Always", + "dnsPolicy": "ClusterFirst" } - ] + } } }, { + "kind": "Service", "apiVersion": "v1", - "kind": "ImageStream", "metadata": { - "annotations": { - "openshift.io/display-name": "Perl" - }, - "name": "perl" + "name": "database" }, "spec": { - "tags": [ - { - "annotations": { - "description": "Build and run Perl applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.20/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Perl available on OpenShift, including major versions updates.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl", - "tags": "builder,perl" - }, - "from": { - "kind": "ImageStreamTag", - "name": "5.26" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Perl 5.16 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.16/README.md.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl 5.16", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl:5.16,perl", - "tags": "hidden,builder,perl", - "version": "5.16" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift3/perl-516-rhel7:latest" - }, - "name": "5.16", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Perl 5.20 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.20/README.md.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl 5.20", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl:5.20,perl", - "tags": "hidden,builder,perl", - "version": "5.20" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/perl-520-rhel7:latest" - }, - "name": "5.20", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Perl 5.24 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.24/README.md.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl 5.24", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl:5.24,perl", - "tags": "builder,perl", - "version": "5.24" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/perl-524-rhel7:latest" - }, - "name": "5.24", - "referencePolicy": { - "type": "Local" - } - }, + "ports": [ { - "annotations": { - "description": "Build and run Perl 5.26 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.26/README.md.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl 5.26", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl:5.26,perl", - "tags": "builder,perl", - "version": "5.26" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/perl-526-rhel7:latest" - }, - "name": "5.26", - "referencePolicy": { - "type": "Local" - } + "name": "db", + "protocol": "TCP", + "port": 5434, + "targetPort": 3306, + "nodePort": 0 } - ] + ], + "selector": { + "name": "database" + }, + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} } }, { + "kind": "DeploymentConfig", "apiVersion": "v1", - "kind": "ImageStream", "metadata": { + "name": "database", "annotations": { - "openshift.io/display-name": "PHP" - }, - "name": "php" + "template.alpha.openshift.io/wait-for-ready": "true" + } }, "spec": { - "tags": [ - { - "annotations": { - "description": "Build and run PHP applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/7.1/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of PHP available on OpenShift, including major versions updates.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php", - "tags": "builder,php" - }, - "from": { - "kind": "ImageStreamTag", - "name": "7.1" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run PHP 5.5 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/5.5/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP 5.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php:5.5,php", - "tags": "hidden,builder,php", - "version": "5.5" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift3/php-55-rhel7:latest" - }, - "name": "5.5", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run PHP 5.6 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/5.6/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP 5.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php:5.6,php", - "tags": "hidden,builder,php", - "version": "5.6" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/php-56-rhel7:latest" - }, - "name": "5.6", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run PHP 7.0 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/7.0/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP 7.0", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php:7.0,php", - "tags": "builder,php", - "version": "7.0" + "strategy": { + "type": "Recreate", + "recreateParams": { + "pre": { + "failurePolicy": "Abort", + "execNewPod": { + "command": [ + "/bin/true" + ], + "env": [ + { + "name": "CUSTOM_VAR1", + "value": "custom_value1" + } + ], + "containerName": "ruby-helloworld-database", + "volumes": ["ruby-helloworld-data"] + } }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/php-70-rhel7:latest" + "mid": { + "failurePolicy": "Abort", + "execNewPod": { + "command": [ + "/bin/true" + ], + "env": [ + { + "name": "CUSTOM_VAR2", + "value": "custom_value2" + } + ], + "containerName": "ruby-helloworld-database", + "volumes": ["ruby-helloworld-data"] + } }, - "name": "7.0", - "referencePolicy": { - "type": "Local" + "post": { + "failurePolicy": "Ignore", + "execNewPod": { + "command": [ + "/bin/true" + ], + "env": [ + { + "name": "CUSTOM_VAR2", + "value": "custom_value2" + } + ], + "containerName": "ruby-helloworld-database", + "volumes": ["ruby-helloworld-data"] + } } }, + "resources": {} + }, + "triggers": [ { - "annotations": { - "description": "Build and run PHP 7.1 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/7.1/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP 7.1", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php:7.1,php", - "tags": "builder,php", - "version": "7.1" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/php-71-rhel7:latest" - }, - "name": "7.1", - "referencePolicy": { - "type": "Local" - } + "type": "ConfigChange" } - ] - } - }, - { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "PostgreSQL" + ], + "replicas": 1, + "selector": { + "name": "database" }, - "name": "postgresql" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Provides a PostgreSQL database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of PostgreSQL available on OpenShift, including major versions updates.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,postgresql" - }, - "from": { - "kind": "ImageStreamTag", - "name": "10" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" + "template": { + "metadata": { + "labels": { + "name": "database" } }, - { - "annotations": { - "description": "Provides a PostgreSQL 9.2 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 9.2", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,postgresql", - "version": "9.2" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift3/postgresql-92-rhel7:latest" - }, - "name": "9.2", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 9.4 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 9.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,database,postgresql", - "version": "9.4" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/postgresql-94-rhel7:latest" - }, - "name": "9.4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 9.5 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 9.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,postgresql", - "version": "9.5" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/postgresql-95-rhel7:latest" - }, - "name": "9.5", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 9.6 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL (Ephemeral) 9.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,postgresql", - "version": "9.6" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/postgresql-96-rhel7:latest" - }, - "name": "9.6", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 10 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL (Ephemeral) 10", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,postgresql", - "version": "10" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/postgresql-10-rhel7:latest" - }, - "name": "10", - "referencePolicy": { - "type": "Local" - } + "spec": { + "containers": [ + { + "name": "ruby-helloworld-database", + "image": "centos/mysql-57-centos7:latest", + "ports": [ + { + "containerPort": 3306, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "MYSQL_USER", + "valueFrom": { + "secretKeyRef" : { + "name" : "dbsecret", + "key" : "mysql-user" + } + } + }, + { + "name": "MYSQL_PASSWORD", + "valueFrom": { + "secretKeyRef" : { + "name" : "dbsecret", + "key" : "mysql-password" + } + } + }, + { + "name": "MYSQL_DATABASE", + "value": "${MYSQL_DATABASE}" + } + ], + "resources": {}, + "volumeMounts": [ + { + "name": "ruby-helloworld-data", + "mountPath": "/var/lib/mysql/data" + } + ], + "terminationMessagePath": "/dev/termination-log", + "imagePullPolicy": "Always", + "securityContext": { + "capabilities": {}, + "privileged": false + } + } + ], + "volumes": [ + { + "name": "ruby-helloworld-data", + "emptyDir": { + "medium": "" + } + } + ], + "restartPolicy": "Always", + "dnsPolicy": "ClusterFirst" } - ] + } } - }, + } + ], + "parameters": [ { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "Python" - }, - "name": "python" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Build and run Python applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.6/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Python available on OpenShift, including major versions updates.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python", - "tags": "builder,python" - }, - "from": { - "kind": "ImageStreamTag", - "name": "3.6" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Python 3.3 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.3/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.3", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.3,python", - "tags": "hidden,builder,python", - "version": "3.3" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift3/python-33-rhel7:latest" - }, - "name": "3.3", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Python 2.7 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/2.7/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 2.7", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:2.7,python", - "tags": "builder,python", - "version": "2.7" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/python-27-rhel7:latest" - }, - "name": "2.7", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Python 3.4 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.4/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.4,python", - "tags": "hidden,builder,python", - "version": "3.4" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/python-34-rhel7:latest" - }, - "name": "3.4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Python 3.5 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.5/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.5,python", - "tags": "builder,python", - "version": "3.5" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/python-35-rhel7:latest" - }, - "name": "3.5", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Python 3.6 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.6/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.6,python", - "tags": "builder,python", - "version": "3.6" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/python-36-rhel7:latest" - }, - "name": "3.6", - "referencePolicy": { - "type": "Local" - } - } - ] - } + "name": "MYSQL_USER", + "description": "database username", + "generate": "expression", + "from": "user[A-Z0-9]{3}", + "required": true }, { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "Redis" - }, - "name": "redis" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Provides a Redis database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/tree/master/3.2/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Redis available on OpenShift, including major versions updates.", - "iconClass": "icon-redis", - "openshift.io/display-name": "Redis (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "redis" - }, - "from": { - "kind": "ImageStreamTag", - "name": "3.2" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a Redis 3.2 database on RHEL 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/tree/master/3.2/README.md.", - "iconClass": "icon-redis", - "openshift.io/display-name": "Redis 3.2", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "redis", - "version": "3.2" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/redis-32-rhel7:latest" - }, - "name": "3.2", - "referencePolicy": { - "type": "Local" - } - } - ] - } + "name": "MYSQL_PASSWORD", + "description": "database password", + "generate": "expression", + "from": "[a-zA-Z0-9]{8}", + "required": true }, { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "openshift.io/display-name": "Ruby" - }, - "name": "ruby" - }, - "spec": { - "tags": [ - { - "annotations": { - "description": "Build and run Ruby applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/tree/master/2.3/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Ruby available on OpenShift, including major versions updates.", - "iconClass": "icon-ruby", - "openshift.io/display-name": "Ruby (Latest)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/ruby-ex.git", - "supports": "ruby", - "tags": "builder,ruby" - }, - "from": { - "kind": "ImageStreamTag", - "name": "2.5" - }, - "name": "latest", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Ruby 2.0 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/tree/master/2.0/README.md.", - "iconClass": "icon-ruby", - "openshift.io/display-name": "Ruby 2.0", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/ruby-ex.git", - "supports": "ruby:2.0,ruby", - "tags": "hidden,builder,ruby", - "version": "2.0" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/openshift3/ruby-20-rhel7:latest" - }, - "name": "2.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Ruby 2.2 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/tree/master/2.2/README.md.", - "iconClass": "icon-ruby", - "openshift.io/display-name": "Ruby 2.2", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/ruby-ex.git", - "supports": "ruby:2.2,ruby", - "tags": "hidden,builder,ruby", - "version": "2.2" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/ruby-22-rhel7:latest" - }, - "name": "2.2", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Ruby 2.3 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/blob/master/2.3/README.md.", - "iconClass": "icon-ruby", - "openshift.io/display-name": "Ruby 2.3", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/ruby-ex.git", - "supports": "ruby:2.3,ruby", - "tags": "builder,ruby", - "version": "2.3" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/ruby-23-rhel7:latest" - }, - "name": "2.3", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Ruby 2.4 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/blob/master/2.4/README.md.", - "iconClass": "icon-ruby", - "openshift.io/display-name": "Ruby 2.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/ruby-ex.git", - "supports": "ruby:2.4,ruby", - "tags": "builder,ruby", - "version": "2.4" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/ruby-24-rhel7:latest" - }, - "name": "2.4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Ruby 2.5 applications on RHEL 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/blob/master/2.5/README.md.", - "iconClass": "icon-ruby", - "openshift.io/display-name": "Ruby 2.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/ruby-ex.git", - "supports": "ruby:2.5,ruby", - "tags": "builder,ruby", - "version": "2.5" - }, - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/ruby-25-rhel7:latest" - }, - "name": "2.5", - "referencePolicy": { - "type": "Local" - } - } - ] - } + "name": "MYSQL_DATABASE", + "description": "database name", + "value": "root", + "required": true } - ] + ], + "labels": { + "template": "application-template-stibuild" + } } `) -func examplesImageStreamsImageStreamsRhel7JsonBytes() ([]byte, error) { - return _examplesImageStreamsImageStreamsRhel7Json, nil +func examplesSampleAppApplicationTemplatePullspecbuildJsonBytes() ([]byte, error) { + return _examplesSampleAppApplicationTemplatePullspecbuildJson, nil } -func examplesImageStreamsImageStreamsRhel7Json() (*asset, error) { - bytes, err := examplesImageStreamsImageStreamsRhel7JsonBytes() +func examplesSampleAppApplicationTemplatePullspecbuildJson() (*asset, error) { + bytes, err := examplesSampleAppApplicationTemplatePullspecbuildJsonBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "examples/image-streams/image-streams-rhel7.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "examples/sample-app/application-template-pullspecbuild.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _examplesSampleAppApplicationTemplateDockerbuildJson = []byte(`{ +var _examplesSampleAppApplicationTemplateStibuildJson = []byte(`{ "kind": "Template", "apiVersion": "v1", "metadata": { @@ -6456,7 +5437,7 @@ var _examplesSampleAppApplicationTemplateDockerbuildJson = []byte(`{ "annotations": { "template.openshift.io/expose-uri": "http://{.spec.host}{.spec.path}" } - }, + }, "spec": { "host": "www.example.com", "to": { @@ -6487,15 +5468,10 @@ var _examplesSampleAppApplicationTemplateDockerbuildJson = []byte(`{ "name": "ruby-27-centos7" }, "spec": { - "tags": [ - { - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/ruby-27-centos7:latest" - }, - "name": "latest" - } - ] + "dockerImageRepository": "centos/ruby-27-centos7" + }, + "status": { + "dockerImageRepository": "" } }, { @@ -6540,8 +5516,8 @@ var _examplesSampleAppApplicationTemplateDockerbuildJson = []byte(`{ } }, "strategy": { - "type": "Docker", - "dockerStrategy": { + "type": "Source", + "sourceStrategy": { "from": { "kind": "ImageStreamTag", "name": "ruby-27-centos7:latest" @@ -6694,8 +5670,7 @@ var _examplesSampleAppApplicationTemplateDockerbuildJson = []byte(`{ "dnsPolicy": "ClusterFirst" } } - }, - "status": {} + } }, { "kind": "Service", @@ -6735,6 +5710,56 @@ var _examplesSampleAppApplicationTemplateDockerbuildJson = []byte(`{ "spec": { "strategy": { "type": "Recreate", + "recreateParams": { + "pre": { + "failurePolicy": "Abort", + "execNewPod": { + "command": [ + "/bin/true" + ], + "env": [ + { + "name": "CUSTOM_VAR1", + "value": "custom_value1" + } + ], + "containerName": "ruby-helloworld-database", + "volumes": ["ruby-helloworld-data"] + } + }, + "mid": { + "failurePolicy": "Abort", + "execNewPod": { + "command": [ + "/bin/true" + ], + "env": [ + { + "name": "CUSTOM_VAR2", + "value": "custom_value2" + } + ], + "containerName": "ruby-helloworld-database", + "volumes": ["ruby-helloworld-data"] + } + }, + "post": { + "failurePolicy": "Ignore", + "execNewPod": { + "command": [ + "/bin/true" + ], + "env": [ + { + "name": "CUSTOM_VAR2", + "value": "custom_value2" + } + ], + "containerName": "ruby-helloworld-database", + "volumes": ["ruby-helloworld-data"] + } + } + }, "resources": {} }, "triggers": [ @@ -6814,8 +5839,7 @@ var _examplesSampleAppApplicationTemplateDockerbuildJson = []byte(`{ "dnsPolicy": "ClusterFirst" } } - }, - "status": {} + } } ], "parameters": [ @@ -6841,1265 +5865,861 @@ var _examplesSampleAppApplicationTemplateDockerbuildJson = []byte(`{ } ], "labels": { - "template": "application-template-dockerbuild" + "template": "application-template-stibuild" } } `) -func examplesSampleAppApplicationTemplateDockerbuildJsonBytes() ([]byte, error) { - return _examplesSampleAppApplicationTemplateDockerbuildJson, nil +func examplesSampleAppApplicationTemplateStibuildJsonBytes() ([]byte, error) { + return _examplesSampleAppApplicationTemplateStibuildJson, nil } -func examplesSampleAppApplicationTemplateDockerbuildJson() (*asset, error) { - bytes, err := examplesSampleAppApplicationTemplateDockerbuildJsonBytes() +func examplesSampleAppApplicationTemplateStibuildJson() (*asset, error) { + bytes, err := examplesSampleAppApplicationTemplateStibuildJsonBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "examples/sample-app/application-template-dockerbuild.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "examples/sample-app/application-template-stibuild.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _examplesSampleAppApplicationTemplatePullspecbuildJson = []byte(`{ - "kind": "Template", - "apiVersion": "v1", - "metadata": { - "name": "ruby-helloworld-sample", - "annotations": { - "description": "This example shows how to create a simple ruby application in openshift origin v3", - "iconClass": "icon-ruby", - "tags": "instant-app,ruby,mysql" - } - }, - "objects": [ - { - "kind": "Secret", - "apiVersion": "v1", - "metadata": { - "name": "dbsecret" - }, - "stringData" : { - "mysql-user" : "${MYSQL_USER}", - "mysql-password" : "${MYSQL_PASSWORD}" - } - }, +var _examplesSampleAppCleanupSh = []byte(`#!/bin/sh + +echo "Killing openshift all-in-one server ..." +sudo pkill -x openshift + +echo "Stopping all k8s containers on host ..." +sudo docker ps --format='{{.Names}}' | grep -E '^k8s_' | xargs -l -r sudo docker stop + +echo "Unmounting openshift local volumes ..." +mount | grep "openshift.local.volumes" | awk '{ print $3}' | xargs -l -r sudo umount + +echo "Cleaning up openshift runtime files ..." +sudo rm -rf openshift.local.* + + +`) + +func examplesSampleAppCleanupShBytes() ([]byte, error) { + return _examplesSampleAppCleanupSh, nil +} + +func examplesSampleAppCleanupSh() (*asset, error) { + bytes, err := examplesSampleAppCleanupShBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "examples/sample-app/cleanup.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _examplesSampleAppGithubWebhookExampleJson = []byte(`{ + "after": "9bdc3a26ff933b32f3e558636b58aea86a69f051", + "before": "0000000000000000000000000000000000000000", + "commits": [ { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "frontend" + "added": [ + "LICENSE" + ], + "author": { + "email": "anonUser@example.com", + "name": "Anonymous User" }, - "spec": { - "ports": [ - { - "name": "web", - "protocol": "TCP", - "port": 5432, - "targetPort": 8080, - "nodePort": 0 - } - ], - "selector": { - "name": "frontend" - }, - "type": "ClusterIP", - "sessionAffinity": "None" + "committer": { + "email": "anonUser@example.com", + "name": "Anonymous User" }, - "status": { - "loadBalancer": {} - } + "distinct": true, + "id": "9bdc3a26ff933b32f3e558636b58aea86a69f051", + "message": "Added license", + "modified": [], + "removed": [], + "timestamp": "2014-08-28T16:55:36+02:00", + "url": "https://github.com/anonUser/anonRepo/commit/9bdc3a26ff933b32f3e558636b58aea86a69f051" + } + ], + "compare": "https://github.com/anonUser/anonRepo/commit/9bdc3a26ff93", + "created": true, + "deleted": false, + "forced": true, + "head_commit": { + "added": [ + "LICENSE" + ], + "author": { + "email": "anonUser@example.com", + "name": "Anonymous User" }, - { - "kind": "Route", - "apiVersion": "v1", - "metadata": { - "name": "route-edge", - "annotations": { - "template.openshift.io/expose-uri": "http://{.spec.host}{.spec.path}" - } - }, - "spec": { - "host": "www.example.com", - "to": { - "kind": "Service", - "name": "frontend" - }, - "tls": { - "termination": "edge" - } - }, - "status": {} + "committer": { + "email": "anonUser@example.com", + "name": "Anonymous User" }, - { - "kind": "ImageStream", - "apiVersion": "v1", - "metadata": { - "name": "origin-ruby-sample" - }, - "spec": {}, - "status": { - "dockerImageRepository": "" - } + "distinct": true, + "id": "", + "message": "Added license", + "modified": [], + "removed": [], + "timestamp": "2014-08-28T16:55:36+02:00", + "url": "https://github.com/anonUser/anonRepo/commit/9bdc3a26ff933b32f3e558636b58aea86a69f051" + }, + "pusher": { + "email": "anonUser@example.com", + "name": "anonUser" + }, + "ref": "refs/heads/master", + "repository": { + "archive_url": "https://api.github.com/repos/anonUser/anonRepo/{archive_format}{/ref}", + "assignees_url": "https://api.github.com/repos/anonUser/anonRepo/assignees{/user}", + "blobs_url": "https://api.github.com/repos/anonUser/anonRepo/git/blobs{/sha}", + "branches_url": "https://api.github.com/repos/anonUser/anonRepo/branches{/branch}", + "clone_url": "https://github.com/anonUser/anonRepo.git", + "collaborators_url": "https://api.github.com/repos/anonUser/anonRepo/collaborators{/collaborator}", + "comments_url": "https://api.github.com/repos/anonUser/anonRepo/comments{/number}", + "commits_url": "https://api.github.com/repos/anonUser/anonRepo/commits{/sha}", + "compare_url": "https://api.github.com/repos/anonUser/anonRepo/compare/{base}...{head}", + "contents_url": "https://api.github.com/repos/anonUser/anonRepo/contents/{+path}", + "contributors_url": "https://api.github.com/repos/anonUser/anonRepo/contributors", + "created_at": 1.409063699e+09, + "default_branch": "master", + "description": "Git webhook implementation in Go.", + "downloads_url": "https://api.github.com/repos/anonUser/anonRepo/downloads", + "events_url": "https://api.github.com/repos/anonUser/anonRepo/events", + "fork": false, + "forks": 0, + "forks_count": 0, + "forks_url": "https://api.github.com/repos/anonUser/anonRepo/forks", + "full_name": "anonUser/anonRepo", + "git_commits_url": "https://api.github.com/repos/anonUser/anonRepo/git/commits{/sha}", + "git_refs_url": "https://api.github.com/repos/anonUser/anonRepo/git/refs{/sha}", + "git_tags_url": "https://api.github.com/repos/anonUser/anonRepo/git/tags{/sha}", + "git_url": "https://github.com/anonUser/anonRepo.git", + "has_downloads": true, + "has_issues": true, + "has_wiki": true, + "homepage": null, + "hooks_url": "https://api.github.com/repos/anonUser/anonRepo/hooks", + "html_url": "https://github.com/anonUser/anonRepo", + "id": 2.3354788e+07, + "issue_comment_url": "https://api.github.com/repos/anonUser/anonRepo/issues/comments/{number}", + "issue_events_url": "https://api.github.com/repos/anonUser/anonRepo/issues/events{/number}", + "issues_url": "https://api.github.com/repos/anonUser/anonRepo/issues{/number}", + "keys_url": "https://api.github.com/repos/anonUser/anonRepo/keys{/key_id}", + "labels_url": "https://api.github.com/repos/anonUser/anonRepo/labels{/name}", + "language": null, + "languages_url": "https://api.github.com/repos/anonUser/anonRepo/languages", + "master_branch": "master", + "merges_url": "https://api.github.com/repos/anonUser/anonRepo/merges", + "milestones_url": "https://api.github.com/repos/anonUser/anonRepo/milestones{/number}", + "mirror_url": null, + "name": "anonRepo", + "notifications_url": "https://api.github.com/repos/anonUser/anonRepo/notifications{?since,all,participating}", + "open_issues": 0, + "open_issues_count": 0, + "owner": { + "email": "anonUser@example.com", + "name": "anonUser" }, - { - "kind": "ImageStream", - "apiVersion": "v1", - "metadata": { - "name": "ruby-27-centos7" - }, - "spec": { - "dockerImageRepository": "centos/ruby-27-centos7" - }, - "status": { - "dockerImageRepository": "" - } + "private": false, + "pulls_url": "https://api.github.com/repos/anonUser/anonRepo/pulls{/number}", + "pushed_at": 1.409238007e+09, + "releases_url": "https://api.github.com/repos/anonUser/anonRepo/releases{/id}", + "size": 0, + "ssh_url": "git@github.com:anonUser/anonRepo.git", + "stargazers": 0, + "stargazers_count": 0, + "stargazers_url": "https://api.github.com/repos/anonUser/anonRepo/stargazers", + "statuses_url": "https://api.github.com/repos/anonUser/anonRepo/statuses/{sha}", + "subscribers_url": "https://api.github.com/repos/anonUser/anonRepo/subscribers", + "subscription_url": "https://api.github.com/repos/anonUser/anonRepo/subscription", + "svn_url": "https://github.com/anonUser/anonRepo", + "tags_url": "https://api.github.com/repos/anonUser/anonRepo/tags", + "teams_url": "https://api.github.com/repos/anonUser/anonRepo/teams", + "trees_url": "https://api.github.com/repos/anonUser/anonRepo/git/trees{/sha}", + "updated_at": "2014-08-26T14:34:59Z", + "url": "https://github.com/anonUser/anonRepo", + "watchers": 0, + "watchers_count": 0 + } +} +`) + +func examplesSampleAppGithubWebhookExampleJsonBytes() ([]byte, error) { + return _examplesSampleAppGithubWebhookExampleJson, nil +} + +func examplesSampleAppGithubWebhookExampleJson() (*asset, error) { + bytes, err := examplesSampleAppGithubWebhookExampleJsonBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "examples/sample-app/github-webhook-example.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _examplesQuickstartsCakephpMysqlPersistentJson = []byte(`{ + "apiVersion": "v1", + "kind": "Template", + "labels": { + "app": "cakephp-mysql-persistent", + "template": "cakephp-mysql-persistent" }, - { - "kind": "BuildConfig", - "apiVersion": "v1", - "metadata": { - "name": "ruby-sample-build", - "labels": { - "name": "ruby-sample-build" - }, + "message": "The following service(s) have been created in your project: ${NAME}, ${DATABASE_SERVICE_NAME}.\n\nFor more information about using this template, including OpenShift considerations, see https://github.com/sclorg/cakephp-ex/blob/master/README.md.", + "metadata": { "annotations": { - "template.alpha.openshift.io/wait-for-ready": "true" - } - }, - "spec": { - "triggers": [ - { - "type": "GitHub", - "github": { - "secret": "secret101" - } - }, - { - "type": "Generic", - "generic": { - "secret": "secret101", - "allowEnv": true - } - }, - { - "type": "ConfigChange" - } - ], - "source": { - "type": "Git", - "git": { - "uri": "https://github.com/openshift/ruby-hello-world.git" - } + "description": "An example CakePHP application with a MySQL database. For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/cakephp-ex/blob/master/README.md.", + "iconClass": "icon-php", + "openshift.io/display-name": "CakePHP + MySQL", + "openshift.io/documentation-url": "https://github.com/sclorg/cakephp-ex", + "openshift.io/long-description": "This template defines resources needed to develop a CakePHP application, including a build configuration, application deployment configuration, and database deployment configuration.", + "openshift.io/provider-display-name": "Red Hat, Inc.", + "openshift.io/support-url": "https://access.redhat.com", + "tags": "quickstart,php,cakephp", + "template.openshift.io/bindable": "false" }, - "strategy": { - "type": "Source", - "sourceStrategy": { - "from": { - "kind": "DockerImage", - "name": "centos/ruby-27-centos7:latest" + "name": "cakephp-mysql-persistent" + }, + "objects": [ + { + "apiVersion": "v1", + "kind": "Secret", + "metadata": { + "name": "${NAME}" + }, + "stringData": { + "cakephp-secret-token": "${CAKEPHP_SECRET_TOKEN}", + "cakephp-security-salt": "${CAKEPHP_SECURITY_SALT}", + "database-password": "${DATABASE_PASSWORD}", + "database-user": "${DATABASE_USER}" } - } - }, - "output": { - "to": { - "kind": "ImageStreamTag", - "name": "origin-ruby-sample:latest" - } - }, - "postCommit": { - "script": "bundle exec rake test" }, - "resources": {} - }, - "status": { - "lastVersion": 0 - } - }, - { - "kind": "DeploymentConfig", - "apiVersion": "v1", - "metadata": { - "name": "frontend", - "annotations": { - "template.alpha.openshift.io/wait-for-ready": "true" - } - }, - "spec": { - "strategy": { - "type": "Rolling", - "rollingParams": { - "updatePeriodSeconds": 1, - "intervalSeconds": 1, - "timeoutSeconds": 120, - "pre": { - "failurePolicy": "Abort", - "execNewPod": { - "command": [ - "/bin/true" - ], - "env": [ - { - "name": "CUSTOM_VAR1", - "value": "custom_value1" - } - ], - "containerName": "ruby-helloworld" - } + { + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "annotations": { + "description": "Exposes and load balances the application pods", + "service.alpha.openshift.io/dependencies": "[{\"name\": \"${DATABASE_SERVICE_NAME}\", \"kind\": \"Service\"}]" + }, + "name": "${NAME}" }, - "post": { - "failurePolicy": "Ignore", - "execNewPod": { - "command": [ - "/bin/true" - ], - "env": [ - { - "name": "CUSTOM_VAR2", - "value": "custom_value2" - } + "spec": { + "ports": [ + { + "name": "web", + "port": 8080, + "targetPort": 8080 + } ], - "containerName": "ruby-helloworld" - } + "selector": { + "name": "${NAME}" + } } - }, - "resources": {} }, - "triggers": [ - { - "type": "ImageChange", - "imageChangeParams": { - "automatic": true, - "containerNames": [ - "ruby-helloworld" - ], - "from": { - "kind": "ImageStreamTag", - "name": "origin-ruby-sample:latest" - } + { + "apiVersion": "v1", + "kind": "Route", + "metadata": { + "name": "${NAME}" + }, + "spec": { + "host": "${APPLICATION_DOMAIN}", + "to": { + "kind": "Service", + "name": "${NAME}" + } } - }, - { - "type": "ConfigChange" - } - ], - "replicas": 2, - "selector": { - "name": "frontend" }, - "template": { - "metadata": { - "labels": { - "name": "frontend" + { + "apiVersion": "v1", + "kind": "ImageStream", + "metadata": { + "annotations": { + "description": "Keeps track of changes in the application image" + }, + "name": "${NAME}" } - }, - "spec": { - "containers": [ - { - "name": "ruby-helloworld", - "image": "origin-ruby-sample", - "ports": [ - { - "containerPort": 8080, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "MYSQL_USER", - "valueFrom": { - "secretKeyRef" : { - "name" : "dbsecret", - "key" : "mysql-user" - } - } - }, - { - "name": "MYSQL_PASSWORD", - "valueFrom": { - "secretKeyRef" : { - "name" : "dbsecret", - "key" : "mysql-password" - } - } - }, - { - "name": "MYSQL_DATABASE", - "value": "${MYSQL_DATABASE}" - } - ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst" - } - } - }, - "status": {} - }, - { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "database" - }, - "spec": { - "ports": [ - { - "name": "db", - "protocol": "TCP", - "port": 5434, - "targetPort": 3306, - "nodePort": 0 - } - ], - "selector": { - "name": "database" }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } - }, - { - "kind": "DeploymentConfig", - "apiVersion": "v1", - "metadata": { - "name": "database", - "annotations": { - "template.alpha.openshift.io/wait-for-ready": "true" - } - }, - "spec": { - "strategy": { - "type": "Recreate", - "recreateParams": { - "pre": { - "failurePolicy": "Abort", - "execNewPod": { - "command": [ - "/bin/true" - ], - "env": [ - { - "name": "CUSTOM_VAR1", - "value": "custom_value1" - } - ], - "containerName": "ruby-helloworld-database", - "volumes": ["ruby-helloworld-data"] - } - }, - "mid": { - "failurePolicy": "Abort", - "execNewPod": { - "command": [ - "/bin/true" - ], - "env": [ - { - "name": "CUSTOM_VAR2", - "value": "custom_value2" - } - ], - "containerName": "ruby-helloworld-database", - "volumes": ["ruby-helloworld-data"] - } + { + "apiVersion": "v1", + "kind": "BuildConfig", + "metadata": { + "annotations": { + "description": "Defines how to build the application", + "template.alpha.openshift.io/wait-for-ready": "true" + }, + "name": "${NAME}" }, - "post": { - "failurePolicy": "Ignore", - "execNewPod": { - "command": [ - "/bin/true" - ], - "env": [ - { - "name": "CUSTOM_VAR2", - "value": "custom_value2" - } - ], - "containerName": "ruby-helloworld-database", - "volumes": ["ruby-helloworld-data"] - } + "spec": { + "output": { + "to": { + "kind": "ImageStreamTag", + "name": "${NAME}:latest" + } + }, + "postCommit": { + "script": "./vendor/bin/phpunit" + }, + "source": { + "contextDir": "${CONTEXT_DIR}", + "git": { + "ref": "${SOURCE_REPOSITORY_REF}", + "uri": "${SOURCE_REPOSITORY_URL}" + }, + "type": "Git" + }, + "strategy": { + "sourceStrategy": { + "env": [ + { + "name": "COMPOSER_MIRROR", + "value": "${COMPOSER_MIRROR}" + } + ], + "from": { + "kind": "ImageStreamTag", + "name": "php:${PHP_VERSION}", + "namespace": "${NAMESPACE}" + } + }, + "type": "Source" + }, + "triggers": [ + { + "type": "ImageChange" + }, + { + "type": "ConfigChange" + }, + { + "github": { + "secret": "${GITHUB_WEBHOOK_SECRET}" + }, + "type": "GitHub" + } + ] } - }, - "resources": {} - }, - "triggers": [ - { - "type": "ConfigChange" - } - ], - "replicas": 1, - "selector": { - "name": "database" }, - "template": { - "metadata": { - "labels": { - "name": "database" + { + "apiVersion": "v1", + "kind": "DeploymentConfig", + "metadata": { + "annotations": { + "description": "Defines how to deploy the application server", + "template.alpha.openshift.io/wait-for-ready": "true" + }, + "name": "${NAME}" + }, + "spec": { + "replicas": 1, + "selector": { + "name": "${NAME}" + }, + "strategy": { + "recreateParams": { + "pre": { + "execNewPod": { + "command": [ + "./migrate-database.sh" + ], + "containerName": "cakephp-mysql-persistent" + }, + "failurePolicy": "Retry" + } + }, + "type": "Recreate" + }, + "template": { + "metadata": { + "labels": { + "name": "${NAME}" + }, + "name": "${NAME}" + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "DATABASE_SERVICE_NAME", + "value": "${DATABASE_SERVICE_NAME}" + }, + { + "name": "DATABASE_ENGINE", + "value": "${DATABASE_ENGINE}" + }, + { + "name": "DATABASE_NAME", + "value": "${DATABASE_NAME}" + }, + { + "name": "DATABASE_USER", + "valueFrom": { + "secretKeyRef": { + "key": "database-user", + "name": "${NAME}" + } + } + }, + { + "name": "DATABASE_PASSWORD", + "valueFrom": { + "secretKeyRef": { + "key": "database-password", + "name": "${NAME}" + } + } + }, + { + "name": "CAKEPHP_SECRET_TOKEN", + "valueFrom": { + "secretKeyRef": { + "key": "cakephp-secret-token", + "name": "${NAME}" + } + } + }, + { + "name": "CAKEPHP_SECURITY_SALT", + "valueFrom": { + "secretKeyRef": { + "key": "cakephp-security-salt", + "name": "${NAME}" + } + } + }, + { + "name": "OPCACHE_REVALIDATE_FREQ", + "value": "${OPCACHE_REVALIDATE_FREQ}" + } + ], + "image": " ", + "livenessProbe": { + "httpGet": { + "path": "/health.php", + "port": 8080 + }, + "initialDelaySeconds": 30, + "periodSeconds": 60, + "timeoutSeconds": 3 + }, + "name": "cakephp-mysql-persistent", + "ports": [ + { + "containerPort": 8080 + } + ], + "readinessProbe": { + "httpGet": { + "path": "/health.php", + "port": 8080 + }, + "initialDelaySeconds": 3, + "periodSeconds": 60, + "timeoutSeconds": 3 + }, + "resources": { + "limits": { + "memory": "${MEMORY_LIMIT}" + } + } + } + ] + } + }, + "triggers": [ + { + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "cakephp-mysql-persistent" + ], + "from": { + "kind": "ImageStreamTag", + "name": "${NAME}:latest" + } + }, + "type": "ImageChange" + }, + { + "type": "ConfigChange" + } + ] } - }, - "spec": { - "containers": [ - { - "name": "ruby-helloworld-database", - "image": "centos/mysql-57-centos7:latest", - "ports": [ - { - "containerPort": 3306, - "protocol": "TCP" - } + }, + { + "apiVersion": "v1", + "kind": "PersistentVolumeClaim", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "spec": { + "accessModes": [ + "ReadWriteOnce" ], - "env": [ - { - "name": "MYSQL_USER", - "valueFrom": { - "secretKeyRef" : { - "name" : "dbsecret", - "key" : "mysql-user" - } + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" } - }, - { - "name": "MYSQL_PASSWORD", - "valueFrom": { - "secretKeyRef" : { - "name" : "dbsecret", - "key" : "mysql-password" - } + } + } + }, + { + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "annotations": { + "description": "Exposes the database server" + }, + "name": "${DATABASE_SERVICE_NAME}" + }, + "spec": { + "ports": [ + { + "name": "mysql", + "port": 3306, + "targetPort": 3306 } - }, - { - "name": "MYSQL_DATABASE", - "value": "${MYSQL_DATABASE}" - } - ], - "resources": {}, - "volumeMounts": [ - { - "name": "ruby-helloworld-data", - "mountPath": "/var/lib/mysql/data" - } ], - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "Always", - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "volumes": [ - { - "name": "ruby-helloworld-data", - "emptyDir": { - "medium": "" + "selector": { + "name": "${DATABASE_SERVICE_NAME}" } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst" - } - } - }, - "status": {} - } - ], - "parameters": [ - { - "name": "MYSQL_USER", - "description": "database username", - "generate": "expression", - "from": "user[A-Z0-9]{3}", - "required": true - }, - { - "name": "MYSQL_PASSWORD", - "description": "database password", - "generate": "expression", - "from": "[a-zA-Z0-9]{8}", - "required": true - }, - { - "name": "MYSQL_DATABASE", - "description": "database name", - "value": "root", - "required": true - } - ], - "labels": { - "template": "application-template-stibuild" - } -} -`) - -func examplesSampleAppApplicationTemplatePullspecbuildJsonBytes() ([]byte, error) { - return _examplesSampleAppApplicationTemplatePullspecbuildJson, nil -} - -func examplesSampleAppApplicationTemplatePullspecbuildJson() (*asset, error) { - bytes, err := examplesSampleAppApplicationTemplatePullspecbuildJsonBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "examples/sample-app/application-template-pullspecbuild.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _examplesSampleAppApplicationTemplateStibuildJson = []byte(`{ - "kind": "Template", - "apiVersion": "v1", - "metadata": { - "name": "ruby-helloworld-sample", - "annotations": { - "description": "This example shows how to create a simple ruby application in openshift origin v3", - "iconClass": "icon-ruby", - "tags": "instant-app,ruby,mysql" - } - }, - "objects": [ - { - "kind": "Secret", - "apiVersion": "v1", - "metadata": { - "name": "dbsecret" - }, - "stringData" : { - "mysql-user" : "${MYSQL_USER}", - "mysql-password" : "${MYSQL_PASSWORD}" - } - }, - { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "frontend" - }, - "spec": { - "ports": [ - { - "name": "web", - "protocol": "TCP", - "port": 5432, - "targetPort": 8080, - "nodePort": 0 - } - ], - "selector": { - "name": "frontend" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } - }, - { - "kind": "Route", - "apiVersion": "v1", - "metadata": { - "name": "route-edge", - "annotations": { - "template.openshift.io/expose-uri": "http://{.spec.host}{.spec.path}" - } - }, - "spec": { - "host": "www.example.com", - "to": { - "kind": "Service", - "name": "frontend" - }, - "tls": { - "termination": "edge" - } - }, - "status": {} - }, - { - "kind": "ImageStream", - "apiVersion": "v1", - "metadata": { - "name": "origin-ruby-sample" - }, - "spec": {}, - "status": { - "dockerImageRepository": "" - } - }, - { - "kind": "ImageStream", - "apiVersion": "v1", - "metadata": { - "name": "ruby-27-centos7" - }, - "spec": { - "dockerImageRepository": "centos/ruby-27-centos7" - }, - "status": { - "dockerImageRepository": "" - } - }, - { - "kind": "BuildConfig", - "apiVersion": "v1", - "metadata": { - "name": "ruby-sample-build", - "labels": { - "name": "ruby-sample-build" + } }, - "annotations": { - "template.alpha.openshift.io/wait-for-ready": "true" - } - }, - "spec": { - "triggers": [ - { - "type": "GitHub", - "github": { - "secret": "secret101" - } - }, - { - "type": "Generic", - "generic": { - "secret": "secret101", - "allowEnv": true + { + "apiVersion": "v1", + "kind": "DeploymentConfig", + "metadata": { + "annotations": { + "description": "Defines how to deploy the database", + "template.alpha.openshift.io/wait-for-ready": "true" + }, + "name": "${DATABASE_SERVICE_NAME}" + }, + "spec": { + "replicas": 1, + "selector": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "strategy": { + "type": "Recreate" + }, + "template": { + "metadata": { + "labels": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "name": "${DATABASE_SERVICE_NAME}" + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "MYSQL_USER", + "valueFrom": { + "secretKeyRef": { + "key": "database-user", + "name": "${NAME}" + } + } + }, + { + "name": "MYSQL_PASSWORD", + "valueFrom": { + "secretKeyRef": { + "key": "database-password", + "name": "${NAME}" + } + } + }, + { + "name": "MYSQL_DATABASE", + "value": "${DATABASE_NAME}" + } + ], + "image": " ", + "livenessProbe": { + "initialDelaySeconds": 30, + "tcpSocket": { + "port": 3306 + }, + "timeoutSeconds": 1 + }, + "name": "mysql", + "ports": [ + { + "containerPort": 3306 + } + ], + "readinessProbe": { + "exec": { + "command": [ + "/bin/sh", + "-i", + "-c", + "MYSQL_PWD='${DATABASE_PASSWORD}' mysql -h 127.0.0.1 -u ${DATABASE_USER} -D ${DATABASE_NAME} -e 'SELECT 1'" + ] + }, + "initialDelaySeconds": 5, + "timeoutSeconds": 1 + }, + "resources": { + "limits": { + "memory": "${MEMORY_MYSQL_LIMIT}" + } + }, + "volumeMounts": [ + { + "mountPath": "/var/lib/mysql/data", + "name": "${DATABASE_SERVICE_NAME}-data" + } + ] + } + ], + "volumes": [ + { + "name": "${DATABASE_SERVICE_NAME}-data", + "persistentVolumeClaim": { + "claimName": "${DATABASE_SERVICE_NAME}" + } + } + ] + } + }, + "triggers": [ + { + "imageChangeParams": { + "automatic": true, + "containerNames": [ + "mysql" + ], + "from": { + "kind": "ImageStreamTag", + "name": "mysql:5.7", + "namespace": "${NAMESPACE}" + } + }, + "type": "ImageChange" + }, + { + "type": "ConfigChange" + } + ] } - }, - { - "type": "ImageChange", - "imageChange": {} - }, - { - "type": "ConfigChange" - } - ], - "source": { - "type": "Git", - "git": { - "uri": "https://github.com/openshift/ruby-hello-world.git" - } + } + ], + "parameters": [ + { + "description": "The name assigned to all of the frontend objects defined in this template.", + "displayName": "Name", + "name": "NAME", + "required": true, + "value": "cakephp-mysql-persistent" }, - "strategy": { - "type": "Source", - "sourceStrategy": { - "from": { - "kind": "ImageStreamTag", - "name": "ruby-27-centos7:latest" - }, - "env": [ - { - "name": "EXAMPLE", - "value": "sample-app" - } - ] - } + { + "description": "The OpenShift Namespace where the ImageStream resides.", + "displayName": "Namespace", + "name": "NAMESPACE", + "required": true, + "value": "openshift" }, - "output": { - "to": { - "kind": "ImageStreamTag", - "name": "origin-ruby-sample:latest" - } + { + "description": "Version of PHP image to be used (7.1 or latest).", + "displayName": "PHP Version", + "name": "PHP_VERSION", + "required": true, + "value": "7.1" }, - "postCommit": { - "script": "bundle exec rake test" + { + "description": "Maximum amount of memory the CakePHP container can use.", + "displayName": "Memory Limit", + "name": "MEMORY_LIMIT", + "required": true, + "value": "512Mi" }, - "resources": {} - }, - "status": { - "lastVersion": 0 - } + { + "description": "Maximum amount of memory the MySQL container can use.", + "displayName": "Memory Limit (MySQL)", + "name": "MEMORY_MYSQL_LIMIT", + "required": true, + "value": "512Mi" + }, + { + "description": "Volume space available for data, e.g. 512Mi, 2Gi", + "displayName": "Volume Capacity", + "name": "VOLUME_CAPACITY", + "required": true, + "value": "1Gi" + }, + { + "description": "The URL of the repository with your application source code.", + "displayName": "Git Repository URL", + "name": "SOURCE_REPOSITORY_URL", + "required": true, + "value": "https://github.com/sclorg/cakephp-ex.git" + }, + { + "description": "Set this to a branch name, tag or other ref of your repository if you are not using the default branch.", + "displayName": "Git Reference", + "name": "SOURCE_REPOSITORY_REF" + }, + { + "description": "Set this to the relative path to your project if it is not in the root of your repository.", + "displayName": "Context Directory", + "name": "CONTEXT_DIR" + }, + { + "description": "The exposed hostname that will route to the CakePHP service, if left blank a value will be defaulted.", + "displayName": "Application Hostname", + "name": "APPLICATION_DOMAIN", + "value": "" + }, + { + "description": "Github trigger secret. A difficult to guess string encoded as part of the webhook URL. Not encrypted.", + "displayName": "GitHub Webhook Secret", + "from": "[a-zA-Z0-9]{40}", + "generate": "expression", + "name": "GITHUB_WEBHOOK_SECRET" + }, + { + "displayName": "Database Service Name", + "name": "DATABASE_SERVICE_NAME", + "required": true, + "value": "mysql" + }, + { + "description": "Database engine: postgresql, mysql or sqlite (default).", + "displayName": "Database Engine", + "name": "DATABASE_ENGINE", + "required": true, + "value": "mysql" + }, + { + "displayName": "Database Name", + "name": "DATABASE_NAME", + "required": true, + "value": "default" + }, + { + "displayName": "Database User", + "name": "DATABASE_USER", + "required": true, + "value": "cakephp" + }, + { + "displayName": "Database Password", + "from": "[a-zA-Z0-9]{16}", + "generate": "expression", + "name": "DATABASE_PASSWORD" + }, + { + "description": "Set this to a long random string.", + "displayName": "CakePHP secret token", + "from": "[\\w]{50}", + "generate": "expression", + "name": "CAKEPHP_SECRET_TOKEN" + }, + { + "description": "Security salt for session hash.", + "displayName": "CakePHP Security Salt", + "from": "[a-zA-Z0-9]{40}", + "generate": "expression", + "name": "CAKEPHP_SECURITY_SALT" + }, + { + "description": "How often to check script timestamps for updates, in seconds. 0 will result in OPcache checking for updates on every request.", + "displayName": "OPcache Revalidation Frequency", + "name": "OPCACHE_REVALIDATE_FREQ", + "value": "2" + }, + { + "description": "The custom Composer mirror URL", + "displayName": "Custom Composer Mirror URL", + "name": "COMPOSER_MIRROR", + "value": "" + } + ] +}`) + +func examplesQuickstartsCakephpMysqlPersistentJsonBytes() ([]byte, error) { + return _examplesQuickstartsCakephpMysqlPersistentJson, nil +} + +func examplesQuickstartsCakephpMysqlPersistentJson() (*asset, error) { + bytes, err := examplesQuickstartsCakephpMysqlPersistentJsonBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "examples/quickstarts/cakephp-mysql-persistent.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _examplesQuickstartsCakephpMysqlJson = []byte(`{ + "apiVersion": "v1", + "kind": "Template", + "labels": { + "app": "cakephp-mysql-example", + "template": "cakephp-mysql-example" }, - { - "kind": "DeploymentConfig", - "apiVersion": "v1", - "metadata": { - "name": "frontend", + "message": "The following service(s) have been created in your project: ${NAME}, ${DATABASE_SERVICE_NAME}.\n\nFor more information about using this template, including OpenShift considerations, see https://github.com/sclorg/cakephp-ex/blob/master/README.md.", + "metadata": { "annotations": { - "template.alpha.openshift.io/wait-for-ready": "true" - } - }, - "spec": { - "strategy": { - "type": "Rolling", - "rollingParams": { - "updatePeriodSeconds": 1, - "intervalSeconds": 1, - "timeoutSeconds": 120, - "pre": { - "failurePolicy": "Abort", - "execNewPod": { - "command": [ - "/bin/true" - ], - "env": [ - { - "name": "CUSTOM_VAR1", - "value": "custom_value1" - } - ], - "containerName": "ruby-helloworld" - } - }, - "post": { - "failurePolicy": "Ignore", - "execNewPod": { - "command": [ - "/bin/true" - ], - "env": [ - { - "name": "CUSTOM_VAR2", - "value": "custom_value2" - } - ], - "containerName": "ruby-helloworld" - } - } - }, - "resources": {} + "description": "An example CakePHP application with a MySQL database. For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/cakephp-ex/blob/master/README.md.\n\nWARNING: Any data stored will be lost upon pod destruction. Only use this template for testing.", + "iconClass": "icon-php", + "openshift.io/display-name": "CakePHP + MySQL (Ephemeral)", + "openshift.io/documentation-url": "https://github.com/sclorg/cakephp-ex", + "openshift.io/long-description": "This template defines resources needed to develop a CakePHP application, including a build configuration, application deployment configuration, and database deployment configuration. The database is stored in non-persistent storage, so this configuration should be used for experimental purposes only.", + "openshift.io/provider-display-name": "Red Hat, Inc.", + "openshift.io/support-url": "https://access.redhat.com", + "tags": "quickstart,php,cakephp", + "template.openshift.io/bindable": "false" }, - "triggers": [ - { - "type": "ImageChange", - "imageChangeParams": { - "automatic": true, - "containerNames": [ - "ruby-helloworld" - ], - "from": { - "kind": "ImageStreamTag", - "name": "origin-ruby-sample:latest" - } + "name": "cakephp-mysql-example" + }, + "objects": [ + { + "apiVersion": "v1", + "kind": "Secret", + "metadata": { + "name": "${NAME}" + }, + "stringData": { + "cakephp-secret-token": "${CAKEPHP_SECRET_TOKEN}", + "cakephp-security-salt": "${CAKEPHP_SECURITY_SALT}", + "database-password": "${DATABASE_PASSWORD}", + "database-user": "${DATABASE_USER}" } - }, - { - "type": "ConfigChange" - } - ], - "replicas": 2, - "selector": { - "name": "frontend" }, - "template": { - "metadata": { - "labels": { - "name": "frontend" - } - }, - "spec": { - "containers": [ - { - "name": "ruby-helloworld", - "image": "origin-ruby-sample", + { + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "annotations": { + "description": "Exposes and load balances the application pods", + "service.alpha.openshift.io/dependencies": "[{\"name\": \"${DATABASE_SERVICE_NAME}\", \"kind\": \"Service\"}]" + }, + "name": "${NAME}" + }, + "spec": { "ports": [ - { - "containerPort": 8080, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "MYSQL_USER", - "valueFrom": { - "secretKeyRef" : { - "name" : "dbsecret", - "key" : "mysql-user" - } - } - }, - { - "name": "MYSQL_PASSWORD", - "valueFrom": { - "secretKeyRef" : { - "name" : "dbsecret", - "key" : "mysql-password" - } + { + "name": "web", + "port": 8080, + "targetPort": 8080 } - }, - { - "name": "MYSQL_DATABASE", - "value": "${MYSQL_DATABASE}" - } ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "securityContext": { - "capabilities": {}, - "privileged": false + "selector": { + "name": "${NAME}" } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst" - } - } - }, - "status": {} - }, - { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "database" - }, - "spec": { - "ports": [ - { - "name": "db", - "protocol": "TCP", - "port": 5434, - "targetPort": 3306, - "nodePort": 0 - } - ], - "selector": { - "name": "database" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } - }, - { - "kind": "DeploymentConfig", - "apiVersion": "v1", - "metadata": { - "name": "database", - "annotations": { - "template.alpha.openshift.io/wait-for-ready": "true" - } - }, - "spec": { - "strategy": { - "type": "Recreate", - "recreateParams": { - "pre": { - "failurePolicy": "Abort", - "execNewPod": { - "command": [ - "/bin/true" - ], - "env": [ - { - "name": "CUSTOM_VAR1", - "value": "custom_value1" - } - ], - "containerName": "ruby-helloworld-database", - "volumes": ["ruby-helloworld-data"] - } - }, - "mid": { - "failurePolicy": "Abort", - "execNewPod": { - "command": [ - "/bin/true" - ], - "env": [ - { - "name": "CUSTOM_VAR2", - "value": "custom_value2" - } - ], - "containerName": "ruby-helloworld-database", - "volumes": ["ruby-helloworld-data"] - } - }, - "post": { - "failurePolicy": "Ignore", - "execNewPod": { - "command": [ - "/bin/true" - ], - "env": [ - { - "name": "CUSTOM_VAR2", - "value": "custom_value2" - } - ], - "containerName": "ruby-helloworld-database", - "volumes": ["ruby-helloworld-data"] - } - } - }, - "resources": {} - }, - "triggers": [ - { - "type": "ConfigChange" - } - ], - "replicas": 1, - "selector": { - "name": "database" - }, - "template": { - "metadata": { - "labels": { - "name": "database" - } - }, - "spec": { - "containers": [ - { - "name": "ruby-helloworld-database", - "image": "centos/mysql-57-centos7:latest", - "ports": [ - { - "containerPort": 3306, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "MYSQL_USER", - "valueFrom": { - "secretKeyRef" : { - "name" : "dbsecret", - "key" : "mysql-user" - } - } - }, - { - "name": "MYSQL_PASSWORD", - "valueFrom": { - "secretKeyRef" : { - "name" : "dbsecret", - "key" : "mysql-password" - } - } - }, - { - "name": "MYSQL_DATABASE", - "value": "${MYSQL_DATABASE}" - } - ], - "resources": {}, - "volumeMounts": [ - { - "name": "ruby-helloworld-data", - "mountPath": "/var/lib/mysql/data" - } - ], - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "Always", - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "volumes": [ - { - "name": "ruby-helloworld-data", - "emptyDir": { - "medium": "" - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst" - } - } - }, - "status": {} - } - ], - "parameters": [ - { - "name": "MYSQL_USER", - "description": "database username", - "generate": "expression", - "from": "user[A-Z0-9]{3}", - "required": true - }, - { - "name": "MYSQL_PASSWORD", - "description": "database password", - "generate": "expression", - "from": "[a-zA-Z0-9]{8}", - "required": true - }, - { - "name": "MYSQL_DATABASE", - "description": "database name", - "value": "root", - "required": true - } - ], - "labels": { - "template": "application-template-stibuild" - } -} -`) - -func examplesSampleAppApplicationTemplateStibuildJsonBytes() ([]byte, error) { - return _examplesSampleAppApplicationTemplateStibuildJson, nil -} - -func examplesSampleAppApplicationTemplateStibuildJson() (*asset, error) { - bytes, err := examplesSampleAppApplicationTemplateStibuildJsonBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "examples/sample-app/application-template-stibuild.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _examplesSampleAppCleanupSh = []byte(`#!/bin/sh - -echo "Killing openshift all-in-one server ..." -sudo pkill -x openshift - -echo "Stopping all k8s containers on host ..." -sudo docker ps --format='{{.Names}}' | grep -E '^k8s_' | xargs -l -r sudo docker stop - -echo "Unmounting openshift local volumes ..." -mount | grep "openshift.local.volumes" | awk '{ print $3}' | xargs -l -r sudo umount - -echo "Cleaning up openshift runtime files ..." -sudo rm -rf openshift.local.* - - -`) - -func examplesSampleAppCleanupShBytes() ([]byte, error) { - return _examplesSampleAppCleanupSh, nil -} - -func examplesSampleAppCleanupSh() (*asset, error) { - bytes, err := examplesSampleAppCleanupShBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "examples/sample-app/cleanup.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _examplesSampleAppGithubWebhookExampleJson = []byte(`{ - "after": "9bdc3a26ff933b32f3e558636b58aea86a69f051", - "before": "0000000000000000000000000000000000000000", - "commits": [ - { - "added": [ - "LICENSE" - ], - "author": { - "email": "anonUser@example.com", - "name": "Anonymous User" - }, - "committer": { - "email": "anonUser@example.com", - "name": "Anonymous User" - }, - "distinct": true, - "id": "9bdc3a26ff933b32f3e558636b58aea86a69f051", - "message": "Added license", - "modified": [], - "removed": [], - "timestamp": "2014-08-28T16:55:36+02:00", - "url": "https://github.com/anonUser/anonRepo/commit/9bdc3a26ff933b32f3e558636b58aea86a69f051" - } - ], - "compare": "https://github.com/anonUser/anonRepo/commit/9bdc3a26ff93", - "created": true, - "deleted": false, - "forced": true, - "head_commit": { - "added": [ - "LICENSE" - ], - "author": { - "email": "anonUser@example.com", - "name": "Anonymous User" - }, - "committer": { - "email": "anonUser@example.com", - "name": "Anonymous User" - }, - "distinct": true, - "id": "", - "message": "Added license", - "modified": [], - "removed": [], - "timestamp": "2014-08-28T16:55:36+02:00", - "url": "https://github.com/anonUser/anonRepo/commit/9bdc3a26ff933b32f3e558636b58aea86a69f051" - }, - "pusher": { - "email": "anonUser@example.com", - "name": "anonUser" - }, - "ref": "refs/heads/master", - "repository": { - "archive_url": "https://api.github.com/repos/anonUser/anonRepo/{archive_format}{/ref}", - "assignees_url": "https://api.github.com/repos/anonUser/anonRepo/assignees{/user}", - "blobs_url": "https://api.github.com/repos/anonUser/anonRepo/git/blobs{/sha}", - "branches_url": "https://api.github.com/repos/anonUser/anonRepo/branches{/branch}", - "clone_url": "https://github.com/anonUser/anonRepo.git", - "collaborators_url": "https://api.github.com/repos/anonUser/anonRepo/collaborators{/collaborator}", - "comments_url": "https://api.github.com/repos/anonUser/anonRepo/comments{/number}", - "commits_url": "https://api.github.com/repos/anonUser/anonRepo/commits{/sha}", - "compare_url": "https://api.github.com/repos/anonUser/anonRepo/compare/{base}...{head}", - "contents_url": "https://api.github.com/repos/anonUser/anonRepo/contents/{+path}", - "contributors_url": "https://api.github.com/repos/anonUser/anonRepo/contributors", - "created_at": 1.409063699e+09, - "default_branch": "master", - "description": "Git webhook implementation in Go.", - "downloads_url": "https://api.github.com/repos/anonUser/anonRepo/downloads", - "events_url": "https://api.github.com/repos/anonUser/anonRepo/events", - "fork": false, - "forks": 0, - "forks_count": 0, - "forks_url": "https://api.github.com/repos/anonUser/anonRepo/forks", - "full_name": "anonUser/anonRepo", - "git_commits_url": "https://api.github.com/repos/anonUser/anonRepo/git/commits{/sha}", - "git_refs_url": "https://api.github.com/repos/anonUser/anonRepo/git/refs{/sha}", - "git_tags_url": "https://api.github.com/repos/anonUser/anonRepo/git/tags{/sha}", - "git_url": "git://github.com/anonUser/anonRepo.git", - "has_downloads": true, - "has_issues": true, - "has_wiki": true, - "homepage": null, - "hooks_url": "https://api.github.com/repos/anonUser/anonRepo/hooks", - "html_url": "https://github.com/anonUser/anonRepo", - "id": 2.3354788e+07, - "issue_comment_url": "https://api.github.com/repos/anonUser/anonRepo/issues/comments/{number}", - "issue_events_url": "https://api.github.com/repos/anonUser/anonRepo/issues/events{/number}", - "issues_url": "https://api.github.com/repos/anonUser/anonRepo/issues{/number}", - "keys_url": "https://api.github.com/repos/anonUser/anonRepo/keys{/key_id}", - "labels_url": "https://api.github.com/repos/anonUser/anonRepo/labels{/name}", - "language": null, - "languages_url": "https://api.github.com/repos/anonUser/anonRepo/languages", - "master_branch": "master", - "merges_url": "https://api.github.com/repos/anonUser/anonRepo/merges", - "milestones_url": "https://api.github.com/repos/anonUser/anonRepo/milestones{/number}", - "mirror_url": null, - "name": "anonRepo", - "notifications_url": "https://api.github.com/repos/anonUser/anonRepo/notifications{?since,all,participating}", - "open_issues": 0, - "open_issues_count": 0, - "owner": { - "email": "anonUser@example.com", - "name": "anonUser" - }, - "private": false, - "pulls_url": "https://api.github.com/repos/anonUser/anonRepo/pulls{/number}", - "pushed_at": 1.409238007e+09, - "releases_url": "https://api.github.com/repos/anonUser/anonRepo/releases{/id}", - "size": 0, - "ssh_url": "git@github.com:anonUser/anonRepo.git", - "stargazers": 0, - "stargazers_count": 0, - "stargazers_url": "https://api.github.com/repos/anonUser/anonRepo/stargazers", - "statuses_url": "https://api.github.com/repos/anonUser/anonRepo/statuses/{sha}", - "subscribers_url": "https://api.github.com/repos/anonUser/anonRepo/subscribers", - "subscription_url": "https://api.github.com/repos/anonUser/anonRepo/subscription", - "svn_url": "https://github.com/anonUser/anonRepo", - "tags_url": "https://api.github.com/repos/anonUser/anonRepo/tags", - "teams_url": "https://api.github.com/repos/anonUser/anonRepo/teams", - "trees_url": "https://api.github.com/repos/anonUser/anonRepo/git/trees{/sha}", - "updated_at": "2014-08-26T14:34:59Z", - "url": "https://github.com/anonUser/anonRepo", - "watchers": 0, - "watchers_count": 0 - } -} -`) - -func examplesSampleAppGithubWebhookExampleJsonBytes() ([]byte, error) { - return _examplesSampleAppGithubWebhookExampleJson, nil -} - -func examplesSampleAppGithubWebhookExampleJson() (*asset, error) { - bytes, err := examplesSampleAppGithubWebhookExampleJsonBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "examples/sample-app/github-webhook-example.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _examplesQuickstartsCakephpMysqlPersistentJson = []byte(`{ - "apiVersion": "v1", - "kind": "Template", - "labels": { - "app": "cakephp-mysql-persistent", - "template": "cakephp-mysql-persistent" - }, - "message": "The following service(s) have been created in your project: ${NAME}, ${DATABASE_SERVICE_NAME}.\n\nFor more information about using this template, including OpenShift considerations, see https://github.com/sclorg/cakephp-ex/blob/master/README.md.", - "metadata": { - "annotations": { - "description": "An example CakePHP application with a MySQL database. For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/cakephp-ex/blob/master/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "CakePHP + MySQL", - "openshift.io/documentation-url": "https://github.com/sclorg/cakephp-ex", - "openshift.io/long-description": "This template defines resources needed to develop a CakePHP application, including a build configuration, application deployment configuration, and database deployment configuration.", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "openshift.io/support-url": "https://access.redhat.com", - "tags": "quickstart,php,cakephp", - "template.openshift.io/bindable": "false" - }, - "name": "cakephp-mysql-persistent" - }, - "objects": [ - { - "apiVersion": "v1", - "kind": "Secret", - "metadata": { - "name": "${NAME}" - }, - "stringData": { - "cakephp-secret-token": "${CAKEPHP_SECRET_TOKEN}", - "cakephp-security-salt": "${CAKEPHP_SECURITY_SALT}", - "database-password": "${DATABASE_PASSWORD}", - "database-user": "${DATABASE_USER}" - } - }, - { - "apiVersion": "v1", - "kind": "Service", - "metadata": { - "annotations": { - "description": "Exposes and load balances the application pods", - "service.alpha.openshift.io/dependencies": "[{\"name\": \"${DATABASE_SERVICE_NAME}\", \"kind\": \"Service\"}]" - }, - "name": "${NAME}" - }, - "spec": { - "ports": [ - { - "name": "web", - "port": 8080, - "targetPort": 8080 - } - ], - "selector": { - "name": "${NAME}" - } - } + } }, { "apiVersion": "v1", @@ -8207,7 +6827,7 @@ var _examplesQuickstartsCakephpMysqlPersistentJson = []byte(`{ "command": [ "./migrate-database.sh" ], - "containerName": "cakephp-mysql-persistent" + "containerName": "cakephp-mysql-example" }, "failurePolicy": "Retry" } @@ -8288,7 +6908,7 @@ var _examplesQuickstartsCakephpMysqlPersistentJson = []byte(`{ "periodSeconds": 60, "timeoutSeconds": 3 }, - "name": "cakephp-mysql-persistent", + "name": "cakephp-mysql-example", "ports": [ { "containerPort": 8080 @@ -8317,7 +6937,7 @@ var _examplesQuickstartsCakephpMysqlPersistentJson = []byte(`{ "imageChangeParams": { "automatic": true, "containerNames": [ - "cakephp-mysql-persistent" + "cakephp-mysql-example" ], "from": { "kind": "ImageStreamTag", @@ -8332,23 +6952,6 @@ var _examplesQuickstartsCakephpMysqlPersistentJson = []byte(`{ ] } }, - { - "apiVersion": "v1", - "kind": "PersistentVolumeClaim", - "metadata": { - "name": "${DATABASE_SERVICE_NAME}" - }, - "spec": { - "accessModes": [ - "ReadWriteOnce" - ], - "resources": { - "requests": { - "storage": "${VOLUME_CAPACITY}" - } - } - } - }, { "apiVersion": "v1", "kind": "Service", @@ -8457,17 +7060,15 @@ var _examplesQuickstartsCakephpMysqlPersistentJson = []byte(`{ "volumeMounts": [ { "mountPath": "/var/lib/mysql/data", - "name": "${DATABASE_SERVICE_NAME}-data" + "name": "data" } ] } ], "volumes": [ { - "name": "${DATABASE_SERVICE_NAME}-data", - "persistentVolumeClaim": { - "claimName": "${DATABASE_SERVICE_NAME}" - } + "emptyDir": {}, + "name": "data" } ] } @@ -8500,7 +7101,7 @@ var _examplesQuickstartsCakephpMysqlPersistentJson = []byte(`{ "displayName": "Name", "name": "NAME", "required": true, - "value": "cakephp-mysql-persistent" + "value": "cakephp-mysql-example" }, { "description": "The OpenShift Namespace where the ImageStream resides.", @@ -8530,13 +7131,6 @@ var _examplesQuickstartsCakephpMysqlPersistentJson = []byte(`{ "required": true, "value": "512Mi" }, - { - "description": "Volume space available for data, e.g. 512Mi, 2Gi", - "displayName": "Volume Capacity", - "name": "VOLUME_CAPACITY", - "required": true, - "value": "1Gi" - }, { "description": "The URL of the repository with your application source code.", "displayName": "Git Repository URL", @@ -8627,42 +7221,42 @@ var _examplesQuickstartsCakephpMysqlPersistentJson = []byte(`{ ] }`) -func examplesQuickstartsCakephpMysqlPersistentJsonBytes() ([]byte, error) { - return _examplesQuickstartsCakephpMysqlPersistentJson, nil +func examplesQuickstartsCakephpMysqlJsonBytes() ([]byte, error) { + return _examplesQuickstartsCakephpMysqlJson, nil } -func examplesQuickstartsCakephpMysqlPersistentJson() (*asset, error) { - bytes, err := examplesQuickstartsCakephpMysqlPersistentJsonBytes() +func examplesQuickstartsCakephpMysqlJson() (*asset, error) { + bytes, err := examplesQuickstartsCakephpMysqlJsonBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "examples/quickstarts/cakephp-mysql-persistent.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "examples/quickstarts/cakephp-mysql.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _examplesQuickstartsCakephpMysqlJson = []byte(`{ +var _examplesQuickstartsDancerMysqlPersistentJson = []byte(`{ "apiVersion": "v1", "kind": "Template", "labels": { - "app": "cakephp-mysql-example", - "template": "cakephp-mysql-example" + "app": "dancer-mysql-persistent", + "template": "dancer-mysql-persistent" }, - "message": "The following service(s) have been created in your project: ${NAME}, ${DATABASE_SERVICE_NAME}.\n\nFor more information about using this template, including OpenShift considerations, see https://github.com/sclorg/cakephp-ex/blob/master/README.md.", + "message": "The following service(s) have been created in your project: ${NAME}, ${DATABASE_SERVICE_NAME}.\n\nFor more information about using this template, including OpenShift considerations, see https://github.com/sclorg/dancer-ex/blob/master/README.md.", "metadata": { "annotations": { - "description": "An example CakePHP application with a MySQL database. For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/cakephp-ex/blob/master/README.md.\n\nWARNING: Any data stored will be lost upon pod destruction. Only use this template for testing.", - "iconClass": "icon-php", - "openshift.io/display-name": "CakePHP + MySQL (Ephemeral)", - "openshift.io/documentation-url": "https://github.com/sclorg/cakephp-ex", - "openshift.io/long-description": "This template defines resources needed to develop a CakePHP application, including a build configuration, application deployment configuration, and database deployment configuration. The database is stored in non-persistent storage, so this configuration should be used for experimental purposes only.", + "description": "An example Dancer application with a MySQL database. For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/dancer-ex/blob/master/README.md.", + "iconClass": "icon-perl", + "openshift.io/display-name": "Dancer + MySQL", + "openshift.io/documentation-url": "https://github.com/sclorg/dancer-ex", + "openshift.io/long-description": "This template defines resources needed to develop a Dancer based application, including a build configuration, application deployment configuration, and database deployment configuration.", "openshift.io/provider-display-name": "Red Hat, Inc.", "openshift.io/support-url": "https://access.redhat.com", - "tags": "quickstart,php,cakephp", + "tags": "quickstart,perl,dancer", "template.openshift.io/bindable": "false" }, - "name": "cakephp-mysql-example" + "name": "dancer-mysql-persistent" }, "objects": [ { @@ -8672,10 +7266,9 @@ var _examplesQuickstartsCakephpMysqlJson = []byte(`{ "name": "${NAME}" }, "stringData": { - "cakephp-secret-token": "${CAKEPHP_SECRET_TOKEN}", - "cakephp-security-salt": "${CAKEPHP_SECURITY_SALT}", "database-password": "${DATABASE_PASSWORD}", - "database-user": "${DATABASE_USER}" + "database-user": "${DATABASE_USER}", + "keybase": "${SECRET_KEY_BASE}" } }, { @@ -8743,7 +7336,7 @@ var _examplesQuickstartsCakephpMysqlJson = []byte(`{ } }, "postCommit": { - "script": "./vendor/bin/phpunit" + "script": "perl -I extlib/lib/perl5 -I lib t/*" }, "source": { "contextDir": "${CONTEXT_DIR}", @@ -8757,13 +7350,13 @@ var _examplesQuickstartsCakephpMysqlJson = []byte(`{ "sourceStrategy": { "env": [ { - "name": "COMPOSER_MIRROR", - "value": "${COMPOSER_MIRROR}" + "name": "CPAN_MIRROR", + "value": "${CPAN_MIRROR}" } ], "from": { "kind": "ImageStreamTag", - "name": "php:${PHP_VERSION}", + "name": "perl:5.26", "namespace": "${NAMESPACE}" } }, @@ -8801,17 +7394,6 @@ var _examplesQuickstartsCakephpMysqlJson = []byte(`{ "name": "${NAME}" }, "strategy": { - "recreateParams": { - "pre": { - "execNewPod": { - "command": [ - "./migrate-database.sh" - ], - "containerName": "cakephp-mysql-example" - }, - "failurePolicy": "Retry" - } - }, "type": "Recreate" }, "template": { @@ -8830,15 +7412,7 @@ var _examplesQuickstartsCakephpMysqlJson = []byte(`{ "value": "${DATABASE_SERVICE_NAME}" }, { - "name": "DATABASE_ENGINE", - "value": "${DATABASE_ENGINE}" - }, - { - "name": "DATABASE_NAME", - "value": "${DATABASE_NAME}" - }, - { - "name": "DATABASE_USER", + "name": "MYSQL_USER", "valueFrom": { "secretKeyRef": { "key": "database-user", @@ -8847,7 +7421,7 @@ var _examplesQuickstartsCakephpMysqlJson = []byte(`{ } }, { - "name": "DATABASE_PASSWORD", + "name": "MYSQL_PASSWORD", "valueFrom": { "secretKeyRef": { "key": "database-password", @@ -8856,39 +7430,33 @@ var _examplesQuickstartsCakephpMysqlJson = []byte(`{ } }, { - "name": "CAKEPHP_SECRET_TOKEN", - "valueFrom": { - "secretKeyRef": { - "key": "cakephp-secret-token", - "name": "${NAME}" - } - } + "name": "MYSQL_DATABASE", + "value": "${DATABASE_NAME}" }, { - "name": "CAKEPHP_SECURITY_SALT", + "name": "SECRET_KEY_BASE", "valueFrom": { "secretKeyRef": { - "key": "cakephp-security-salt", + "key": "keybase", "name": "${NAME}" } } }, { - "name": "OPCACHE_REVALIDATE_FREQ", - "value": "${OPCACHE_REVALIDATE_FREQ}" + "name": "PERL_APACHE2_RELOAD", + "value": "${PERL_APACHE2_RELOAD}" } ], "image": " ", "livenessProbe": { "httpGet": { - "path": "/health.php", + "path": "/health", "port": 8080 }, "initialDelaySeconds": 30, - "periodSeconds": 60, "timeoutSeconds": 3 }, - "name": "cakephp-mysql-example", + "name": "dancer-mysql-persistent", "ports": [ { "containerPort": 8080 @@ -8896,11 +7464,10 @@ var _examplesQuickstartsCakephpMysqlJson = []byte(`{ ], "readinessProbe": { "httpGet": { - "path": "/health.php", + "path": "/health", "port": 8080 }, "initialDelaySeconds": 3, - "periodSeconds": 60, "timeoutSeconds": 3 }, "resources": { @@ -8917,7 +7484,7 @@ var _examplesQuickstartsCakephpMysqlJson = []byte(`{ "imageChangeParams": { "automatic": true, "containerNames": [ - "cakephp-mysql-example" + "dancer-mysql-persistent" ], "from": { "kind": "ImageStreamTag", @@ -8932,6 +7499,23 @@ var _examplesQuickstartsCakephpMysqlJson = []byte(`{ ] } }, + { + "apiVersion": "v1", + "kind": "PersistentVolumeClaim", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "spec": { + "accessModes": [ + "ReadWriteOnce" + ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + }, { "apiVersion": "v1", "kind": "Service", @@ -9040,15 +7624,17 @@ var _examplesQuickstartsCakephpMysqlJson = []byte(`{ "volumeMounts": [ { "mountPath": "/var/lib/mysql/data", - "name": "data" + "name": "${DATABASE_SERVICE_NAME}-data" } ] } ], "volumes": [ { - "emptyDir": {}, - "name": "data" + "name": "${DATABASE_SERVICE_NAME}-data", + "persistentVolumeClaim": { + "claimName": "${DATABASE_SERVICE_NAME}" + } } ] } @@ -9081,7 +7667,7 @@ var _examplesQuickstartsCakephpMysqlJson = []byte(`{ "displayName": "Name", "name": "NAME", "required": true, - "value": "cakephp-mysql-example" + "value": "dancer-mysql-persistent" }, { "description": "The OpenShift Namespace where the ImageStream resides.", @@ -9091,14 +7677,7 @@ var _examplesQuickstartsCakephpMysqlJson = []byte(`{ "value": "openshift" }, { - "description": "Version of PHP image to be used (7.1 or latest).", - "displayName": "PHP Version", - "name": "PHP_VERSION", - "required": true, - "value": "7.1" - }, - { - "description": "Maximum amount of memory the CakePHP container can use.", + "description": "Maximum amount of memory the Perl Dancer container can use.", "displayName": "Memory Limit", "name": "MEMORY_LIMIT", "required": true, @@ -9111,12 +7690,19 @@ var _examplesQuickstartsCakephpMysqlJson = []byte(`{ "required": true, "value": "512Mi" }, + { + "description": "Volume space available for data, e.g. 512Mi, 2Gi", + "displayName": "Volume Capacity", + "name": "VOLUME_CAPACITY", + "required": true, + "value": "1Gi" + }, { "description": "The URL of the repository with your application source code.", "displayName": "Git Repository URL", "name": "SOURCE_REPOSITORY_URL", "required": true, - "value": "https://github.com/sclorg/cakephp-ex.git" + "value": "https://github.com/sclorg/dancer-ex.git" }, { "description": "Set this to a branch name, tag or other ref of your repository if you are not using the default branch.", @@ -9129,7 +7715,7 @@ var _examplesQuickstartsCakephpMysqlJson = []byte(`{ "name": "CONTEXT_DIR" }, { - "description": "The exposed hostname that will route to the CakePHP service, if left blank a value will be defaulted.", + "description": "The exposed hostname that will route to the Dancer service, if left blank a value will be defaulted.", "displayName": "Application Hostname", "name": "APPLICATION_DOMAIN", "value": "" @@ -9145,98 +7731,84 @@ var _examplesQuickstartsCakephpMysqlJson = []byte(`{ "displayName": "Database Service Name", "name": "DATABASE_SERVICE_NAME", "required": true, - "value": "mysql" - }, - { - "description": "Database engine: postgresql, mysql or sqlite (default).", - "displayName": "Database Engine", - "name": "DATABASE_ENGINE", - "required": true, - "value": "mysql" - }, - { - "displayName": "Database Name", - "name": "DATABASE_NAME", - "required": true, - "value": "default" + "value": "database" }, { - "displayName": "Database User", - "name": "DATABASE_USER", - "required": true, - "value": "cakephp" + "displayName": "Database Username", + "from": "user[A-Z0-9]{3}", + "generate": "expression", + "name": "DATABASE_USER" }, { "displayName": "Database Password", - "from": "[a-zA-Z0-9]{16}", + "from": "[a-zA-Z0-9]{8}", "generate": "expression", "name": "DATABASE_PASSWORD" }, { - "description": "Set this to a long random string.", - "displayName": "CakePHP secret token", - "from": "[\\w]{50}", - "generate": "expression", - "name": "CAKEPHP_SECRET_TOKEN" + "displayName": "Database Name", + "name": "DATABASE_NAME", + "required": true, + "value": "sampledb" }, { - "description": "Security salt for session hash.", - "displayName": "CakePHP Security Salt", - "from": "[a-zA-Z0-9]{40}", - "generate": "expression", - "name": "CAKEPHP_SECURITY_SALT" + "description": "Set this to \"true\" to enable automatic reloading of modified Perl modules.", + "displayName": "Perl Module Reload", + "name": "PERL_APACHE2_RELOAD", + "value": "" }, { - "description": "How often to check script timestamps for updates, in seconds. 0 will result in OPcache checking for updates on every request.", - "displayName": "OPcache Revalidation Frequency", - "name": "OPCACHE_REVALIDATE_FREQ", - "value": "2" + "description": "Your secret key for verifying the integrity of signed cookies.", + "displayName": "Secret Key", + "from": "[a-z0-9]{127}", + "generate": "expression", + "name": "SECRET_KEY_BASE" }, { - "description": "The custom Composer mirror URL", - "displayName": "Custom Composer Mirror URL", - "name": "COMPOSER_MIRROR", + "description": "The custom CPAN mirror URL", + "displayName": "Custom CPAN Mirror URL", + "name": "CPAN_MIRROR", "value": "" } ] }`) -func examplesQuickstartsCakephpMysqlJsonBytes() ([]byte, error) { - return _examplesQuickstartsCakephpMysqlJson, nil +func examplesQuickstartsDancerMysqlPersistentJsonBytes() ([]byte, error) { + return _examplesQuickstartsDancerMysqlPersistentJson, nil } -func examplesQuickstartsCakephpMysqlJson() (*asset, error) { - bytes, err := examplesQuickstartsCakephpMysqlJsonBytes() +func examplesQuickstartsDancerMysqlPersistentJson() (*asset, error) { + bytes, err := examplesQuickstartsDancerMysqlPersistentJsonBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "examples/quickstarts/cakephp-mysql.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "examples/quickstarts/dancer-mysql-persistent.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _examplesQuickstartsDancerMysqlPersistentJson = []byte(`{ +var _examplesQuickstartsDancerMysqlJson = []byte(`{ "apiVersion": "v1", "kind": "Template", "labels": { - "app": "dancer-mysql-persistent", - "template": "dancer-mysql-persistent" + "app": "dancer-mysql-example", + "template": "dancer-mysql-example" }, "message": "The following service(s) have been created in your project: ${NAME}, ${DATABASE_SERVICE_NAME}.\n\nFor more information about using this template, including OpenShift considerations, see https://github.com/sclorg/dancer-ex/blob/master/README.md.", "metadata": { "annotations": { - "description": "An example Dancer application with a MySQL database. For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/dancer-ex/blob/master/README.md.", + "description": "An example Dancer application with a MySQL database. For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/dancer-ex/blob/master/README.md.\n\nWARNING: Any data stored will be lost upon pod destruction. Only use this template for testing.", "iconClass": "icon-perl", - "openshift.io/display-name": "Dancer + MySQL", + "openshift.io/display-name": "Dancer + MySQL (Ephemeral)", "openshift.io/documentation-url": "https://github.com/sclorg/dancer-ex", - "openshift.io/long-description": "This template defines resources needed to develop a Dancer based application, including a build configuration, application deployment configuration, and database deployment configuration.", + "openshift.io/long-description": "This template defines resources needed to develop a Dancer based application, including a build configuration, application deployment configuration, and database deployment configuration. The database is stored in non-persistent storage, so this configuration should be used for experimental purposes only.", "openshift.io/provider-display-name": "Red Hat, Inc.", "openshift.io/support-url": "https://access.redhat.com", "tags": "quickstart,perl,dancer", "template.openshift.io/bindable": "false" }, - "name": "dancer-mysql-persistent" + "name": "dancer-mysql-example" }, "objects": [ { @@ -9436,7 +8008,7 @@ var _examplesQuickstartsDancerMysqlPersistentJson = []byte(`{ "initialDelaySeconds": 30, "timeoutSeconds": 3 }, - "name": "dancer-mysql-persistent", + "name": "dancer-mysql-example", "ports": [ { "containerPort": 8080 @@ -9464,7 +8036,7 @@ var _examplesQuickstartsDancerMysqlPersistentJson = []byte(`{ "imageChangeParams": { "automatic": true, "containerNames": [ - "dancer-mysql-persistent" + "dancer-mysql-example" ], "from": { "kind": "ImageStreamTag", @@ -9479,23 +8051,6 @@ var _examplesQuickstartsDancerMysqlPersistentJson = []byte(`{ ] } }, - { - "apiVersion": "v1", - "kind": "PersistentVolumeClaim", - "metadata": { - "name": "${DATABASE_SERVICE_NAME}" - }, - "spec": { - "accessModes": [ - "ReadWriteOnce" - ], - "resources": { - "requests": { - "storage": "${VOLUME_CAPACITY}" - } - } - } - }, { "apiVersion": "v1", "kind": "Service", @@ -9604,17 +8159,15 @@ var _examplesQuickstartsDancerMysqlPersistentJson = []byte(`{ "volumeMounts": [ { "mountPath": "/var/lib/mysql/data", - "name": "${DATABASE_SERVICE_NAME}-data" + "name": "data" } ] } ], "volumes": [ { - "name": "${DATABASE_SERVICE_NAME}-data", - "persistentVolumeClaim": { - "claimName": "${DATABASE_SERVICE_NAME}" - } + "emptyDir": {}, + "name": "data" } ] } @@ -9647,7 +8200,7 @@ var _examplesQuickstartsDancerMysqlPersistentJson = []byte(`{ "displayName": "Name", "name": "NAME", "required": true, - "value": "dancer-mysql-persistent" + "value": "dancer-mysql-example" }, { "description": "The OpenShift Namespace where the ImageStream resides.", @@ -9670,13 +8223,6 @@ var _examplesQuickstartsDancerMysqlPersistentJson = []byte(`{ "required": true, "value": "512Mi" }, - { - "description": "Volume space available for data, e.g. 512Mi, 2Gi", - "displayName": "Volume Capacity", - "name": "VOLUME_CAPACITY", - "required": true, - "value": "1Gi" - }, { "description": "The URL of the repository with your application source code.", "displayName": "Git Repository URL", @@ -9753,42 +8299,42 @@ var _examplesQuickstartsDancerMysqlPersistentJson = []byte(`{ ] }`) -func examplesQuickstartsDancerMysqlPersistentJsonBytes() ([]byte, error) { - return _examplesQuickstartsDancerMysqlPersistentJson, nil +func examplesQuickstartsDancerMysqlJsonBytes() ([]byte, error) { + return _examplesQuickstartsDancerMysqlJson, nil } -func examplesQuickstartsDancerMysqlPersistentJson() (*asset, error) { - bytes, err := examplesQuickstartsDancerMysqlPersistentJsonBytes() +func examplesQuickstartsDancerMysqlJson() (*asset, error) { + bytes, err := examplesQuickstartsDancerMysqlJsonBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "examples/quickstarts/dancer-mysql-persistent.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "examples/quickstarts/dancer-mysql.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _examplesQuickstartsDancerMysqlJson = []byte(`{ +var _examplesQuickstartsDjangoPostgresqlPersistentJson = []byte(`{ "apiVersion": "v1", "kind": "Template", "labels": { - "app": "dancer-mysql-example", - "template": "dancer-mysql-example" + "app": "django-psql-persistent", + "template": "django-psql-persistent" }, - "message": "The following service(s) have been created in your project: ${NAME}, ${DATABASE_SERVICE_NAME}.\n\nFor more information about using this template, including OpenShift considerations, see https://github.com/sclorg/dancer-ex/blob/master/README.md.", + "message": "The following service(s) have been created in your project: ${NAME}, ${DATABASE_SERVICE_NAME}.\n\nFor more information about using this template, including OpenShift considerations, see https://github.com/sclorg/django-ex/blob/master/README.md.", "metadata": { "annotations": { - "description": "An example Dancer application with a MySQL database. For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/dancer-ex/blob/master/README.md.\n\nWARNING: Any data stored will be lost upon pod destruction. Only use this template for testing.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Dancer + MySQL (Ephemeral)", - "openshift.io/documentation-url": "https://github.com/sclorg/dancer-ex", - "openshift.io/long-description": "This template defines resources needed to develop a Dancer based application, including a build configuration, application deployment configuration, and database deployment configuration. The database is stored in non-persistent storage, so this configuration should be used for experimental purposes only.", + "description": "An example Django application with a PostgreSQL database. For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/django-ex/blob/master/README.md.", + "iconClass": "icon-python", + "openshift.io/display-name": "Django + PostgreSQL", + "openshift.io/documentation-url": "https://github.com/sclorg/django-ex", + "openshift.io/long-description": "This template defines resources needed to develop a Django based application, including a build configuration, application deployment configuration, and database deployment configuration.", "openshift.io/provider-display-name": "Red Hat, Inc.", "openshift.io/support-url": "https://access.redhat.com", - "tags": "quickstart,perl,dancer", + "tags": "quickstart,python,django", "template.openshift.io/bindable": "false" }, - "name": "dancer-mysql-example" + "name": "django-psql-persistent" }, "objects": [ { @@ -9800,7 +8346,7 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ "stringData": { "database-password": "${DATABASE_PASSWORD}", "database-user": "${DATABASE_USER}", - "keybase": "${SECRET_KEY_BASE}" + "django-secret-key": "${DJANGO_SECRET_KEY}" } }, { @@ -9868,7 +8414,7 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ } }, "postCommit": { - "script": "perl -I extlib/lib/perl5 -I lib t/*" + "script": "./manage.py test" }, "source": { "contextDir": "${CONTEXT_DIR}", @@ -9882,13 +8428,13 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ "sourceStrategy": { "env": [ { - "name": "CPAN_MIRROR", - "value": "${CPAN_MIRROR}" + "name": "PIP_INDEX_URL", + "value": "${PIP_INDEX_URL}" } ], "from": { "kind": "ImageStreamTag", - "name": "perl:5.26", + "name": "python:${PYTHON_VERSION}", "namespace": "${NAMESPACE}" } }, @@ -9944,7 +8490,15 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ "value": "${DATABASE_SERVICE_NAME}" }, { - "name": "MYSQL_USER", + "name": "DATABASE_ENGINE", + "value": "${DATABASE_ENGINE}" + }, + { + "name": "DATABASE_NAME", + "value": "${DATABASE_NAME}" + }, + { + "name": "DATABASE_USER", "valueFrom": { "secretKeyRef": { "key": "database-user", @@ -9953,7 +8507,7 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ } }, { - "name": "MYSQL_PASSWORD", + "name": "DATABASE_PASSWORD", "valueFrom": { "secretKeyRef": { "key": "database-password", @@ -9962,21 +8516,17 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ } }, { - "name": "MYSQL_DATABASE", - "value": "${DATABASE_NAME}" + "name": "APP_CONFIG", + "value": "${APP_CONFIG}" }, { - "name": "SECRET_KEY_BASE", + "name": "DJANGO_SECRET_KEY", "valueFrom": { "secretKeyRef": { - "key": "keybase", + "key": "django-secret-key", "name": "${NAME}" } } - }, - { - "name": "PERL_APACHE2_RELOAD", - "value": "${PERL_APACHE2_RELOAD}" } ], "image": " ", @@ -9988,7 +8538,7 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ "initialDelaySeconds": 30, "timeoutSeconds": 3 }, - "name": "dancer-mysql-example", + "name": "django-psql-persistent", "ports": [ { "containerPort": 8080 @@ -10016,7 +8566,7 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ "imageChangeParams": { "automatic": true, "containerNames": [ - "dancer-mysql-example" + "django-psql-persistent" ], "from": { "kind": "ImageStreamTag", @@ -10031,6 +8581,23 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ ] } }, + { + "apiVersion": "v1", + "kind": "PersistentVolumeClaim", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "spec": { + "accessModes": [ + "ReadWriteOnce" + ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + }, { "apiVersion": "v1", "kind": "Service", @@ -10043,9 +8610,9 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ "spec": { "ports": [ { - "name": "mysql", - "port": 3306, - "targetPort": 3306 + "name": "postgresql", + "port": 5432, + "targetPort": 5432 } ], "selector": { @@ -10083,7 +8650,7 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ { "env": [ { - "name": "MYSQL_USER", + "name": "POSTGRESQL_USER", "valueFrom": { "secretKeyRef": { "key": "database-user", @@ -10092,7 +8659,7 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ } }, { - "name": "MYSQL_PASSWORD", + "name": "POSTGRESQL_PASSWORD", "valueFrom": { "secretKeyRef": { "key": "database-password", @@ -10101,31 +8668,31 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ } }, { - "name": "MYSQL_DATABASE", + "name": "POSTGRESQL_DATABASE", "value": "${DATABASE_NAME}" } ], "image": " ", "livenessProbe": { - "initialDelaySeconds": 30, - "tcpSocket": { - "port": 3306 + "exec": { + "command": [ + "/usr/libexec/check-container", + "--live" + ] }, - "timeoutSeconds": 1 + "initialDelaySeconds": 120, + "timeoutSeconds": 10 }, - "name": "mysql", + "name": "postgresql", "ports": [ { - "containerPort": 3306 + "containerPort": 5432 } ], "readinessProbe": { "exec": { "command": [ - "/bin/sh", - "-i", - "-c", - "MYSQL_PWD='${DATABASE_PASSWORD}' mysql -h 127.0.0.1 -u ${DATABASE_USER} -D ${DATABASE_NAME} -e 'SELECT 1'" + "/usr/libexec/check-container" ] }, "initialDelaySeconds": 5, @@ -10133,21 +8700,23 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ }, "resources": { "limits": { - "memory": "${MEMORY_MYSQL_LIMIT}" + "memory": "${MEMORY_POSTGRESQL_LIMIT}" } }, "volumeMounts": [ { - "mountPath": "/var/lib/mysql/data", - "name": "data" + "mountPath": "/var/lib/pgsql/data", + "name": "${DATABASE_SERVICE_NAME}-data" } ] } ], "volumes": [ { - "emptyDir": {}, - "name": "data" + "name": "${DATABASE_SERVICE_NAME}-data", + "persistentVolumeClaim": { + "claimName": "${DATABASE_SERVICE_NAME}" + } } ] } @@ -10157,11 +8726,11 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ "imageChangeParams": { "automatic": true, "containerNames": [ - "mysql" + "postgresql" ], "from": { "kind": "ImageStreamTag", - "name": "mysql:5.7", + "name": "postgresql:${POSTGRESQL_VERSION}", "namespace": "${NAMESPACE}" } }, @@ -10180,7 +8749,7 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ "displayName": "Name", "name": "NAME", "required": true, - "value": "dancer-mysql-example" + "value": "django-psql-persistent" }, { "description": "The OpenShift Namespace where the ImageStream resides.", @@ -10190,25 +8759,46 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ "value": "openshift" }, { - "description": "Maximum amount of memory the Perl Dancer container can use.", + "description": "Version of Python image to be used (3.6 or latest).", + "displayName": "Version of Python Image", + "name": "PYTHON_VERSION", + "required": true, + "value": "3.6" + }, + { + "description": "Version of PostgreSQL image to be used (10 or latest).", + "displayName": "Version of PostgreSQL Image", + "name": "POSTGRESQL_VERSION", + "required": true, + "value": "10" + }, + { + "description": "Maximum amount of memory the Django container can use.", "displayName": "Memory Limit", "name": "MEMORY_LIMIT", "required": true, "value": "512Mi" }, { - "description": "Maximum amount of memory the MySQL container can use.", - "displayName": "Memory Limit (MySQL)", - "name": "MEMORY_MYSQL_LIMIT", + "description": "Maximum amount of memory the PostgreSQL container can use.", + "displayName": "Memory Limit (PostgreSQL)", + "name": "MEMORY_POSTGRESQL_LIMIT", "required": true, "value": "512Mi" }, + { + "description": "Volume space available for data, e.g. 512Mi, 2Gi", + "displayName": "Volume Capacity", + "name": "VOLUME_CAPACITY", + "required": true, + "value": "1Gi" + }, { "description": "The URL of the repository with your application source code.", "displayName": "Git Repository URL", "name": "SOURCE_REPOSITORY_URL", "required": true, - "value": "https://github.com/sclorg/dancer-ex.git" + "value": "https://github.com/sclorg/django-ex.git" }, { "description": "Set this to a branch name, tag or other ref of your repository if you are not using the default branch.", @@ -10221,7 +8811,7 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ "name": "CONTEXT_DIR" }, { - "description": "The exposed hostname that will route to the Dancer service, if left blank a value will be defaulted.", + "description": "The exposed hostname that will route to the Django service, if left blank a value will be defaulted.", "displayName": "Application Hostname", "name": "APPLICATION_DOMAIN", "value": "" @@ -10237,84 +8827,90 @@ var _examplesQuickstartsDancerMysqlJson = []byte(`{ "displayName": "Database Service Name", "name": "DATABASE_SERVICE_NAME", "required": true, - "value": "database" - }, - { - "displayName": "Database Username", - "from": "user[A-Z0-9]{3}", - "generate": "expression", - "name": "DATABASE_USER" + "value": "postgresql" }, { - "displayName": "Database Password", - "from": "[a-zA-Z0-9]{8}", - "generate": "expression", - "name": "DATABASE_PASSWORD" + "description": "Database engine: postgresql, mysql or sqlite (default).", + "displayName": "Database Engine", + "name": "DATABASE_ENGINE", + "required": true, + "value": "postgresql" }, { "displayName": "Database Name", "name": "DATABASE_NAME", "required": true, - "value": "sampledb" + "value": "default" }, { - "description": "Set this to \"true\" to enable automatic reloading of modified Perl modules.", - "displayName": "Perl Module Reload", - "name": "PERL_APACHE2_RELOAD", - "value": "" + "displayName": "Database Username", + "name": "DATABASE_USER", + "required": true, + "value": "django" }, { - "description": "Your secret key for verifying the integrity of signed cookies.", - "displayName": "Secret Key", - "from": "[a-z0-9]{127}", + "displayName": "Database User Password", + "from": "[a-zA-Z0-9]{16}", "generate": "expression", - "name": "SECRET_KEY_BASE" + "name": "DATABASE_PASSWORD" }, { - "description": "The custom CPAN mirror URL", - "displayName": "Custom CPAN Mirror URL", - "name": "CPAN_MIRROR", + "description": "Relative path to Gunicorn configuration file (optional).", + "displayName": "Application Configuration File Path", + "name": "APP_CONFIG" + }, + { + "description": "Set this to a long random string.", + "displayName": "Django Secret Key", + "from": "[\\w]{50}", + "generate": "expression", + "name": "DJANGO_SECRET_KEY" + }, + { + "description": "The custom PyPi index URL", + "displayName": "Custom PyPi Index URL", + "name": "PIP_INDEX_URL", "value": "" } ] }`) -func examplesQuickstartsDancerMysqlJsonBytes() ([]byte, error) { - return _examplesQuickstartsDancerMysqlJson, nil +func examplesQuickstartsDjangoPostgresqlPersistentJsonBytes() ([]byte, error) { + return _examplesQuickstartsDjangoPostgresqlPersistentJson, nil } -func examplesQuickstartsDancerMysqlJson() (*asset, error) { - bytes, err := examplesQuickstartsDancerMysqlJsonBytes() +func examplesQuickstartsDjangoPostgresqlPersistentJson() (*asset, error) { + bytes, err := examplesQuickstartsDjangoPostgresqlPersistentJsonBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "examples/quickstarts/dancer-mysql.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "examples/quickstarts/django-postgresql-persistent.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _examplesQuickstartsDjangoPostgresqlPersistentJson = []byte(`{ +var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ "apiVersion": "v1", "kind": "Template", "labels": { - "app": "django-psql-persistent", - "template": "django-psql-persistent" + "app": "django-psql-example", + "template": "django-psql-example" }, "message": "The following service(s) have been created in your project: ${NAME}, ${DATABASE_SERVICE_NAME}.\n\nFor more information about using this template, including OpenShift considerations, see https://github.com/sclorg/django-ex/blob/master/README.md.", "metadata": { "annotations": { - "description": "An example Django application with a PostgreSQL database. For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/django-ex/blob/master/README.md.", + "description": "An example Django application with a PostgreSQL database. For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/django-ex/blob/master/README.md.\n\nWARNING: Any data stored will be lost upon pod destruction. Only use this template for testing.", "iconClass": "icon-python", - "openshift.io/display-name": "Django + PostgreSQL", + "openshift.io/display-name": "Django + PostgreSQL (Ephemeral)", "openshift.io/documentation-url": "https://github.com/sclorg/django-ex", - "openshift.io/long-description": "This template defines resources needed to develop a Django based application, including a build configuration, application deployment configuration, and database deployment configuration.", + "openshift.io/long-description": "This template defines resources needed to develop a Django based application, including a build configuration, application deployment configuration, and database deployment configuration. The database is stored in non-persistent storage, so this configuration should be used for experimental purposes only.", "openshift.io/provider-display-name": "Red Hat, Inc.", "openshift.io/support-url": "https://access.redhat.com", "tags": "quickstart,python,django", "template.openshift.io/bindable": "false" }, - "name": "django-psql-persistent" + "name": "django-psql-example" }, "objects": [ { @@ -10518,7 +9114,7 @@ var _examplesQuickstartsDjangoPostgresqlPersistentJson = []byte(`{ "initialDelaySeconds": 30, "timeoutSeconds": 3 }, - "name": "django-psql-persistent", + "name": "django-psql-example", "ports": [ { "containerPort": 8080 @@ -10546,7 +9142,7 @@ var _examplesQuickstartsDjangoPostgresqlPersistentJson = []byte(`{ "imageChangeParams": { "automatic": true, "containerNames": [ - "django-psql-persistent" + "django-psql-example" ], "from": { "kind": "ImageStreamTag", @@ -10561,23 +9157,6 @@ var _examplesQuickstartsDjangoPostgresqlPersistentJson = []byte(`{ ] } }, - { - "apiVersion": "v1", - "kind": "PersistentVolumeClaim", - "metadata": { - "name": "${DATABASE_SERVICE_NAME}" - }, - "spec": { - "accessModes": [ - "ReadWriteOnce" - ], - "resources": { - "requests": { - "storage": "${VOLUME_CAPACITY}" - } - } - } - }, { "apiVersion": "v1", "kind": "Service", @@ -10686,17 +9265,15 @@ var _examplesQuickstartsDjangoPostgresqlPersistentJson = []byte(`{ "volumeMounts": [ { "mountPath": "/var/lib/pgsql/data", - "name": "${DATABASE_SERVICE_NAME}-data" + "name": "data" } ] } ], "volumes": [ { - "name": "${DATABASE_SERVICE_NAME}-data", - "persistentVolumeClaim": { - "claimName": "${DATABASE_SERVICE_NAME}" - } + "emptyDir": {}, + "name": "data" } ] } @@ -10729,7 +9306,7 @@ var _examplesQuickstartsDjangoPostgresqlPersistentJson = []byte(`{ "displayName": "Name", "name": "NAME", "required": true, - "value": "django-psql-persistent" + "value": "django-psql-example" }, { "description": "The OpenShift Namespace where the ImageStream resides.", @@ -10766,13 +9343,6 @@ var _examplesQuickstartsDjangoPostgresqlPersistentJson = []byte(`{ "required": true, "value": "512Mi" }, - { - "description": "Volume space available for data, e.g. 512Mi, 2Gi", - "displayName": "Volume Capacity", - "name": "VOLUME_CAPACITY", - "required": true, - "value": "1Gi" - }, { "description": "The URL of the repository with your application source code.", "displayName": "Git Repository URL", @@ -10855,42 +9425,39 @@ var _examplesQuickstartsDjangoPostgresqlPersistentJson = []byte(`{ ] }`) -func examplesQuickstartsDjangoPostgresqlPersistentJsonBytes() ([]byte, error) { - return _examplesQuickstartsDjangoPostgresqlPersistentJson, nil +func examplesQuickstartsDjangoPostgresqlJsonBytes() ([]byte, error) { + return _examplesQuickstartsDjangoPostgresqlJson, nil } -func examplesQuickstartsDjangoPostgresqlPersistentJson() (*asset, error) { - bytes, err := examplesQuickstartsDjangoPostgresqlPersistentJsonBytes() +func examplesQuickstartsDjangoPostgresqlJson() (*asset, error) { + bytes, err := examplesQuickstartsDjangoPostgresqlJsonBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "examples/quickstarts/django-postgresql-persistent.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "examples/quickstarts/django-postgresql.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ +var _examplesQuickstartsDotnetPgsqlPersistentJson = []byte(`{ "apiVersion": "v1", "kind": "Template", "labels": { - "app": "django-psql-example", - "template": "django-psql-example" + "template": "dotnet-pgsql-persistent" }, - "message": "The following service(s) have been created in your project: ${NAME}, ${DATABASE_SERVICE_NAME}.\n\nFor more information about using this template, including OpenShift considerations, see https://github.com/sclorg/django-ex/blob/master/README.md.", + "message": "The following service(s) have been created in your project: ${NAME}, ${DATABASE_SERVICE_NAME}.\n\nFor more information about using this template, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore.", "metadata": { "annotations": { - "description": "An example Django application with a PostgreSQL database. For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/django-ex/blob/master/README.md.\n\nWARNING: Any data stored will be lost upon pod destruction. Only use this template for testing.", - "iconClass": "icon-python", - "openshift.io/display-name": "Django + PostgreSQL (Ephemeral)", - "openshift.io/documentation-url": "https://github.com/sclorg/django-ex", - "openshift.io/long-description": "This template defines resources needed to develop a Django based application, including a build configuration, application deployment configuration, and database deployment configuration. The database is stored in non-persistent storage, so this configuration should be used for experimental purposes only.", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "openshift.io/support-url": "https://access.redhat.com", - "tags": "quickstart,python,django", - "template.openshift.io/bindable": "false" + "description": "An example .NET Core application with a PostgreSQL database. For more information about using this template, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore.", + "iconClass": "icon-dotnet", + "openshift.io/display-name": ".NET Core + PostgreSQL (Persistent)", + "tags": "quickstart,dotnet", + "template.openshift.io/documentation-url": "https://github.com/redhat-developer/s2i-dotnetcore", + "template.openshift.io/provider-display-name": "Red Hat, Inc.", + "template.openshift.io/support-url": "https://access.redhat.com" }, - "name": "django-psql-example" + "name": "dotnet-pgsql-persistent" }, "objects": [ { @@ -10900,9 +9467,8 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ "name": "${NAME}" }, "stringData": { - "database-password": "${DATABASE_PASSWORD}", - "database-user": "${DATABASE_USER}", - "django-secret-key": "${DJANGO_SECRET_KEY}" + "connect-string": "Host=${DATABASE_SERVICE_NAME};Database=${DATABASE_NAME};Username=${DATABASE_USER};Password=${DATABASE_PASSWORD}", + "database-password": "${DATABASE_PASSWORD}" } }, { @@ -10957,8 +9523,7 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ "kind": "BuildConfig", "metadata": { "annotations": { - "description": "Defines how to build the application", - "template.alpha.openshift.io/wait-for-ready": "true" + "description": "Defines how to build the application" }, "name": "${NAME}" }, @@ -10969,9 +9534,7 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ "name": "${NAME}:latest" } }, - "postCommit": { - "script": "./manage.py test" - }, + "postCommit": {}, "source": { "contextDir": "${CONTEXT_DIR}", "git": { @@ -10984,13 +9547,41 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ "sourceStrategy": { "env": [ { - "name": "PIP_INDEX_URL", - "value": "${PIP_INDEX_URL}" + "name": "DOTNET_STARTUP_PROJECT", + "value": "${DOTNET_STARTUP_PROJECT}" + }, + { + "name": "DOTNET_SDK_VERSION", + "value": "${DOTNET_SDK_VERSION}" + }, + { + "name": "DOTNET_ASSEMBLY_NAME", + "value": "${DOTNET_ASSEMBLY_NAME}" + }, + { + "name": "DOTNET_NPM_TOOLS", + "value": "${DOTNET_NPM_TOOLS}" + }, + { + "name": "DOTNET_TEST_PROJECTS", + "value": "${DOTNET_TEST_PROJECTS}" + }, + { + "name": "DOTNET_CONFIGURATION", + "value": "${DOTNET_CONFIGURATION}" + }, + { + "name": "DOTNET_RESTORE_SOURCES", + "value": "${DOTNET_RESTORE_SOURCES}" + }, + { + "name": "DOTNET_TOOLS", + "value": "${DOTNET_TOOLS}" } ], "from": { "kind": "ImageStreamTag", - "name": "python:${PYTHON_VERSION}", + "name": "${DOTNET_IMAGE_STREAM_TAG}", "namespace": "${NAMESPACE}" } }, @@ -11017,8 +9608,7 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ "kind": "DeploymentConfig", "metadata": { "annotations": { - "description": "Defines how to deploy the application server", - "template.alpha.openshift.io/wait-for-ready": "true" + "description": "Defines how to deploy the application server" }, "name": "${NAME}" }, @@ -11028,7 +9618,15 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ "name": "${NAME}" }, "strategy": { - "type": "Recreate" + "resources": {}, + "rollingParams": { + "intervalSeconds": 1, + "maxSurge": "25%", + "maxUnavailable": "25%", + "timeoutSeconds": 600, + "updatePeriodSeconds": 1 + }, + "type": "Rolling" }, "template": { "metadata": { @@ -11042,44 +9640,10 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ { "env": [ { - "name": "DATABASE_SERVICE_NAME", - "value": "${DATABASE_SERVICE_NAME}" - }, - { - "name": "DATABASE_ENGINE", - "value": "${DATABASE_ENGINE}" - }, - { - "name": "DATABASE_NAME", - "value": "${DATABASE_NAME}" - }, - { - "name": "DATABASE_USER", - "valueFrom": { - "secretKeyRef": { - "key": "database-user", - "name": "${NAME}" - } - } - }, - { - "name": "DATABASE_PASSWORD", - "valueFrom": { - "secretKeyRef": { - "key": "database-password", - "name": "${NAME}" - } - } - }, - { - "name": "APP_CONFIG", - "value": "${APP_CONFIG}" - }, - { - "name": "DJANGO_SECRET_KEY", + "name": "ConnectionString", "valueFrom": { "secretKeyRef": { - "key": "django-secret-key", + "key": "connect-string", "name": "${NAME}" } } @@ -11088,13 +9652,14 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ "image": " ", "livenessProbe": { "httpGet": { - "path": "/health", - "port": 8080 + "path": "/", + "port": 8080, + "scheme": "HTTP" }, - "initialDelaySeconds": 30, - "timeoutSeconds": 3 + "initialDelaySeconds": 40, + "timeoutSeconds": 10 }, - "name": "django-psql-example", + "name": "dotnet-pgsql-persistent", "ports": [ { "containerPort": 8080 @@ -11102,11 +9667,12 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ ], "readinessProbe": { "httpGet": { - "path": "/health", - "port": 8080 + "path": "/", + "port": 8080, + "scheme": "HTTP" }, - "initialDelaySeconds": 3, - "timeoutSeconds": 3 + "initialDelaySeconds": 10, + "timeoutSeconds": 30 }, "resources": { "limits": { @@ -11122,7 +9688,7 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ "imageChangeParams": { "automatic": true, "containerNames": [ - "django-psql-example" + "dotnet-pgsql-persistent" ], "from": { "kind": "ImageStreamTag", @@ -11137,6 +9703,23 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ ] } }, + { + "apiVersion": "v1", + "kind": "PersistentVolumeClaim", + "metadata": { + "name": "${DATABASE_SERVICE_NAME}" + }, + "spec": { + "accessModes": [ + "ReadWriteOnce" + ], + "resources": { + "requests": { + "storage": "${VOLUME_CAPACITY}" + } + } + } + }, { "apiVersion": "v1", "kind": "Service", @@ -11164,8 +9747,7 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ "kind": "DeploymentConfig", "metadata": { "annotations": { - "description": "Defines how to deploy the database", - "template.alpha.openshift.io/wait-for-ready": "true" + "description": "Defines how to deploy the database" }, "name": "${DATABASE_SERVICE_NAME}" }, @@ -11190,12 +9772,7 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ "env": [ { "name": "POSTGRESQL_USER", - "valueFrom": { - "secretKeyRef": { - "key": "database-user", - "name": "${NAME}" - } - } + "value": "${DATABASE_USER}" }, { "name": "POSTGRESQL_PASSWORD", @@ -11209,18 +9786,23 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ { "name": "POSTGRESQL_DATABASE", "value": "${DATABASE_NAME}" + }, + { + "name": "POSTGRESQL_MAX_CONNECTIONS", + "value": "${POSTGRESQL_MAX_CONNECTIONS}" + }, + { + "name": "POSTGRESQL_SHARED_BUFFERS", + "value": "${POSTGRESQL_SHARED_BUFFERS}" } ], "image": " ", "livenessProbe": { - "exec": { - "command": [ - "/usr/libexec/check-container", - "--live" - ] + "initialDelaySeconds": 30, + "tcpSocket": { + "port": 5432 }, - "initialDelaySeconds": 120, - "timeoutSeconds": 10 + "timeoutSeconds": 1 }, "name": "postgresql", "ports": [ @@ -11228,15 +9810,6 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ "containerPort": 5432 } ], - "readinessProbe": { - "exec": { - "command": [ - "/usr/libexec/check-container" - ] - }, - "initialDelaySeconds": 5, - "timeoutSeconds": 1 - }, "resources": { "limits": { "memory": "${MEMORY_POSTGRESQL_LIMIT}" @@ -11245,15 +9818,17 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ "volumeMounts": [ { "mountPath": "/var/lib/pgsql/data", - "name": "data" + "name": "${DATABASE_SERVICE_NAME}-data" } ] } ], "volumes": [ { - "emptyDir": {}, - "name": "data" + "name": "${DATABASE_SERVICE_NAME}-data", + "persistentVolumeClaim": { + "claimName": "${DATABASE_SERVICE_NAME}" + } } ] } @@ -11267,8 +9842,8 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ ], "from": { "kind": "ImageStreamTag", - "name": "postgresql:${POSTGRESQL_VERSION}", - "namespace": "${NAMESPACE}" + "name": "postgresql:9.5", + "namespace": "openshift" } }, "type": "ImageChange" @@ -11286,54 +9861,55 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ "displayName": "Name", "name": "NAME", "required": true, - "value": "django-psql-example" + "value": "musicstore" }, { - "description": "The OpenShift Namespace where the ImageStream resides.", - "displayName": "Namespace", - "name": "NAMESPACE", + "description": "Maximum amount of memory the .NET Core container can use.", + "displayName": "Memory Limit", + "name": "MEMORY_LIMIT", "required": true, - "value": "openshift" + "value": "128Mi" }, { - "description": "Version of Python image to be used (3.6 or latest).", - "displayName": "Version of Python Image", - "name": "PYTHON_VERSION", + "description": "Maximum amount of memory the PostgreSQL container can use.", + "displayName": "Memory Limit (PostgreSQL)", + "name": "MEMORY_POSTGRESQL_LIMIT", "required": true, - "value": "3.6" + "value": "128Mi" }, { - "description": "Version of PostgreSQL image to be used (10 or latest).", - "displayName": "Version of PostgreSQL Image", - "name": "POSTGRESQL_VERSION", + "description": "Volume space available for data, e.g. 512Mi, 2Gi", + "displayName": "Volume Capacity", + "name": "VOLUME_CAPACITY", "required": true, - "value": "10" + "value": "256Mi" }, { - "description": "Maximum amount of memory the Django container can use.", - "displayName": "Memory Limit", - "name": "MEMORY_LIMIT", + "description": "The image stream tag which is used to build the code.", + "displayName": ".NET builder", + "name": "DOTNET_IMAGE_STREAM_TAG", "required": true, - "value": "512Mi" + "value": "dotnet:2.1" }, { - "description": "Maximum amount of memory the PostgreSQL container can use.", - "displayName": "Memory Limit (PostgreSQL)", - "name": "MEMORY_POSTGRESQL_LIMIT", + "description": "The OpenShift Namespace where the .NET builder ImageStream resides.", + "displayName": "Namespace", + "name": "NAMESPACE", "required": true, - "value": "512Mi" + "value": "openshift" }, { "description": "The URL of the repository with your application source code.", "displayName": "Git Repository URL", "name": "SOURCE_REPOSITORY_URL", "required": true, - "value": "https://github.com/sclorg/django-ex.git" + "value": "https://github.com/redhat-developer/s2i-aspnet-musicstore-ex.git" }, { "description": "Set this to a branch name, tag or other ref of your repository if you are not using the default branch.", "displayName": "Git Reference", - "name": "SOURCE_REPOSITORY_REF" + "name": "SOURCE_REPOSITORY_REF", + "value": "rel/2.1-example" }, { "description": "Set this to the relative path to your project if it is not in the root of your repository.", @@ -11341,13 +9917,56 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ "name": "CONTEXT_DIR" }, { - "description": "The exposed hostname that will route to the Django service, if left blank a value will be defaulted.", + "description": "Set this to a project file (e.g. csproj) or a folder containing a single project file.", + "displayName": "Startup Project", + "name": "DOTNET_STARTUP_PROJECT", + "value": "samples/MusicStore" + }, + { + "description": "Set this to configure the default SDK version. This can be set to a specific version, '' (lowest version) or 'latest' (highest version).", + "displayName": "SDK Version", + "name": "DOTNET_SDK_VERSION", + "value": "" + }, + { + "description": "Set this when the assembly name is overridden in the project file.", + "displayName": "Startup Assembly", + "name": "DOTNET_ASSEMBLY_NAME" + }, + { + "description": "Set this to a space separated list of .NET tools needed to publish.", + "displayName": ".NET Tools", + "name": "DOTNET_TOOLS" + }, + { + "description": "Set this to a space separated list of npm tools needed to publish.", + "displayName": "Npm Tools", + "name": "DOTNET_NPM_TOOLS" + }, + { + "description": "Set this to a space separated list of test projects to run before publishing.", + "displayName": "Test projects", + "name": "DOTNET_TEST_PROJECTS" + }, + { + "description": "Set this to configuration (Release/Debug).", + "displayName": "Configuration", + "name": "DOTNET_CONFIGURATION", + "value": "Release" + }, + { + "description": "Set this to override the NuGet.config sources.", + "displayName": "NuGet package sources", + "name": "DOTNET_RESTORE_SOURCES" + }, + { + "description": "The exposed hostname that will route to the .NET Core service, if left blank a value will be defaulted.", "displayName": "Application Hostname", "name": "APPLICATION_DOMAIN", "value": "" }, { - "description": "Github trigger secret. A difficult to guess string encoded as part of the webhook URL. Not encrypted.", + "description": "A secret string used to configure the GitHub webhook.", "displayName": "GitHub Webhook Secret", "from": "[a-zA-Z0-9]{40}", "generate": "expression", @@ -11359,96 +9978,80 @@ var _examplesQuickstartsDjangoPostgresqlJson = []byte(`{ "required": true, "value": "postgresql" }, - { - "description": "Database engine: postgresql, mysql or sqlite (default).", - "displayName": "Database Engine", - "name": "DATABASE_ENGINE", - "required": true, - "value": "postgresql" - }, - { - "displayName": "Database Name", - "name": "DATABASE_NAME", - "required": true, - "value": "default" - }, { "displayName": "Database Username", - "name": "DATABASE_USER", - "required": true, - "value": "django" + "from": "user[A-Z0-9]{3}", + "generate": "expression", + "name": "DATABASE_USER" }, { - "displayName": "Database User Password", - "from": "[a-zA-Z0-9]{16}", + "displayName": "Database Password", + "from": "[a-zA-Z0-9]{8}", "generate": "expression", "name": "DATABASE_PASSWORD" }, { - "description": "Relative path to Gunicorn configuration file (optional).", - "displayName": "Application Configuration File Path", - "name": "APP_CONFIG" + "displayName": "Database Name", + "name": "DATABASE_NAME", + "required": true, + "value": "musicstore" }, { - "description": "Set this to a long random string.", - "displayName": "Django Secret Key", - "from": "[\\w]{50}", - "generate": "expression", - "name": "DJANGO_SECRET_KEY" + "displayName": "Maximum Database Connections", + "name": "POSTGRESQL_MAX_CONNECTIONS", + "value": "100" }, { - "description": "The custom PyPi index URL", - "displayName": "Custom PyPi Index URL", - "name": "PIP_INDEX_URL", - "value": "" + "displayName": "Shared Buffer Amount", + "name": "POSTGRESQL_SHARED_BUFFERS", + "value": "12MB" } ] }`) -func examplesQuickstartsDjangoPostgresqlJsonBytes() ([]byte, error) { - return _examplesQuickstartsDjangoPostgresqlJson, nil +func examplesQuickstartsDotnetPgsqlPersistentJsonBytes() ([]byte, error) { + return _examplesQuickstartsDotnetPgsqlPersistentJson, nil } -func examplesQuickstartsDjangoPostgresqlJson() (*asset, error) { - bytes, err := examplesQuickstartsDjangoPostgresqlJsonBytes() +func examplesQuickstartsDotnetPgsqlPersistentJson() (*asset, error) { + bytes, err := examplesQuickstartsDotnetPgsqlPersistentJsonBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "examples/quickstarts/django-postgresql.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "examples/quickstarts/dotnet-pgsql-persistent.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _examplesQuickstartsDotnetPgsqlPersistentJson = []byte(`{ +var _examplesQuickstartsDotnetJson = []byte(`{ "apiVersion": "v1", "kind": "Template", - "labels": { - "template": "dotnet-pgsql-persistent" - }, - "message": "The following service(s) have been created in your project: ${NAME}, ${DATABASE_SERVICE_NAME}.\n\nFor more information about using this template, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore.", "metadata": { "annotations": { - "description": "An example .NET Core application with a PostgreSQL database. For more information about using this template, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore.", + "description": "An example .NET Core application.", "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core + PostgreSQL (Persistent)", - "tags": "quickstart,dotnet", + "openshift.io/display-name": ".NET Core Example", + "tags": "quickstart,dotnet,.net", "template.openshift.io/documentation-url": "https://github.com/redhat-developer/s2i-dotnetcore", "template.openshift.io/provider-display-name": "Red Hat, Inc.", "template.openshift.io/support-url": "https://access.redhat.com" }, - "name": "dotnet-pgsql-persistent" + "name": "dotnet-example" }, "objects": [ { "apiVersion": "v1", - "kind": "Secret", + "kind": "Route", "metadata": { "name": "${NAME}" }, - "stringData": { - "connect-string": "Host=${DATABASE_SERVICE_NAME};Database=${DATABASE_NAME};Username=${DATABASE_USER};Password=${DATABASE_PASSWORD}", - "database-password": "${DATABASE_PASSWORD}" + "spec": { + "host": "${APPLICATION_DOMAIN}", + "to": { + "kind": "Service", + "name": "${NAME}" + } } }, { @@ -11456,8 +10059,7 @@ var _examplesQuickstartsDotnetPgsqlPersistentJson = []byte(`{ "kind": "Service", "metadata": { "annotations": { - "description": "Exposes and load balances the application pods", - "service.alpha.openshift.io/dependencies": "[{\"name\": \"${DATABASE_SERVICE_NAME}\", \"kind\": \"Service\"}]" + "description": "Exposes and load balances the application pods" }, "name": "${NAME}" }, @@ -11474,20 +10076,6 @@ var _examplesQuickstartsDotnetPgsqlPersistentJson = []byte(`{ } } }, - { - "apiVersion": "v1", - "kind": "Route", - "metadata": { - "name": "${NAME}" - }, - "spec": { - "host": "${APPLICATION_DOMAIN}", - "to": { - "kind": "Service", - "name": "${NAME}" - } - } - }, { "apiVersion": "v1", "kind": "ImageStream", @@ -11514,7 +10102,6 @@ var _examplesQuickstartsDotnetPgsqlPersistentJson = []byte(`{ "name": "${NAME}:latest" } }, - "postCommit": {}, "source": { "contextDir": "${CONTEXT_DIR}", "git": { @@ -11579,6 +10166,12 @@ var _examplesQuickstartsDotnetPgsqlPersistentJson = []byte(`{ "secret": "${GITHUB_WEBHOOK_SECRET}" }, "type": "GitHub" + }, + { + "generic": { + "secret": "${GENERIC_WEBHOOK_SECRET}" + }, + "type": "Generic" } ] } @@ -11598,14 +10191,6 @@ var _examplesQuickstartsDotnetPgsqlPersistentJson = []byte(`{ "name": "${NAME}" }, "strategy": { - "resources": {}, - "rollingParams": { - "intervalSeconds": 1, - "maxSurge": "25%", - "maxUnavailable": "25%", - "timeoutSeconds": 600, - "updatePeriodSeconds": 1 - }, "type": "Rolling" }, "template": { @@ -11618,17 +10203,7 @@ var _examplesQuickstartsDotnetPgsqlPersistentJson = []byte(`{ "spec": { "containers": [ { - "env": [ - { - "name": "ConnectionString", - "valueFrom": { - "secretKeyRef": { - "key": "connect-string", - "name": "${NAME}" - } - } - } - ], + "env": [], "image": " ", "livenessProbe": { "httpGet": { @@ -11637,9 +10212,9 @@ var _examplesQuickstartsDotnetPgsqlPersistentJson = []byte(`{ "scheme": "HTTP" }, "initialDelaySeconds": 40, - "timeoutSeconds": 10 + "timeoutSeconds": 15 }, - "name": "dotnet-pgsql-persistent", + "name": "dotnet-app", "ports": [ { "containerPort": 8080 @@ -11668,7 +10243,7 @@ var _examplesQuickstartsDotnetPgsqlPersistentJson = []byte(`{ "imageChangeParams": { "automatic": true, "containerNames": [ - "dotnet-pgsql-persistent" + "dotnet-app" ], "from": { "kind": "ImageStreamTag", @@ -11682,584 +10257,29 @@ var _examplesQuickstartsDotnetPgsqlPersistentJson = []byte(`{ } ] } + } + ], + "parameters": [ + { + "description": "The name assigned to all of the frontend objects defined in this template.", + "displayName": "Name", + "name": "NAME", + "required": true, + "value": "dotnet-example" }, { - "apiVersion": "v1", - "kind": "PersistentVolumeClaim", - "metadata": { - "name": "${DATABASE_SERVICE_NAME}" - }, - "spec": { - "accessModes": [ - "ReadWriteOnce" - ], - "resources": { - "requests": { - "storage": "${VOLUME_CAPACITY}" - } - } - } + "description": "Maximum amount of memory the container can use.", + "displayName": "Memory Limit", + "name": "MEMORY_LIMIT", + "required": true, + "value": "128Mi" }, { - "apiVersion": "v1", - "kind": "Service", - "metadata": { - "annotations": { - "description": "Exposes the database server" - }, - "name": "${DATABASE_SERVICE_NAME}" - }, - "spec": { - "ports": [ - { - "name": "postgresql", - "port": 5432, - "targetPort": 5432 - } - ], - "selector": { - "name": "${DATABASE_SERVICE_NAME}" - } - } - }, - { - "apiVersion": "v1", - "kind": "DeploymentConfig", - "metadata": { - "annotations": { - "description": "Defines how to deploy the database" - }, - "name": "${DATABASE_SERVICE_NAME}" - }, - "spec": { - "replicas": 1, - "selector": { - "name": "${DATABASE_SERVICE_NAME}" - }, - "strategy": { - "type": "Recreate" - }, - "template": { - "metadata": { - "labels": { - "name": "${DATABASE_SERVICE_NAME}" - }, - "name": "${DATABASE_SERVICE_NAME}" - }, - "spec": { - "containers": [ - { - "env": [ - { - "name": "POSTGRESQL_USER", - "value": "${DATABASE_USER}" - }, - { - "name": "POSTGRESQL_PASSWORD", - "valueFrom": { - "secretKeyRef": { - "key": "database-password", - "name": "${NAME}" - } - } - }, - { - "name": "POSTGRESQL_DATABASE", - "value": "${DATABASE_NAME}" - }, - { - "name": "POSTGRESQL_MAX_CONNECTIONS", - "value": "${POSTGRESQL_MAX_CONNECTIONS}" - }, - { - "name": "POSTGRESQL_SHARED_BUFFERS", - "value": "${POSTGRESQL_SHARED_BUFFERS}" - } - ], - "image": " ", - "livenessProbe": { - "initialDelaySeconds": 30, - "tcpSocket": { - "port": 5432 - }, - "timeoutSeconds": 1 - }, - "name": "postgresql", - "ports": [ - { - "containerPort": 5432 - } - ], - "resources": { - "limits": { - "memory": "${MEMORY_POSTGRESQL_LIMIT}" - } - }, - "volumeMounts": [ - { - "mountPath": "/var/lib/pgsql/data", - "name": "${DATABASE_SERVICE_NAME}-data" - } - ] - } - ], - "volumes": [ - { - "name": "${DATABASE_SERVICE_NAME}-data", - "persistentVolumeClaim": { - "claimName": "${DATABASE_SERVICE_NAME}" - } - } - ] - } - }, - "triggers": [ - { - "imageChangeParams": { - "automatic": true, - "containerNames": [ - "postgresql" - ], - "from": { - "kind": "ImageStreamTag", - "name": "postgresql:9.5", - "namespace": "openshift" - } - }, - "type": "ImageChange" - }, - { - "type": "ConfigChange" - } - ] - } - } - ], - "parameters": [ - { - "description": "The name assigned to all of the frontend objects defined in this template.", - "displayName": "Name", - "name": "NAME", - "required": true, - "value": "musicstore" - }, - { - "description": "Maximum amount of memory the .NET Core container can use.", - "displayName": "Memory Limit", - "name": "MEMORY_LIMIT", - "required": true, - "value": "128Mi" - }, - { - "description": "Maximum amount of memory the PostgreSQL container can use.", - "displayName": "Memory Limit (PostgreSQL)", - "name": "MEMORY_POSTGRESQL_LIMIT", - "required": true, - "value": "128Mi" - }, - { - "description": "Volume space available for data, e.g. 512Mi, 2Gi", - "displayName": "Volume Capacity", - "name": "VOLUME_CAPACITY", - "required": true, - "value": "256Mi" - }, - { - "description": "The image stream tag which is used to build the code.", - "displayName": ".NET builder", - "name": "DOTNET_IMAGE_STREAM_TAG", - "required": true, - "value": "dotnet:2.1" - }, - { - "description": "The OpenShift Namespace where the .NET builder ImageStream resides.", - "displayName": "Namespace", - "name": "NAMESPACE", - "required": true, - "value": "openshift" - }, - { - "description": "The URL of the repository with your application source code.", - "displayName": "Git Repository URL", - "name": "SOURCE_REPOSITORY_URL", - "required": true, - "value": "https://github.com/redhat-developer/s2i-aspnet-musicstore-ex.git" - }, - { - "description": "Set this to a branch name, tag or other ref of your repository if you are not using the default branch.", - "displayName": "Git Reference", - "name": "SOURCE_REPOSITORY_REF", - "value": "rel/2.1-example" - }, - { - "description": "Set this to the relative path to your project if it is not in the root of your repository.", - "displayName": "Context Directory", - "name": "CONTEXT_DIR" - }, - { - "description": "Set this to a project file (e.g. csproj) or a folder containing a single project file.", - "displayName": "Startup Project", - "name": "DOTNET_STARTUP_PROJECT", - "value": "samples/MusicStore" - }, - { - "description": "Set this to configure the default SDK version. This can be set to a specific version, '' (lowest version) or 'latest' (highest version).", - "displayName": "SDK Version", - "name": "DOTNET_SDK_VERSION", - "value": "" - }, - { - "description": "Set this when the assembly name is overridden in the project file.", - "displayName": "Startup Assembly", - "name": "DOTNET_ASSEMBLY_NAME" - }, - { - "description": "Set this to a space separated list of .NET tools needed to publish.", - "displayName": ".NET Tools", - "name": "DOTNET_TOOLS" - }, - { - "description": "Set this to a space separated list of npm tools needed to publish.", - "displayName": "Npm Tools", - "name": "DOTNET_NPM_TOOLS" - }, - { - "description": "Set this to a space separated list of test projects to run before publishing.", - "displayName": "Test projects", - "name": "DOTNET_TEST_PROJECTS" - }, - { - "description": "Set this to configuration (Release/Debug).", - "displayName": "Configuration", - "name": "DOTNET_CONFIGURATION", - "value": "Release" - }, - { - "description": "Set this to override the NuGet.config sources.", - "displayName": "NuGet package sources", - "name": "DOTNET_RESTORE_SOURCES" - }, - { - "description": "The exposed hostname that will route to the .NET Core service, if left blank a value will be defaulted.", - "displayName": "Application Hostname", - "name": "APPLICATION_DOMAIN", - "value": "" - }, - { - "description": "A secret string used to configure the GitHub webhook.", - "displayName": "GitHub Webhook Secret", - "from": "[a-zA-Z0-9]{40}", - "generate": "expression", - "name": "GITHUB_WEBHOOK_SECRET" - }, - { - "displayName": "Database Service Name", - "name": "DATABASE_SERVICE_NAME", - "required": true, - "value": "postgresql" - }, - { - "displayName": "Database Username", - "from": "user[A-Z0-9]{3}", - "generate": "expression", - "name": "DATABASE_USER" - }, - { - "displayName": "Database Password", - "from": "[a-zA-Z0-9]{8}", - "generate": "expression", - "name": "DATABASE_PASSWORD" - }, - { - "displayName": "Database Name", - "name": "DATABASE_NAME", - "required": true, - "value": "musicstore" - }, - { - "displayName": "Maximum Database Connections", - "name": "POSTGRESQL_MAX_CONNECTIONS", - "value": "100" - }, - { - "displayName": "Shared Buffer Amount", - "name": "POSTGRESQL_SHARED_BUFFERS", - "value": "12MB" - } - ] -}`) - -func examplesQuickstartsDotnetPgsqlPersistentJsonBytes() ([]byte, error) { - return _examplesQuickstartsDotnetPgsqlPersistentJson, nil -} - -func examplesQuickstartsDotnetPgsqlPersistentJson() (*asset, error) { - bytes, err := examplesQuickstartsDotnetPgsqlPersistentJsonBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "examples/quickstarts/dotnet-pgsql-persistent.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _examplesQuickstartsDotnetJson = []byte(`{ - "apiVersion": "v1", - "kind": "Template", - "metadata": { - "annotations": { - "description": "An example .NET Core application.", - "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core Example", - "tags": "quickstart,dotnet,.net", - "template.openshift.io/documentation-url": "https://github.com/redhat-developer/s2i-dotnetcore", - "template.openshift.io/provider-display-name": "Red Hat, Inc.", - "template.openshift.io/support-url": "https://access.redhat.com" - }, - "name": "dotnet-example" - }, - "objects": [ - { - "apiVersion": "v1", - "kind": "Route", - "metadata": { - "name": "${NAME}" - }, - "spec": { - "host": "${APPLICATION_DOMAIN}", - "to": { - "kind": "Service", - "name": "${NAME}" - } - } - }, - { - "apiVersion": "v1", - "kind": "Service", - "metadata": { - "annotations": { - "description": "Exposes and load balances the application pods" - }, - "name": "${NAME}" - }, - "spec": { - "ports": [ - { - "name": "web", - "port": 8080, - "targetPort": 8080 - } - ], - "selector": { - "name": "${NAME}" - } - } - }, - { - "apiVersion": "v1", - "kind": "ImageStream", - "metadata": { - "annotations": { - "description": "Keeps track of changes in the application image" - }, - "name": "${NAME}" - } - }, - { - "apiVersion": "v1", - "kind": "BuildConfig", - "metadata": { - "annotations": { - "description": "Defines how to build the application" - }, - "name": "${NAME}" - }, - "spec": { - "output": { - "to": { - "kind": "ImageStreamTag", - "name": "${NAME}:latest" - } - }, - "source": { - "contextDir": "${CONTEXT_DIR}", - "git": { - "ref": "${SOURCE_REPOSITORY_REF}", - "uri": "${SOURCE_REPOSITORY_URL}" - }, - "type": "Git" - }, - "strategy": { - "sourceStrategy": { - "env": [ - { - "name": "DOTNET_STARTUP_PROJECT", - "value": "${DOTNET_STARTUP_PROJECT}" - }, - { - "name": "DOTNET_SDK_VERSION", - "value": "${DOTNET_SDK_VERSION}" - }, - { - "name": "DOTNET_ASSEMBLY_NAME", - "value": "${DOTNET_ASSEMBLY_NAME}" - }, - { - "name": "DOTNET_NPM_TOOLS", - "value": "${DOTNET_NPM_TOOLS}" - }, - { - "name": "DOTNET_TEST_PROJECTS", - "value": "${DOTNET_TEST_PROJECTS}" - }, - { - "name": "DOTNET_CONFIGURATION", - "value": "${DOTNET_CONFIGURATION}" - }, - { - "name": "DOTNET_RESTORE_SOURCES", - "value": "${DOTNET_RESTORE_SOURCES}" - }, - { - "name": "DOTNET_TOOLS", - "value": "${DOTNET_TOOLS}" - } - ], - "from": { - "kind": "ImageStreamTag", - "name": "${DOTNET_IMAGE_STREAM_TAG}", - "namespace": "${NAMESPACE}" - } - }, - "type": "Source" - }, - "triggers": [ - { - "type": "ImageChange" - }, - { - "type": "ConfigChange" - }, - { - "github": { - "secret": "${GITHUB_WEBHOOK_SECRET}" - }, - "type": "GitHub" - }, - { - "generic": { - "secret": "${GENERIC_WEBHOOK_SECRET}" - }, - "type": "Generic" - } - ] - } - }, - { - "apiVersion": "v1", - "kind": "DeploymentConfig", - "metadata": { - "annotations": { - "description": "Defines how to deploy the application server" - }, - "name": "${NAME}" - }, - "spec": { - "replicas": 1, - "selector": { - "name": "${NAME}" - }, - "strategy": { - "type": "Rolling" - }, - "template": { - "metadata": { - "labels": { - "name": "${NAME}" - }, - "name": "${NAME}" - }, - "spec": { - "containers": [ - { - "env": [], - "image": " ", - "livenessProbe": { - "httpGet": { - "path": "/", - "port": 8080, - "scheme": "HTTP" - }, - "initialDelaySeconds": 40, - "timeoutSeconds": 15 - }, - "name": "dotnet-app", - "ports": [ - { - "containerPort": 8080 - } - ], - "readinessProbe": { - "httpGet": { - "path": "/", - "port": 8080, - "scheme": "HTTP" - }, - "initialDelaySeconds": 10, - "timeoutSeconds": 30 - }, - "resources": { - "limits": { - "memory": "${MEMORY_LIMIT}" - } - } - } - ] - } - }, - "triggers": [ - { - "imageChangeParams": { - "automatic": true, - "containerNames": [ - "dotnet-app" - ], - "from": { - "kind": "ImageStreamTag", - "name": "${NAME}:latest" - } - }, - "type": "ImageChange" - }, - { - "type": "ConfigChange" - } - ] - } - } - ], - "parameters": [ - { - "description": "The name assigned to all of the frontend objects defined in this template.", - "displayName": "Name", - "name": "NAME", - "required": true, - "value": "dotnet-example" - }, - { - "description": "Maximum amount of memory the container can use.", - "displayName": "Memory Limit", - "name": "MEMORY_LIMIT", - "required": true, - "value": "128Mi" - }, - { - "description": "The image stream tag which is used to build the code.", - "displayName": ".NET builder", - "name": "DOTNET_IMAGE_STREAM_TAG", - "required": true, - "value": "dotnet:2.2" + "description": "The image stream tag which is used to build the code.", + "displayName": ".NET builder", + "name": "DOTNET_IMAGE_STREAM_TAG", + "required": true, + "value": "dotnet:2.2" }, { "description": "The OpenShift Namespace where the ImageStream resides.", @@ -20523,7 +18543,7 @@ func testExtendedTestdataBuildsDockerAddDockerfile() (*asset, error) { return a, nil } -var _testExtendedTestdataBuildsDockerAddDockerAddEnvDockerfile = []byte(`FROM registry.redhat.io/rhel7 +var _testExtendedTestdataBuildsDockerAddDockerAddEnvDockerfile = []byte(`FROM centos ENV foo=foo ADD ./${foo} /tmp/foo `) @@ -21568,7 +19588,7 @@ var _testExtendedTestdataBuildsTestBuildRevisionJson = []byte(`{ "source": { "type": "Git", "git": { - "uri": "git://github.com/openshift/ruby-hello-world.git" + "uri": "https://github.com/openshift/ruby-hello-world.git" } }, "strategy": { @@ -21642,7 +19662,7 @@ items: source: type: Git git: - uri: git://github.com/openshift/ruby-hello-world.git + uri: https://github.com/openshift/ruby-hello-world.git strategy: type: Source sourceStrategy: @@ -21671,7 +19691,7 @@ items: source: type: Git git: - uri: git://github.com/openshift/ruby-hello-world.git + uri: https://github.com/openshift/ruby-hello-world.git strategy: type: Source sourceStrategy: @@ -22022,7 +20042,7 @@ var _testExtendedTestdataBuildsTestCdsSourcebuildJson = []byte(`{ "triggers": [], "source":{ "type":"Dockerfile", - "dockerfile":"FROM image-registry.openshift-image-registry.svc:5000/openshift/tools:latest \nRUN sleep 10m" + "dockerfile":"FROM image-registry.openshift-image-registry.svc:5000/openshift/tools:latest\nRUN sleep 10m" }, "strategy": { "type": "Source", @@ -22536,6 +20556,37 @@ func testExtendedTestdataBuildsTestEnvBuildJson() (*asset, error) { return a, nil } +var _testExtendedTestdataBuildsTestImageStreamJson = []byte(`{ + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "test", + "creationTimestamp": null, + "labels": { + "color": "blue" + } + }, + "spec": {}, + "status": { + "dockerImageRepository": "" + } +}`) + +func testExtendedTestdataBuildsTestImageStreamJsonBytes() ([]byte, error) { + return _testExtendedTestdataBuildsTestImageStreamJson, nil +} + +func testExtendedTestdataBuildsTestImageStreamJson() (*asset, error) { + bytes, err := testExtendedTestdataBuildsTestImageStreamJsonBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/extended/testdata/builds/test-image-stream.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + var _testExtendedTestdataBuildsTestImagechangetriggersYaml = []byte(`kind: List apiVersion: v1 items: @@ -23279,7 +21330,7 @@ spec: runPolicy: Serial source: dockerfile: - 'FROM busybox@sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6' + 'FROM image-registry.openshift-image-registry.svc:5000/openshift/tools:latest' strategy: type: Docker dockerStrategy: @@ -24350,7 +22401,7 @@ func testExtendedTestdataBuildsWebhookGenericTestdataPostReceiveGitJson() (*asse var _testExtendedTestdataBuildsWebhookGenericTestdataPushGenericEnvsJson = []byte(`{ "type" : "Git", "git" : { - "uri" : "git://mygitserver/myrepo.git", + "uri" : "https://mygitserver/myrepo.git", "ref" : "refs/heads/master", "commit" : "9bdc3a26ff933b32f3e558636b58aea86a69f051", "message" : "Random act of kindness", @@ -24390,7 +22441,7 @@ func testExtendedTestdataBuildsWebhookGenericTestdataPushGenericEnvsJson() (*ass var _testExtendedTestdataBuildsWebhookGenericTestdataPushGenericEnvsYaml = []byte(`--- type: "Git" git: - uri: "git://mygitserver/myrepo.git" + uri: "https://mygitserver/myrepo.git" ref: "refs/heads/master" commit: "9bdc3a26ff933b32f3e558636b58aea86a69f051" message: "Random act of kindness" @@ -24424,7 +22475,7 @@ func testExtendedTestdataBuildsWebhookGenericTestdataPushGenericEnvsYaml() (*ass var _testExtendedTestdataBuildsWebhookGenericTestdataPushGenericJson = []byte(`{ "type" : "Git", "git" : { - "uri" : "git://mygitserver/myrepo.git", + "uri" : "https://mygitserver/myrepo.git", "ref" : "refs/heads/master", "commit" : "9bdc3a26ff933b32f3e558636b58aea86a69f051", "message" : "Random act of kindness", @@ -24659,7 +22710,7 @@ var _testExtendedTestdataBuildsWebhookGithubTestdataPusheventNotMasterBranchJson "created_at":1409063699, "updated_at":"2014-08-26T14:34:59Z", "pushed_at":1409238007, - "git_url":"git://github.com/anonUser/anonRepo.git", + "git_url":"https://github.com/anonUser/anonRepo.git", "ssh_url":"git@github.com:anonUser/anonRepo.git", "clone_url":"https://github.com/anonUser/anonRepo.git", "svn_url":"https://github.com/anonUser/anonRepo", @@ -24812,7 +22863,7 @@ var _testExtendedTestdataBuildsWebhookGithubTestdataPusheventJson = []byte(`{ "created_at":1409063699, "updated_at":"2014-08-26T14:34:59Z", "pushed_at":1409238007, - "git_url":"git://github.com/anonUser/anonRepo.git", + "git_url":"https://github.com/anonUser/anonRepo.git", "ssh_url":"git@github.com:anonUser/anonRepo.git", "clone_url":"https://github.com/anonUser/anonRepo.git", "svn_url":"https://github.com/anonUser/anonRepo", @@ -25031,7 +23082,7 @@ metadata: spec: containers: - name: hello-centos - image: docker.io/centos:centos7 + image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest command: - /bin/sleep - infinity @@ -25040,10 +23091,9 @@ spec: memory: 256Mi terminationMessagePath: "/dev/termination-log" imagePullPolicy: IfNotPresent - capabilities: {} securityContext: {} - name: hello-centos-2 - image: docker.io/centos:centos7 + image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest command: - /bin/sleep - infinity @@ -25052,7 +23102,6 @@ spec: memory: 256Mi terminationMessagePath: "/dev/termination-log1" imagePullPolicy: IfNotPresent - capabilities: {} securityContext: {} restartPolicy: Always dnsPolicy: ClusterFirst @@ -27874,4216 +25923,3422 @@ var _testExtendedTestdataClusterQuickstartsRailsPostgresqlJson = []byte(`{ }, { "description": "Set this to a branch name, tag or other ref of your repository if you are not using the default branch.", - "displayName": "Git Reference", - "name": "SOURCE_REPOSITORY_REF" - }, - { - "description": "Set this to the relative path to your project if it is not in the root of your repository.", - "displayName": "Context Directory", - "name": "CONTEXT_DIR" - }, - { - "description": "The exposed hostname that will route to the Rails service, if left blank a value will be defaulted.", - "displayName": "Application Hostname", - "name": "APPLICATION_DOMAIN", - "value": "" - }, - { - "description": "Github trigger secret. A difficult to guess string encoded as part of the webhook URL. Not encrypted.", - "displayName": "GitHub Webhook Secret", - "from": "[a-zA-Z0-9]{40}", - "generate": "expression", - "name": "GITHUB_WEBHOOK_SECRET" - }, - { - "description": "Your secret key for verifying the integrity of signed cookies.", - "displayName": "Secret Key", - "from": "[a-z0-9]{127}", - "generate": "expression", - "name": "SECRET_KEY_BASE" - }, - { - "description": "The application user that is used within the sample application to authorize access on pages.", - "displayName": "Application Username", - "name": "APPLICATION_USER", - "required": true, - "value": "openshift" - }, - { - "description": "The application password that is used within the sample application to authorize access on pages.", - "displayName": "Application Password", - "name": "APPLICATION_PASSWORD", - "required": true, - "value": "secret" - }, - { - "description": "Environment under which the sample application will run. Could be set to production, development or test.", - "displayName": "Rails Environment", - "name": "RAILS_ENV", - "required": true, - "value": "production" - }, - { - "displayName": "Database Service Name", - "name": "DATABASE_SERVICE_NAME", - "required": true, - "value": "postgresql" - }, - { - "displayName": "Database Username", - "from": "user[A-Z0-9]{3}", - "generate": "expression", - "name": "DATABASE_USER" - }, - { - "displayName": "Database Password", - "from": "[a-zA-Z0-9]{8}", - "generate": "expression", - "name": "DATABASE_PASSWORD" - }, - { - "displayName": "Database Name", - "name": "DATABASE_NAME", - "required": true, - "value": "root" - }, - { - "displayName": "Maximum Database Connections", - "name": "POSTGRESQL_MAX_CONNECTIONS", - "value": "100" - }, - { - "displayName": "Shared Buffer Amount", - "name": "POSTGRESQL_SHARED_BUFFERS", - "value": "12MB" - }, - { - "description": "The custom RubyGems mirror URL", - "displayName": "Custom RubyGems Mirror URL", - "name": "RUBYGEM_MIRROR", - "value": "" - }, - { - "description": "Unique template ID to prevent name conflict", - "displayName": "CL generation ID", - "name": "IDENTIFIER", - "value": "0" - } - ] -} -`) - -func testExtendedTestdataClusterQuickstartsRailsPostgresqlJsonBytes() ([]byte, error) { - return _testExtendedTestdataClusterQuickstartsRailsPostgresqlJson, nil -} - -func testExtendedTestdataClusterQuickstartsRailsPostgresqlJson() (*asset, error) { - bytes, err := testExtendedTestdataClusterQuickstartsRailsPostgresqlJsonBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/cluster/quickstarts/rails-postgresql.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataCmdHackLibCmdSh = []byte(`#!/usr/bin/env bash -# This utility file contains functions that wrap commands to be tested. All wrapper functions run commands -# in a sub-shell and redirect all output. Tests in test-cmd *must* use these functions for testing. - -# expect_success runs the cmd and expects an exit code of 0 -function os::cmd::expect_success() { - if [[ $# -ne 1 ]]; then echo "os::cmd::expect_success expects only one argument, got $#"; return 1; fi - local cmd=$1 - - os::cmd::internal::expect_exit_code_run_grep "${cmd}" -} -readonly -f os::cmd::expect_success - -# expect_failure runs the cmd and expects a non-zero exit code -function os::cmd::expect_failure() { - if [[ $# -ne 1 ]]; then echo "os::cmd::expect_failure expects only one argument, got $#"; return 1; fi - local cmd=$1 - - os::cmd::internal::expect_exit_code_run_grep "${cmd}" "os::cmd::internal::failure_func" -} -readonly -f os::cmd::expect_failure - -# expect_success_and_text runs the cmd and expects an exit code of 0 -# as well as running a grep test to find the given string in the output -function os::cmd::expect_success_and_text() { - if [[ $# -ne 2 ]]; then echo "os::cmd::expect_success_and_text expects two arguments, got $#"; return 1; fi - local cmd=$1 - local expected_text=$2 - - os::cmd::internal::expect_exit_code_run_grep "${cmd}" "os::cmd::internal::success_func" "${expected_text}" -} -readonly -f os::cmd::expect_success_and_text - -# expect_failure_and_text runs the cmd and expects a non-zero exit code -# as well as running a grep test to find the given string in the output -function os::cmd::expect_failure_and_text() { - if [[ $# -ne 2 ]]; then echo "os::cmd::expect_failure_and_text expects two arguments, got $#"; return 1; fi - local cmd=$1 - local expected_text=$2 - - os::cmd::internal::expect_exit_code_run_grep "${cmd}" "os::cmd::internal::failure_func" "${expected_text}" -} -readonly -f os::cmd::expect_failure_and_text - -# expect_success_and_not_text runs the cmd and expects an exit code of 0 -# as well as running a grep test to ensure the given string is not in the output -function os::cmd::expect_success_and_not_text() { - if [[ $# -ne 2 ]]; then echo "os::cmd::expect_success_and_not_text expects two arguments, got $#"; return 1; fi - local cmd=$1 - local expected_text=$2 - - os::cmd::internal::expect_exit_code_run_grep "${cmd}" "os::cmd::internal::success_func" "${expected_text}" "os::cmd::internal::failure_func" -} -readonly -f os::cmd::expect_success_and_not_text - -# expect_failure_and_not_text runs the cmd and expects a non-zero exit code -# as well as running a grep test to ensure the given string is not in the output -function os::cmd::expect_failure_and_not_text() { - if [[ $# -ne 2 ]]; then echo "os::cmd::expect_failure_and_not_text expects two arguments, got $#"; return 1; fi - local cmd=$1 - local expected_text=$2 - - os::cmd::internal::expect_exit_code_run_grep "${cmd}" "os::cmd::internal::failure_func" "${expected_text}" "os::cmd::internal::failure_func" -} -readonly -f os::cmd::expect_failure_and_not_text - -# expect_code runs the cmd and expects a given exit code -function os::cmd::expect_code() { - if [[ $# -ne 2 ]]; then echo "os::cmd::expect_code expects two arguments, got $#"; return 1; fi - local cmd=$1 - local expected_cmd_code=$2 - - os::cmd::internal::expect_exit_code_run_grep "${cmd}" "os::cmd::internal::specific_code_func ${expected_cmd_code}" -} -readonly -f os::cmd::expect_code - -# expect_code_and_text runs the cmd and expects the given exit code -# as well as running a grep test to find the given string in the output -function os::cmd::expect_code_and_text() { - if [[ $# -ne 3 ]]; then echo "os::cmd::expect_code_and_text expects three arguments, got $#"; return 1; fi - local cmd=$1 - local expected_cmd_code=$2 - local expected_text=$3 - - os::cmd::internal::expect_exit_code_run_grep "${cmd}" "os::cmd::internal::specific_code_func ${expected_cmd_code}" "${expected_text}" -} -readonly -f os::cmd::expect_code_and_text - -# expect_code_and_not_text runs the cmd and expects the given exit code -# as well as running a grep test to ensure the given string is not in the output -function os::cmd::expect_code_and_not_text() { - if [[ $# -ne 3 ]]; then echo "os::cmd::expect_code_and_not_text expects three arguments, got $#"; return 1; fi - local cmd=$1 - local expected_cmd_code=$2 - local expected_text=$3 - - os::cmd::internal::expect_exit_code_run_grep "${cmd}" "os::cmd::internal::specific_code_func ${expected_cmd_code}" "${expected_text}" "os::cmd::internal::failure_func" -} -readonly -f os::cmd::expect_code_and_not_text - -millisecond=1 -second=$(( 1000 * millisecond )) -minute=$(( 60 * second )) - -# os::cmd::try_until_success runs the cmd in a small interval until either the command succeeds or times out -# the default time-out for os::cmd::try_until_success is 60 seconds. -# the default interval for os::cmd::try_until_success is 200ms -function os::cmd::try_until_success() { - if [[ $# -lt 1 ]]; then echo "os::cmd::try_until_success expects at least one arguments, got $#"; return 1; fi - local cmd=$1 - local duration=${2:-$minute} - local interval=${3:-0.2} - - os::cmd::internal::run_until_exit_code "${cmd}" "os::cmd::internal::success_func" "${duration}" "${interval}" -} -readonly -f os::cmd::try_until_success - -# os::cmd::try_until_failure runs the cmd until either the command fails or times out -# the default time-out for os::cmd::try_until_failure is 60 seconds. -function os::cmd::try_until_failure() { - if [[ $# -lt 1 ]]; then echo "os::cmd::try_until_failure expects at least one argument, got $#"; return 1; fi - local cmd=$1 - local duration=${2:-$minute} - local interval=${3:-0.2} - - os::cmd::internal::run_until_exit_code "${cmd}" "os::cmd::internal::failure_func" "${duration}" "${interval}" -} -readonly -f os::cmd::try_until_failure - -# os::cmd::try_until_text runs the cmd until either the command outputs the desired text or times out -# the default time-out for os::cmd::try_until_text is 60 seconds. -function os::cmd::try_until_text() { - if [[ $# -lt 2 ]]; then echo "os::cmd::try_until_text expects at least two arguments, got $#"; return 1; fi - local cmd=$1 - local text=$2 - local duration=${3:-$minute} - local interval=${4:-0.2} - - os::cmd::internal::run_until_text "${cmd}" "${text}" "os::cmd::internal::success_func" "${duration}" "${interval}" -} -readonly -f os::cmd::try_until_text - -# os::cmd::try_until_not_text runs the cmd until either the command doesnot output the text or times out -# the default time-out for os::cmd::try_until_not_text is 60 seconds. -function os::cmd::try_until_not_text() { - if [[ $# -lt 2 ]]; then echo "os::cmd::try_until_not_text expects at least two arguments, got $#"; return 1; fi - local cmd=$1 - local text=$2 - local duration=${3:-$minute} - local interval=${4:-0.2} - - os::cmd::internal::run_until_text "${cmd}" "${text}" "os::cmd::internal::failure_func" "${duration}" "${interval}" -} -readonly -f os::cmd::try_until_text - -# Functions in the os::cmd::internal namespace are discouraged from being used outside of os::cmd - -# In order to harvest stderr and stdout at the same time into different buckets, we need to stick them into files -# in an intermediate step -os_cmd_internal_tmpdir="${TMPDIR:-"/tmp"}/cmd" -os_cmd_internal_tmpout="${os_cmd_internal_tmpdir}/tmp_stdout.log" -os_cmd_internal_tmperr="${os_cmd_internal_tmpdir}/tmp_stderr.log" - -# os::cmd::internal::expect_exit_code_run_grep runs the provided test command and expects a specific -# exit code from that command as well as the success of a specified ` + "`" + `grep` + "`" + ` invocation. Output from the -# command to be tested is suppressed unless either ` + "`" + `VERBOSE=1` + "`" + ` or the test fails. This function bypasses -# any error exiting settings or traps set by upstream callers by masking the return code of the command -# with the return code of setting the result variable on failure. -# -# Globals: -# - JUNIT_REPORT_OUTPUT -# - VERBOSE -# Arguments: -# - 1: the command to run -# - 2: command evaluation assertion to use -# - 3: text to test for -# - 4: text assertion to use -# Returns: -# - 0: if all assertions met -# - 1: if any assertions fail -function os::cmd::internal::expect_exit_code_run_grep() { - local cmd=$1 - # default expected cmd code to 0 for success - local cmd_eval_func=${2:-os::cmd::internal::success_func} - # default to nothing - local grep_args=${3:-} - # default expected test code to 0 for success - local test_eval_func=${4:-os::cmd::internal::success_func} - - local -a junit_log - - os::cmd::internal::init_tempdir - os::test::junit::declare_test_start - - local name=$(os::cmd::internal::describe_call "${cmd}" "${cmd_eval_func}" "${grep_args}" "${test_eval_func}") - local preamble="Running ${name}..." - echo "${preamble}" - # for ease of parsing, we want the entire declaration on one line, so we replace '\n' with ';' - junit_log+=( "${name//$'\n'/;}" ) - - local start_time=$(os::cmd::internal::seconds_since_epoch) - - local cmd_result=$( os::cmd::internal::run_collecting_output "${cmd}"; echo $? ) - local cmd_succeeded=$( ${cmd_eval_func} "${cmd_result}"; echo $? ) - - local test_result=0 - if [[ -n "${grep_args}" ]]; then - test_result=$( os::cmd::internal::run_collecting_output 'grep -Eq "${grep_args}" <(os::cmd::internal::get_results)'; echo $? ) - fi - local test_succeeded=$( ${test_eval_func} "${test_result}"; echo $? ) - - local end_time=$(os::cmd::internal::seconds_since_epoch) - local time_elapsed=$(echo $(( ${end_time} - ${start_time} )) | xargs printf '%5.3f') # in decimal seconds, we need leading zeroes for parsing later - - # clear the preamble so we can print out the success or error message - os::text::clear_string "${preamble}" - - local return_code - if (( cmd_succeeded && test_succeeded )); then - os::text::print_green "SUCCESS after ${time_elapsed}s: ${name}" - junit_log+=( "SUCCESS after ${time_elapsed}s: ${name//$'\n'/;}" ) - - if [[ -n ${VERBOSE-} ]]; then - os::cmd::internal::print_results - fi - return_code=0 - else - local cause=$(os::cmd::internal::assemble_causes "${cmd_succeeded}" "${test_succeeded}") - - os::text::print_red_bold "FAILURE after ${time_elapsed}s: ${name}: ${cause}" - junit_log+=( "FAILURE after ${time_elapsed}s: ${name//$'\n'/;}: ${cause}" ) - - os::text::print_red "$(os::cmd::internal::print_results)" - return_code=1 - fi - - junit_log+=( "$(os::cmd::internal::print_results)" ) - # append inside of a subshell so that IFS doesn't get propagated out - ( IFS=$'\n'; echo "${junit_log[*]}" >> "${JUNIT_REPORT_OUTPUT:-/dev/null}" ) - os::test::junit::declare_test_end - return "${return_code}" -} -readonly -f os::cmd::internal::expect_exit_code_run_grep - -# os::cmd::internal::init_tempdir initializes the temporary directory -function os::cmd::internal::init_tempdir() { - mkdir -p "${os_cmd_internal_tmpdir}" - rm -f "${os_cmd_internal_tmpdir}"/tmp_std{out,err}.log -} -readonly -f os::cmd::internal::init_tempdir - -# os::cmd::internal::describe_call determines the file:line of the latest function call made -# from outside of this file in the call stack, and the name of the function being called from -# that line, returning a string describing the call -function os::cmd::internal::describe_call() { - local cmd=$1 - local cmd_eval_func=$2 - local grep_args=${3:-} - local test_eval_func=${4:-} - - local caller_id=$(os::cmd::internal::determine_caller) - local full_name="${caller_id}: executing '${cmd}'" - - local cmd_expectation=$(os::cmd::internal::describe_expectation "${cmd_eval_func}") - local full_name="${full_name} expecting ${cmd_expectation}" - - if [[ -n "${grep_args}" ]]; then - local text_expecting= - case "${test_eval_func}" in - "os::cmd::internal::success_func") - text_expecting="text" ;; - "os::cmd::internal::failure_func") - text_expecting="not text" ;; - esac - full_name="${full_name} and ${text_expecting} '${grep_args}'" - fi - - echo "${full_name}" -} -readonly -f os::cmd::internal::describe_call - -# os::cmd::internal::determine_caller determines the file relative to the OpenShift Origin root directory -# and line number of the function call to the outer os::cmd wrapper function -function os::cmd::internal::determine_caller() { - local call_depth= - local len_sources="${#BASH_SOURCE[@]}" - for (( i=0; i<${len_sources}; i++ )); do - if [ ! $(echo "${BASH_SOURCE[i]}" | grep "hack/lib/cmd\.sh$") ]; then - call_depth=i - break - fi - done - - local caller_file="${BASH_SOURCE[${call_depth}]}" - caller_file="$( os::util::repository_relative_path "${caller_file}" )" - local caller_line="${BASH_LINENO[${call_depth}-1]}" - echo "${caller_file}:${caller_line}" -} -readonly -f os::cmd::internal::determine_caller - -# os::cmd::internal::describe_expectation describes a command return code evaluation function -function os::cmd::internal::describe_expectation() { - local func=$1 - case "${func}" in - "os::cmd::internal::success_func") - echo "success" ;; - "os::cmd::internal::failure_func") - echo "failure" ;; - "os::cmd::internal::specific_code_func"*[0-9]) - local code=$(echo "${func}" | grep -Eo "[0-9]+$") - echo "exit code ${code}" ;; - "") - echo "any result" - esac -} -readonly -f os::cmd::internal::describe_expectation - -# os::cmd::internal::seconds_since_epoch returns the number of seconds elapsed since the epoch -# with milli-second precision -function os::cmd::internal::seconds_since_epoch() { - local ns=$(date +%s%N) - # if ` + "`" + `date` + "`" + ` doesn't support nanoseconds, return second precision - if [[ "$ns" == *N ]]; then - date "+%s.000" - return - fi - echo $(( ${ns}/1000000000 )) -} -readonly -f os::cmd::internal::seconds_since_epoch - -# os::cmd::internal::run_collecting_output runs the command given, piping stdout and stderr into -# the given files, and returning the exit code of the command -function os::cmd::internal::run_collecting_output() { - local cmd=$1 - - local result= - $( eval "${cmd}" 1>>"${os_cmd_internal_tmpout}" 2>>"${os_cmd_internal_tmperr}" ) || result=$? - local result=${result:-0} # if we haven't set result yet, the command succeeded - - return "${result}" -} -readonly -f os::cmd::internal::run_collecting_output - -# os::cmd::internal::success_func determines if the input exit code denotes success -# this function returns 0 for false and 1 for true to be compatible with arithmetic tests -function os::cmd::internal::success_func() { - local exit_code=$1 - - # use a negated test to get output correct for (( )) - [[ "${exit_code}" -ne "0" ]] - return $? -} -readonly -f os::cmd::internal::success_func - -# os::cmd::internal::failure_func determines if the input exit code denotes failure -# this function returns 0 for false and 1 for true to be compatible with arithmetic tests -function os::cmd::internal::failure_func() { - local exit_code=$1 - - # use a negated test to get output correct for (( )) - [[ "${exit_code}" -eq "0" ]] - return $? -} -readonly -f os::cmd::internal::failure_func - -# os::cmd::internal::specific_code_func determines if the input exit code matches the given code -# this function returns 0 for false and 1 for true to be compatible with arithmetic tests -function os::cmd::internal::specific_code_func() { - local expected_code=$1 - local exit_code=$2 - - # use a negated test to get output correct for (( )) - [[ "${exit_code}" -ne "${expected_code}" ]] - return $? -} -readonly -f os::cmd::internal::specific_code_func - -# os::cmd::internal::get_results prints the stderr and stdout files -function os::cmd::internal::get_results() { - cat "${os_cmd_internal_tmpout}" "${os_cmd_internal_tmperr}" -} -readonly -f os::cmd::internal::get_results - -# os::cmd::internal::get_last_results prints the stderr and stdout from the last attempt -function os::cmd::internal::get_last_results() { - cat "${os_cmd_internal_tmpout}" | awk 'BEGIN { RS = "\x1e" } END { print $0 }' - cat "${os_cmd_internal_tmperr}" | awk 'BEGIN { RS = "\x1e" } END { print $0 }' -} -readonly -f os::cmd::internal::get_last_results - -# os::cmd::internal::mark_attempt marks the end of an attempt in the stdout and stderr log files -# this is used to make the try_until_* output more concise -function os::cmd::internal::mark_attempt() { - echo -e '\x1e' >> "${os_cmd_internal_tmpout}" - echo -e '\x1e' >> "${os_cmd_internal_tmperr}" -} -readonly -f os::cmd::internal::mark_attempt - -# os::cmd::internal::compress_output compresses an output file into timeline representation -function os::cmd::internal::compress_output() { - local logfile=$1 - - awk -f ${OS_ROOT}/hack/lib/compress.awk $logfile -} -readonly -f os::cmd::internal::compress_output - -# os::cmd::internal::print_results pretty-prints the stderr and stdout files. If attempt separators -# are present, this function returns a concise view of the stdout and stderr output files using a -# timeline format, where consecutive output lines that are the same are condensed into one line -# with a counter -function os::cmd::internal::print_results() { - if [[ -s "${os_cmd_internal_tmpout}" ]]; then - echo "Standard output from the command:" - if grep -q $'\x1e' "${os_cmd_internal_tmpout}"; then - os::cmd::internal::compress_output "${os_cmd_internal_tmpout}" - else - cat "${os_cmd_internal_tmpout}"; echo - fi - else - echo "There was no output from the command." - fi - - if [[ -s "${os_cmd_internal_tmperr}" ]]; then - echo "Standard error from the command:" - if grep -q $'\x1e' "${os_cmd_internal_tmperr}"; then - os::cmd::internal::compress_output "${os_cmd_internal_tmperr}" - else - cat "${os_cmd_internal_tmperr}"; echo - fi - else - echo "There was no error output from the command." - fi -} -readonly -f os::cmd::internal::print_results - -# os::cmd::internal::assemble_causes determines from the two input booleans which part of the test -# failed and generates a nice delimited list of failure causes -function os::cmd::internal::assemble_causes() { - local cmd_succeeded=$1 - local test_succeeded=$2 - - local causes=() - if (( ! cmd_succeeded )); then - causes+=("the command returned the wrong error code") - fi - if (( ! test_succeeded )); then - causes+=("the output content test failed") - fi - - local list=$(printf '; %s' "${causes[@]}") - echo "${list:2}" -} -readonly -f os::cmd::internal::assemble_causes - -# os::cmd::internal::run_until_exit_code runs the provided command until the exit code test given -# succeeds or the timeout given runs out. Output from the command to be tested is suppressed unless -# either ` + "`" + `VERBOSE=1` + "`" + ` or the test fails. This function bypasses any error exiting settings or traps -# set by upstream callers by masking the return code of the command with the return code of setting -# the result variable on failure. -# -# Globals: -# - JUNIT_REPORT_OUTPUT -# - VERBOSE -# Arguments: -# - 1: the command to run -# - 2: command evaluation assertion to use -# - 3: timeout duration -# - 4: interval duration -# Returns: -# - 0: if all assertions met before timeout -# - 1: if timeout occurs -function os::cmd::internal::run_until_exit_code() { - local cmd=$1 - local cmd_eval_func=$2 - local duration=$3 - local interval=$4 - - local -a junit_log - - os::cmd::internal::init_tempdir - os::test::junit::declare_test_start - - local description=$(os::cmd::internal::describe_call "${cmd}" "${cmd_eval_func}") - local duration_seconds=` + "`" + `echo $(( $(( duration )) / 1000 )) | xargs printf '%5.3f'` + "`" + ` - local description="${description}; re-trying every ${interval}s until completion or ${duration_seconds}s" - local preamble="Running ${description}..." - echo "${preamble}" - # for ease of parsing, we want the entire declaration on one line, so we replace '\n' with ';' - junit_log+=( "${description//$'\n'/;}" ) - - local start_time=$(os::cmd::internal::seconds_since_epoch) - - local deadline=$(( $(date +%s000) + $duration )) - local cmd_succeeded=0 - while [ $(date +%s000) -lt $deadline ]; do - local cmd_result=$( os::cmd::internal::run_collecting_output "${cmd}"; echo $? ) - cmd_succeeded=$( ${cmd_eval_func} "${cmd_result}"; echo $? ) - if (( cmd_succeeded )); then - break - fi - sleep "${interval}" - os::cmd::internal::mark_attempt - done - - local end_time=$(os::cmd::internal::seconds_since_epoch) - local time_elapsed=$(echo $(( ${end_time} - ${start_time} )) | xargs printf '%5.3f') # in decimal seconds, we need leading zeroes for parsing later - - # clear the preamble so we can print out the success or error message - os::text::clear_string "${preamble}" - - local return_code - if (( cmd_succeeded )); then - os::text::print_green "SUCCESS after ${time_elapsed}s: ${description}" - junit_log+=( "SUCCESS after ${time_elapsed}s: ${description//$'\n'/;}" ) - - if [[ -n ${VERBOSE-} ]]; then - os::cmd::internal::print_results - fi - return_code=0 - else - os::text::print_red_bold "FAILURE after ${time_elapsed}s: ${description}: the command timed out" - junit_log+=( "FAILURE after ${time_elapsed}s: ${description//$'\n'/;}: the command timed out" ) - - os::text::print_red "$(os::cmd::internal::print_results)" - return_code=1 - fi - - junit_log+=( "$(os::cmd::internal::print_results)" ) - ( IFS=$'\n'; echo "${junit_log[*]}" >> "${JUNIT_REPORT_OUTPUT:-/dev/null}" ) - os::test::junit::declare_test_end - return "${return_code}" -} -readonly -f os::cmd::internal::run_until_exit_code - -# os::cmd::internal::run_until_text runs the provided command until the assertion function succeeds with -# the given text on the command output or the timeout given runs out. This can be used to run until the -# output does or does not contain some text. Output from the command to be tested is suppressed unless -# either ` + "`" + `VERBOSE=1` + "`" + ` or the test fails. This function bypasses any error exiting settings or traps -# set by upstream callers by masking the return code of the command with the return code of setting -# the result variable on failure. -# -# Globals: -# - JUNIT_REPORT_OUTPUT -# - VERBOSE -# Arguments: -# - 1: the command to run -# - 2: text to test for -# - 3: text assertion to use -# - 4: timeout duration -# - 5: interval duration -# Returns: -# - 0: if all assertions met before timeout -# - 1: if timeout occurs -function os::cmd::internal::run_until_text() { - local cmd=$1 - local text=$2 - local test_eval_func=${3:-os::cmd::internal::success_func} - local duration=$4 - local interval=$5 - - local -a junit_log - - os::cmd::internal::init_tempdir - os::test::junit::declare_test_start - - local description=$(os::cmd::internal::describe_call "${cmd}" "" "${text}" "${test_eval_func}") - local duration_seconds=$(echo $(( $(( duration )) / 1000)) | xargs printf '%5.3f') - local description="${description}; re-trying every ${interval}s until completion or ${duration_seconds}s" - local preamble="Running ${description}..." - echo "${preamble}" - # for ease of parsing, we want the entire declaration on one line, so we replace '\n' with ';' - junit_log+=( "${description//$'\n'/;}" ) - - local start_time=$(os::cmd::internal::seconds_since_epoch) - - local deadline=$(( $(date +%s000) + $duration )) - local test_succeeded=0 - while [ $(date +%s000) -lt $deadline ]; do - local cmd_result=$( os::cmd::internal::run_collecting_output "${cmd}"; echo $? ) - local test_result - test_result=$( os::cmd::internal::run_collecting_output 'grep -Eq "${text}" <(os::cmd::internal::get_last_results)'; echo $? ) - test_succeeded=$( ${test_eval_func} "${test_result}"; echo $? ) - - if (( test_succeeded )); then - break - fi - sleep "${interval}" - os::cmd::internal::mark_attempt - done - - local end_time=$(os::cmd::internal::seconds_since_epoch) - local time_elapsed=$(echo $(( ${end_time} - ${start_time} )) | xargs printf '%5.3f') # in decimal seconds, we need leading zeroes for parsing later - - # clear the preamble so we can print out the success or error message - os::text::clear_string "${preamble}" - - local return_code - if (( test_succeeded )); then - os::text::print_green "SUCCESS after ${time_elapsed}s: ${description}" - junit_log+=( "SUCCESS after ${time_elapsed}s: ${description//$'\n'/;}" ) - - if [[ -n ${VERBOSE-} ]]; then - os::cmd::internal::print_results - fi - return_code=0 - else - os::text::print_red_bold "FAILURE after ${time_elapsed}s: ${description}: the command timed out" - junit_log+=( "FAILURE after ${time_elapsed}s: ${description//$'\n'/;}: the command timed out" ) - - os::text::print_red "$(os::cmd::internal::print_results)" - return_code=1 - fi - - junit_log+=( "$(os::cmd::internal::print_results)" ) - ( IFS=$'\n'; echo "${junit_log[*]}" >> "${JUNIT_REPORT_OUTPUT:-/dev/null}" ) - os::test::junit::declare_test_end - return "${return_code}" -} -readonly -f os::cmd::internal::run_until_text -`) - -func testExtendedTestdataCmdHackLibCmdShBytes() ([]byte, error) { - return _testExtendedTestdataCmdHackLibCmdSh, nil -} - -func testExtendedTestdataCmdHackLibCmdSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdHackLibCmdShBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/cmd.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataCmdHackLibCompressAwk = []byte(`# Helper functions -function trim(s) { - gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "", s); - return s; -} - -function printRecordAndCount(record, count) { - print record; - if (count > 1) { - printf("... repeated %d times\n", count) - } -} - -BEGIN { - # Before processing, set the record separator to the ASCII record separator character \x1e - RS = "\x1e"; -} - -# This action is executed for each record -{ - # Build our current var from the trimmed record - current = trim($0); - - # Bump the count of times we have seen it - seen[current]++; - - # Print the previous record and its count (if it is not identical to the current record) - if (previous && previous != current) { - printRecordAndCount(previous, seen[previous]); - } - - # Store the current record as the previous record - previous = current; -} - -END { - # After processing, print the last record and count if it is non-empty - if (previous) { - printRecordAndCount(previous, seen[previous]); - } -}`) - -func testExtendedTestdataCmdHackLibCompressAwkBytes() ([]byte, error) { - return _testExtendedTestdataCmdHackLibCompressAwk, nil -} - -func testExtendedTestdataCmdHackLibCompressAwk() (*asset, error) { - bytes, err := testExtendedTestdataCmdHackLibCompressAwkBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/compress.awk", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataCmdHackLibConstantsSh = []byte(`#!/usr/bin/env bash - -readonly OS_OUTPUT_BASEPATH="${OS_OUTPUT_BASEPATH:-_output}" -readonly OS_BASE_OUTPUT="${OS_ROOT}/${OS_OUTPUT_BASEPATH}" -readonly OS_OUTPUT_SCRIPTPATH="${OS_OUTPUT_SCRIPTPATH:-"${OS_BASE_OUTPUT}/scripts"}" -`) - -func testExtendedTestdataCmdHackLibConstantsShBytes() ([]byte, error) { - return _testExtendedTestdataCmdHackLibConstantsSh, nil -} - -func testExtendedTestdataCmdHackLibConstantsSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdHackLibConstantsShBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/constants.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataCmdHackLibInitSh = []byte(`#!/usr/bin/env bash - -# This script is meant to be the entrypoint for OpenShift Bash scripts to import all of the support -# libraries at once in order to make Bash script preambles as minimal as possible. This script recur- -# sively ` + "`" + `source` + "`" + `s *.sh files in this directory tree. As such, no files should be ` + "`" + `source` + "`" + `ed outside -# of this script to ensure that we do not attempt to overwrite read-only variables. - -set -o errexit -set -o nounset -set -o pipefail - -OS_SCRIPT_START_TIME="$( date +%s )"; export OS_SCRIPT_START_TIME - -# os::util::absolute_path returns the absolute path to the directory provided -function os::util::absolute_path() { - local relative_path="$1" - local absolute_path - - pushd "${relative_path}" >/dev/null - relative_path="$( pwd )" - if [[ -h "${relative_path}" ]]; then - absolute_path="$( readlink "${relative_path}" )" - else - absolute_path="${relative_path}" - fi - popd >/dev/null - - echo "${absolute_path}" -} -readonly -f os::util::absolute_path - -# find the absolute path to the root of the Origin source tree -init_source="$( dirname "${BASH_SOURCE[0]}" )/../.." -OS_ROOT="$( os::util::absolute_path "${init_source}" )" -export OS_ROOT -cd "${OS_ROOT}" - -source "${OS_ROOT}/hack/lib/constants.sh" -source "${OS_ROOT}/hack/lib/cmd.sh" - -for library_file in $( find "${OS_ROOT}/hack/lib/log" -type f -name '*.sh' -not -path '*/hack/lib/init.sh' ); do - source "${library_file}" -done -for library_file in $( find "${OS_ROOT}/hack/lib/test" -type f -name '*.sh' -not -path '*/hack/lib/init.sh' ); do - source "${library_file}" -done -for library_file in $( find "${OS_ROOT}/hack/lib/util" -type f -name '*.sh' -not -path '*/hack/lib/init.sh' ); do - source "${library_file}" -done - -unset library_files library_file init_source - -# all of our Bash scripts need to have the stacktrace -# handler installed to deal with errors -os::log::stacktrace::install - -# All of our Bash scripts need to have access to the -# binaries that we build so we don't have to find -# them before every invocation. -os::util::environment::update_path_var - -if [[ -z "${OS_TMP_ENV_SET-}" ]]; then - # if this file is run via 'source', then $0 will be "-bash" and won't work with basename - if [[ "${0}" =~ .*\.sh ]]; then - os::util::environment::setup_tmpdir_vars "$( basename "${0}" ".sh" )" - else - os::util::environment::setup_tmpdir_vars "shell" - fi -fi - -# Allow setting $JUNIT_REPORT to toggle output behavior -if [[ -n "${JUNIT_REPORT:-}" ]]; then - export JUNIT_REPORT_OUTPUT="${LOG_DIR}/raw_test_output.log" -fi - - -cp ${KUBECONFIG_TESTS} /kubeconfig -chmod 644 /kubeconfig -export KUBECONFIG=/kubeconfig - -namespace="cmd-${TEST_NAME}" -oc new-project "${namespace}" -`) - -func testExtendedTestdataCmdHackLibInitShBytes() ([]byte, error) { - return _testExtendedTestdataCmdHackLibInitSh, nil -} - -func testExtendedTestdataCmdHackLibInitSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdHackLibInitShBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/init.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataCmdHackLibLogOutputSh = []byte(`#!/usr/bin/env bash - -# This file contains functions used for writing log messages -# to stdout and stderr from scripts while they run. - -# os::log::info writes the message to stdout. -# -# Arguments: -# - all: message to write -function os::log::info() { - local message; message="$( os::log::internal::prefix_lines "[INFO]" "$*" )" - os::log::internal::to_logfile "${message}" - echo "${message}" -} -readonly -f os::log::info - -# os::log::warning writes the message to stderr. -# A warning indicates something went wrong but -# not so wrong that we cannot recover. -# -# Arguments: -# - all: message to write -function os::log::warning() { - local message; message="$( os::log::internal::prefix_lines "[WARNING]" "$*" )" - os::log::internal::to_logfile "${message}" - os::text::print_yellow "${message}" 1>&2 -} -readonly -f os::log::warning - -# os::log::error writes the message to stderr. -# An error indicates that something went wrong -# and we will most likely fail after this. -# -# Arguments: -# - all: message to write -function os::log::error() { - local message; message="$( os::log::internal::prefix_lines "[ERROR]" "$*" )" - os::log::internal::to_logfile "${message}" - os::text::print_red "${message}" 1>&2 -} -readonly -f os::log::error - -# os::log::fatal writes the message to stderr and -# returns a non-zero code to force a process exit. -# A fatal error indicates that there is no chance -# of recovery. -# -# Arguments: -# - all: message to write -function os::log::fatal() { - local message; message="$( os::log::internal::prefix_lines "[FATAL]" "$*" )" - os::log::internal::to_logfile "${message}" - os::text::print_red "${message}" 1>&2 - exit 1 -} -readonly -f os::log::fatal - -# os::log::debug writes the message to stderr if -# the ${OS_DEBUG} variable is set. -# -# Globals: -# - OS_DEBUG -# Arguments: -# - all: message to write -function os::log::debug() { - local message; message="$( os::log::internal::prefix_lines "[DEBUG]" "$*" )" - os::log::internal::to_logfile "${message}" - if [[ -n "${OS_DEBUG:-}" ]]; then - os::text::print_blue "${message}" 1>&2 - fi -} -readonly -f os::log::debug - -# os::log::internal::to_logfile makes a best-effort -# attempt to write the message to the script logfile -# -# Globals: -# - LOG_DIR -# Arguments: -# - all: message to write -function os::log::internal::to_logfile() { - if [[ -n "${LOG_DIR:-}" && -d "${LOG_DIR-}" ]]; then - echo "$*" >>"${LOG_DIR}/scripts.log" - fi -} - -# os::log::internal::prefix_lines prints out the -# original content with the given prefix at the -# start of every line. -# -# Arguments: -# - 1: prefix for lines -# - 2: content to prefix -function os::log::internal::prefix_lines() { - local prefix="$1" - local content="$2" - - local old_ifs="${IFS}" - IFS=$'\n' - for line in ${content}; do - echo "${prefix} ${line}" - done - IFS="${old_ifs}" -}`) - -func testExtendedTestdataCmdHackLibLogOutputShBytes() ([]byte, error) { - return _testExtendedTestdataCmdHackLibLogOutputSh, nil -} - -func testExtendedTestdataCmdHackLibLogOutputSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdHackLibLogOutputShBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/log/output.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataCmdHackLibLogStacktraceSh = []byte(`#!/usr/bin/env bash -# -# This library contains an implementation of a stack trace for Bash scripts. - -# os::log::stacktrace::install installs the stacktrace as a handler for the ERR signal if one -# has not already been installed and sets ` + "`" + `set -o errtrace` + "`" + ` in order to propagate the handler -# If the ERR trap is not initialized, installing this plugin will initialize it. -# -# Globals: -# None -# Arguments: -# None -# Returns: -# - export OS_USE_STACKTRACE -function os::log::stacktrace::install() { - # setting 'errtrace' propagates our ERR handler to functions, expansions and subshells - set -o errtrace - - # OS_USE_STACKTRACE is read by os::util::trap at runtime to request a stacktrace - export OS_USE_STACKTRACE=true - - os::util::trap::init_err -} -readonly -f os::log::stacktrace::install - -# os::log::stacktrace::print prints the stacktrace and exits with the return code from the script that -# called for a stack trace. This function will always return 0 if it is not handling the signal, and if it -# is handling the signal, this function will always ` + "`" + `exit` + "`" + `, not return, the return code it receives as -# its first argument. -# -# Globals: -# - BASH_SOURCE -# - BASH_LINENO -# - FUNCNAME -# Arguments: -# - 1: the return code of the command in the script that generated the ERR signal -# - 2: the last command that ran before handlers were invoked -# - 3: whether or not ` + "`" + `set -o errexit` + "`" + ` was set in the script that generated the ERR signal -# Returns: -# None -function os::log::stacktrace::print() { - local return_code=$1 - local last_command=$2 - local errexit_set=${3:-} - - if [[ "${return_code}" = "0" ]]; then - # we're not supposed to respond when no error has occurred - return 0 - fi - - if [[ -z "${errexit_set}" ]]; then - # if errexit wasn't set in the shell when the ERR signal was issued, then we can ignore the signal - # as this is not cause for failure - return 0 - fi - - # dump the entire stack for debugging purposes - os::log::debug "$( os::util::repository_relative_path "${BASH_SOURCE[0]}:${LINENO}: ${BASH_COMMAND}" )" - for (( i = 0; i < ${#BASH_LINENO[@]}; i++ )); do - os::log::debug "$( os::util::repository_relative_path "${BASH_SOURCE[$i+1]:-"$( os::util::repository_relative_path "$0" )"}" ):${BASH_LINENO[$i]}: ${FUNCNAME[$i]}" - done - - # iterate backwards through the stack until we leave library files, so we can be sure we start logging - # actual script code and not this handler's call - local stack_begin_index - for (( stack_begin_index = 0; stack_begin_index < ${#BASH_SOURCE[@]}; stack_begin_index++ )); do - if [[ ! "${BASH_SOURCE[${stack_begin_index}]}" =~ hack/lib/(log/stacktrace|util/trap)\.sh ]]; then - break - fi - done - - local preamble_finished - local stack_index=1 - local i - for (( i = stack_begin_index; i < ${#BASH_SOURCE[@]}; i++ )); do - local bash_source - bash_source="$( os::util::repository_relative_path "${BASH_SOURCE[$i]}" )" - if [[ -z "${preamble_finished:-}" ]]; then - preamble_finished=true - os::log::error "${bash_source}:${BASH_LINENO[$i-1]}: \` + "`" + `${last_command}\` + "`" + ` exited with status ${return_code}." >&2 - exit "${return_code}" - fi - stack_index=$(( stack_index + 1 )) - done - - # we know we're the privileged handler in this chain, so we can safely exit the shell without - # starving another handler of the privilege of reacting to this signal - os::log::info " Exiting with code ${return_code}." >&2 - exit "${return_code}" + "displayName": "Git Reference", + "name": "SOURCE_REPOSITORY_REF" + }, + { + "description": "Set this to the relative path to your project if it is not in the root of your repository.", + "displayName": "Context Directory", + "name": "CONTEXT_DIR" + }, + { + "description": "The exposed hostname that will route to the Rails service, if left blank a value will be defaulted.", + "displayName": "Application Hostname", + "name": "APPLICATION_DOMAIN", + "value": "" + }, + { + "description": "Github trigger secret. A difficult to guess string encoded as part of the webhook URL. Not encrypted.", + "displayName": "GitHub Webhook Secret", + "from": "[a-zA-Z0-9]{40}", + "generate": "expression", + "name": "GITHUB_WEBHOOK_SECRET" + }, + { + "description": "Your secret key for verifying the integrity of signed cookies.", + "displayName": "Secret Key", + "from": "[a-z0-9]{127}", + "generate": "expression", + "name": "SECRET_KEY_BASE" + }, + { + "description": "The application user that is used within the sample application to authorize access on pages.", + "displayName": "Application Username", + "name": "APPLICATION_USER", + "required": true, + "value": "openshift" + }, + { + "description": "The application password that is used within the sample application to authorize access on pages.", + "displayName": "Application Password", + "name": "APPLICATION_PASSWORD", + "required": true, + "value": "secret" + }, + { + "description": "Environment under which the sample application will run. Could be set to production, development or test.", + "displayName": "Rails Environment", + "name": "RAILS_ENV", + "required": true, + "value": "production" + }, + { + "displayName": "Database Service Name", + "name": "DATABASE_SERVICE_NAME", + "required": true, + "value": "postgresql" + }, + { + "displayName": "Database Username", + "from": "user[A-Z0-9]{3}", + "generate": "expression", + "name": "DATABASE_USER" + }, + { + "displayName": "Database Password", + "from": "[a-zA-Z0-9]{8}", + "generate": "expression", + "name": "DATABASE_PASSWORD" + }, + { + "displayName": "Database Name", + "name": "DATABASE_NAME", + "required": true, + "value": "root" + }, + { + "displayName": "Maximum Database Connections", + "name": "POSTGRESQL_MAX_CONNECTIONS", + "value": "100" + }, + { + "displayName": "Shared Buffer Amount", + "name": "POSTGRESQL_SHARED_BUFFERS", + "value": "12MB" + }, + { + "description": "The custom RubyGems mirror URL", + "displayName": "Custom RubyGems Mirror URL", + "name": "RUBYGEM_MIRROR", + "value": "" + }, + { + "description": "Unique template ID to prevent name conflict", + "displayName": "CL generation ID", + "name": "IDENTIFIER", + "value": "0" + } + ] } -readonly -f os::log::stacktrace::print `) -func testExtendedTestdataCmdHackLibLogStacktraceShBytes() ([]byte, error) { - return _testExtendedTestdataCmdHackLibLogStacktraceSh, nil +func testExtendedTestdataClusterQuickstartsRailsPostgresqlJsonBytes() ([]byte, error) { + return _testExtendedTestdataClusterQuickstartsRailsPostgresqlJson, nil } -func testExtendedTestdataCmdHackLibLogStacktraceSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdHackLibLogStacktraceShBytes() +func testExtendedTestdataClusterQuickstartsRailsPostgresqlJson() (*asset, error) { + bytes, err := testExtendedTestdataClusterQuickstartsRailsPostgresqlJsonBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/log/stacktrace.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cluster/quickstarts/rails-postgresql.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdHackLibLogSystemSh = []byte(`#!/usr/bin/env bash -# -# This library holds all of the system logging functions for OpenShift bash scripts. - -# os::log::system::install_cleanup installs os::log::system::clean_up as a trap on exit. -# If any traps are currently set for these signals, os::log::system::clean_up is prefixed. -# -# Globals: -# None -# Arguments: -# None -# Returns: -# None -function os::log::system::install_cleanup() { - trap "os::log::system::clean_up; $(trap -p EXIT | awk -F"'" '{print $2}')" EXIT -} -readonly -f os::log::system::install_cleanup - -# os::log::system::clean_up should be trapped so that it can stop the logging utility once the script that -# installed it is finished. -# This function stops logging and generates plots of data for easy consumption. -# -# Globals: -# - LOG_DIR -# - LOGGER_PID -# - SAR_LOGFILE -# Arguments: -# None -# Returns: -# None -function os::log::system::clean_up() { - local return_code=$? - - # we don't want failures in this logger to - set +o errexit - - if jobs -pr | grep -q "${LOGGER_PID}"; then - kill -SIGTERM "${LOGGER_PID}" - # give logger ten seconds to gracefully exit before killing it - for (( i = 0; i < 10; i++ )); do - if ! jobs -pr | grep -q "${LOGGER_PID}"; then - # the logger has shutdown, we don't need to wait on it any longer - break - fi - done - - if jobs -pr | grep -q "${LOGGER_PID}"; then - # the logger has not shutdown, so kill it - kill -SIGKILL "${LOGGER_PID}" - fi - fi - - if ! which sadf >/dev/null 2>&1; then - os::log::warning "System logger data could not be unpacked and graphed, 'sadf' binary not found in this environment." - return 0 - fi - - if [[ ! -s "${SAR_LOGFILE:-}" ]]; then - os::log::warning "No system logger data could be found, log file missing." - return 0 - fi - - local log_subset_flags=( "-b" "-B" "-u ALL" "-q" "-r" ) - - local log_subset_names=( "iops" "paging" "cpu" "queue" "memory" ) - - local log_subset_file - local i - for (( i = 0; i < "${#log_subset_flags[@]}"; i++ )); do - log_subset_file="${LOG_DIR}/${log_subset_names[$i]}.txt" - # use sadf utility to extract data into easily-parseable format - sadf -d "${SAR_LOGFILE}" -- ${log_subset_flags[$i]} > "${log_subset_file}" - - local ignored_columns="hostname,interval," - - # special cases for special output from SAR, because the tool often gives us columns full of baloney - if [[ "${log_subset_names[$i]}" == "cpu" ]]; then - ignored_columns="${ignored_columns}CPU," - fi - - os::log::system::internal::prune_datafile "${log_subset_file}" "${ignored_columns}" - os::log::system::internal::plot "${log_subset_file}" - done +var _testExtendedTestdataCmdHackLibCmdSh = []byte(`#!/usr/bin/env bash +# This utility file contains functions that wrap commands to be tested. All wrapper functions run commands +# in a sub-shell and redirect all output. Tests in test-cmd *must* use these functions for testing. - # remove the ` + "`" + `sar` + "`" + ` log file for space constraints - rm -f "${SAR_LOGFILE}" +# expect_success runs the cmd and expects an exit code of 0 +function os::cmd::expect_success() { + if [[ $# -ne 1 ]]; then echo "os::cmd::expect_success expects only one argument, got $#"; return 1; fi + local cmd=$1 - return "${return_code}" + os::cmd::internal::expect_exit_code_run_grep "${cmd}" } -readonly -f os::log::system::clean_up - -# os::log::system::internal::prune_datafile removes the given columns from a datafile created by 'sadf -d' -# -# Globals: -# None -# Arguments: -# - 1: datafile -# - 2: comma-delimited columns to remove, with trailing comma -# Returns: -# None -function os::log::system::internal::prune_datafile() { - local datafile=$1 - local column_names=$2 - - if [[ "${#column_names}" -eq 0 ]]; then - return 0 - fi - - local columns_in_order - columns_in_order=( $( head -n 1 "${datafile}" | sed 's/^# //g' | tr ';' ' ' ) ) - - local columns_to_keep - local i - for (( i = 0; i < "${#columns_in_order[@]}"; i++ )); do - if ! echo "${column_names}" | grep -q "${columns_in_order[$i]},"; then - # this is a column we need to keep, adding one as 'cut' is 1-indexed - columns_to_keep+=( "$(( i + 1 ))" ) - fi - done +readonly -f os::cmd::expect_success - # for the proper flag format for 'cut', we join the list delimiting with commas - columns_to_keep="$( IFS=','; echo "${columns_to_keep[*]}" )" +# expect_failure runs the cmd and expects a non-zero exit code +function os::cmd::expect_failure() { + if [[ $# -ne 1 ]]; then echo "os::cmd::expect_failure expects only one argument, got $#"; return 1; fi + local cmd=$1 - cut --delimiter=';' -f"${columns_to_keep}" "${datafile}" > "${datafile}.tmp" - sed -i '1s/^/# /' "${datafile}.tmp" - mv "${datafile}.tmp" "${datafile}" + os::cmd::internal::expect_exit_code_run_grep "${cmd}" "os::cmd::internal::failure_func" } -readonly -f os::log::system::internal::prune_datafile - -# os::log::system::internal::plot uses gnuplot to make a plot of some data across time points. This function is intended to be used -# on the output of a 'sar -f' read of a sar binary file. Plots will be made of all columns and stacked on each other with one x axis. -# This function needs the non-data columns of the file to be prefixed with comments. -# -# Globals: -# - LOG_DIR -# Arguments: -# - 1: data file -# Returns: -# None -function os::log::system::internal::plot() { - local datafile=$1 - local plotname - plotname="$(basename "${datafile}" .txt)" - - # we are expecting the output of a 'sadf -d' read, so the headers will be on the first line of the file - local headers - headers=( $( head -n 1 "${datafile}" | sed 's/^# //g' | tr ';' ' ' ) ) - - local records - local width - records="$(( $( wc -l < "${datafile}" ) - 1 ))" # one of these lines will be the header comment - if [[ "${records}" -gt 90 ]]; then - width="$(echo "8.5 + ${records}*0.025" | bc )" - else - width="8.5" - fi - - local gnuplot_directive=( "set terminal pdf size ${width}in,$(( 2 * (${#headers[@]} - 1) ))in" \ - "set output \"${LOG_DIR}/${plotname}.pdf\"" \ - "set datafile separator \";\"" \ - "set xdata time" \ - "set timefmt '%Y-%m-%d %H:%M:%S UTC'" \ - "set tmargin 1" \ - "set bmargin 1" \ - "set lmargin 20" \ - "set rmargin 20" \ - "set multiplot layout ${#headers[@]},1 title \"\n${plotname}\n\"" \ - "unset title" ) - - local i - for (( i = 1; i < "${#headers[@]}"; i++ )); do - local header - header="${headers[$i]}" - - if (( i == ${#headers[@]} - 1 )); then - # we need x-tick labels on the bottom plot - gnuplot_directive+=( "set xtics format '%H:%M:%S' rotate by -90" ) - else - gnuplot_directive+=( "set format x ''" ) - fi - - gnuplot_directive+=( "plot \"${datafile}\" using 1:$(( i + 1 )) title \"${header}\" with lines" ) - done - - # concatenate the array with newlines to get the final directive to send to gnuplot - gnuplot_directive="$( IFS=$'\n'; echo "${gnuplot_directive[*]}" )" +readonly -f os::cmd::expect_failure - { - printf '$ gnuplot <<< %s\n' "${gnuplot_directive}" - gnuplot <<< "${gnuplot_directive}" 2>&1 - printf '\n\n' - } >> "${LOG_DIR}/gnuplot.log" +# expect_success_and_text runs the cmd and expects an exit code of 0 +# as well as running a grep test to find the given string in the output +function os::cmd::expect_success_and_text() { + if [[ $# -ne 2 ]]; then echo "os::cmd::expect_success_and_text expects two arguments, got $#"; return 1; fi + local cmd=$1 + local expected_text=$2 - os::log::debug "Stacked plot for log subset \"${plotname}\" written to ${LOG_DIR}/${plotname}.pdf" + os::cmd::internal::expect_exit_code_run_grep "${cmd}" "os::cmd::internal::success_func" "${expected_text}" } -readonly -f os::log::system::internal::plot - -# os::log::system::start installs the system logger and begins logging -# -# Globals: -# - LOG_DIR -# Arguments: -# None -# Returns: -# - export LOGGER_PID -# - export SAR_LOGFILE -function os::log::system::start() { - if ! which sar >/dev/null 2>&1; then - os::log::debug "System logger could not be started, 'sar' binary not found in this environment." - return 0 - fi - - readonly SAR_LOGFILE="${LOG_DIR}/sar.log" - export SAR_LOGFILE +readonly -f os::cmd::expect_success_and_text - os::log::system::internal::run "${SAR_LOGFILE}" "${LOG_DIR}/sar_stderr.log" +# expect_failure_and_text runs the cmd and expects a non-zero exit code +# as well as running a grep test to find the given string in the output +function os::cmd::expect_failure_and_text() { + if [[ $# -ne 2 ]]; then echo "os::cmd::expect_failure_and_text expects two arguments, got $#"; return 1; fi + local cmd=$1 + local expected_text=$2 - os::log::system::install_cleanup + os::cmd::internal::expect_exit_code_run_grep "${cmd}" "os::cmd::internal::failure_func" "${expected_text}" } -readonly -f os::log::system::start - -# os::log::system::internal::run runs the system logger in the background. -# 'sar' is configured to run once a second for 24 hours, so the cleanup trap should be installed to ensure that -# the process is killed once the parent script is finished. -# -# Globals: -# None -# Arguments: -# - 1: file to log binary outut to -# - 2: file to log stderr of the logger to -# Returns: -# None -function os::log::system::internal::run() { - local binary_logfile=$1 - local stderr_logfile=$2 - - sar -A -o "${binary_logfile}" 1 86400 1>/dev/null 2>"${stderr_logfile}" & +readonly -f os::cmd::expect_failure_and_text - LOGGER_PID=$! - readonly LOGGER_PID - export LOGGER_PID -} -readonly -f os::log::system::internal::run -`) +# expect_success_and_not_text runs the cmd and expects an exit code of 0 +# as well as running a grep test to ensure the given string is not in the output +function os::cmd::expect_success_and_not_text() { + if [[ $# -ne 2 ]]; then echo "os::cmd::expect_success_and_not_text expects two arguments, got $#"; return 1; fi + local cmd=$1 + local expected_text=$2 -func testExtendedTestdataCmdHackLibLogSystemShBytes() ([]byte, error) { - return _testExtendedTestdataCmdHackLibLogSystemSh, nil + os::cmd::internal::expect_exit_code_run_grep "${cmd}" "os::cmd::internal::success_func" "${expected_text}" "os::cmd::internal::failure_func" } +readonly -f os::cmd::expect_success_and_not_text -func testExtendedTestdataCmdHackLibLogSystemSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdHackLibLogSystemShBytes() - if err != nil { - return nil, err - } +# expect_failure_and_not_text runs the cmd and expects a non-zero exit code +# as well as running a grep test to ensure the given string is not in the output +function os::cmd::expect_failure_and_not_text() { + if [[ $# -ne 2 ]]; then echo "os::cmd::expect_failure_and_not_text expects two arguments, got $#"; return 1; fi + local cmd=$1 + local expected_text=$2 - info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/log/system.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil + os::cmd::internal::expect_exit_code_run_grep "${cmd}" "os::cmd::internal::failure_func" "${expected_text}" "os::cmd::internal::failure_func" } +readonly -f os::cmd::expect_failure_and_not_text -var _testExtendedTestdataCmdHackLibTestJunitSh = []byte(`#!/usr/bin/env bash -# This utility file contains functions that format test output to be parsed into jUnit XML - -# os::test::junit::declare_suite_start prints a message declaring the start of a test suite -# Any number of suites can be in flight at any time, so there is no failure condition for this -# script based on the number of suites in flight. -# -# Globals: -# - JUNIT_REPORT_OUTPUT -# - NUM_OS_JUNIT_SUITES_IN_FLIGHT -# Arguments: -# - 1: the suite name that is starting -# Returns: -# - increment NUM_OS_JUNIT_SUITES_IN_FLIGHT -function os::test::junit::declare_suite_start() { - local suite_name=$1 - local num_suites=${NUM_OS_JUNIT_SUITES_IN_FLIGHT:-0} +# expect_code runs the cmd and expects a given exit code +function os::cmd::expect_code() { + if [[ $# -ne 2 ]]; then echo "os::cmd::expect_code expects two arguments, got $#"; return 1; fi + local cmd=$1 + local expected_cmd_code=$2 - echo "=== BEGIN TEST SUITE github.com/openshift/origin/test/${suite_name} ===" >> "${JUNIT_REPORT_OUTPUT:-/dev/null}" - NUM_OS_JUNIT_SUITES_IN_FLIGHT=$(( ${num_suites} + 1 )) - export NUM_OS_JUNIT_SUITES_IN_FLIGHT + os::cmd::internal::expect_exit_code_run_grep "${cmd}" "os::cmd::internal::specific_code_func ${expected_cmd_code}" } -readonly -f os::test::junit::declare_suite_start +readonly -f os::cmd::expect_code -# os::test::junit::declare_suite_end prints a message declaring the end of a test suite -# If there aren't any suites in flight, this function will fail. -# -# Globals: -# - JUNIT_REPORT_OUTPUT -# - NUM_OS_JUNIT_SUITES_IN_FLIGHT -# Arguments: -# - 1: the suite name that is starting -# Returns: -# - export/decrement NUM_OS_JUNIT_SUITES_IN_FLIGHT -function os::test::junit::declare_suite_end() { - local num_suites=${NUM_OS_JUNIT_SUITES_IN_FLIGHT:-0} - if [[ "${num_suites}" -lt "1" ]]; then - # we can't end a suite if none have been started yet - echo "[ERROR] jUnit suite marker could not be placed, expected suites in flight, got ${num_suites}" - return 1 - fi +# expect_code_and_text runs the cmd and expects the given exit code +# as well as running a grep test to find the given string in the output +function os::cmd::expect_code_and_text() { + if [[ $# -ne 3 ]]; then echo "os::cmd::expect_code_and_text expects three arguments, got $#"; return 1; fi + local cmd=$1 + local expected_cmd_code=$2 + local expected_text=$3 - echo "=== END TEST SUITE ===" >> "${JUNIT_REPORT_OUTPUT:-/dev/null}" - NUM_OS_JUNIT_SUITES_IN_FLIGHT=$(( ${num_suites} - 1 )) - export NUM_OS_JUNIT_SUITES_IN_FLIGHT + os::cmd::internal::expect_exit_code_run_grep "${cmd}" "os::cmd::internal::specific_code_func ${expected_cmd_code}" "${expected_text}" } -readonly -f os::test::junit::declare_suite_end - -# os::test::junit::declare_test_start prints a message declaring the start of a test case -# If there is already a test marked as being in flight, this function will fail. -# -# Globals: -# - JUNIT_REPORT_OUTPUT -# - NUM_OS_JUNIT_TESTS_IN_FLIGHT -# Arguments: -# None -# Returns: -# - increment NUM_OS_JUNIT_TESTS_IN_FLIGHT -function os::test::junit::declare_test_start() { - local num_tests=${NUM_OS_JUNIT_TESTS_IN_FLIGHT:-0} - if [[ "${num_tests}" -ne "0" ]]; then - # someone's declaring the starting of a test when a test is already in flight - echo "[ERROR] jUnit test marker could not be placed, expected no tests in flight, got ${num_tests}" - return 1 - fi +readonly -f os::cmd::expect_code_and_text - local num_suites=${NUM_OS_JUNIT_SUITES_IN_FLIGHT:-0} - if [[ "${num_suites}" -lt "1" ]]; then - # we can't end a test if no suites are in flight - echo "[ERROR] jUnit test marker could not be placed, expected suites in flight, got ${num_suites}" - return 1 - fi +# expect_code_and_not_text runs the cmd and expects the given exit code +# as well as running a grep test to ensure the given string is not in the output +function os::cmd::expect_code_and_not_text() { + if [[ $# -ne 3 ]]; then echo "os::cmd::expect_code_and_not_text expects three arguments, got $#"; return 1; fi + local cmd=$1 + local expected_cmd_code=$2 + local expected_text=$3 - echo "=== BEGIN TEST CASE ===" >> "${JUNIT_REPORT_OUTPUT:-/dev/null}" - NUM_OS_JUNIT_TESTS_IN_FLIGHT=$(( ${num_tests} + 1 )) - export NUM_OS_JUNIT_TESTS_IN_FLIGHT + os::cmd::internal::expect_exit_code_run_grep "${cmd}" "os::cmd::internal::specific_code_func ${expected_cmd_code}" "${expected_text}" "os::cmd::internal::failure_func" } -readonly -f os::test::junit::declare_test_start +readonly -f os::cmd::expect_code_and_not_text -# os::test::junit::declare_test_end prints a message declaring the end of a test case -# If there is no test marked as being in flight, this function will fail. -# -# Globals: -# - JUNIT_REPORT_OUTPUT -# - NUM_OS_JUNIT_TESTS_IN_FLIGHT -# Arguments: -# None -# Returns: -# - decrement NUM_OS_JUNIT_TESTS_IN_FLIGHT -function os::test::junit::declare_test_end() { - local num_tests=${NUM_OS_JUNIT_TESTS_IN_FLIGHT:-0} - if [[ "${num_tests}" -ne "1" ]]; then - # someone's declaring the end of a test when a test is not in flight - echo "[ERROR] jUnit test marker could not be placed, expected one test in flight, got ${num_tests}" - return 1 - fi +millisecond=1 +second=$(( 1000 * millisecond )) +minute=$(( 60 * second )) + +# os::cmd::try_until_success runs the cmd in a small interval until either the command succeeds or times out +# the default time-out for os::cmd::try_until_success is 60 seconds. +# the default interval for os::cmd::try_until_success is 200ms +function os::cmd::try_until_success() { + if [[ $# -lt 1 ]]; then echo "os::cmd::try_until_success expects at least one arguments, got $#"; return 1; fi + local cmd=$1 + local duration=${2:-$minute} + local interval=${3:-0.2} - echo "=== END TEST CASE ===" >> "${JUNIT_REPORT_OUTPUT:-/dev/null}" - NUM_OS_JUNIT_TESTS_IN_FLIGHT=$(( ${num_tests} - 1 )) - export NUM_OS_JUNIT_TESTS_IN_FLIGHT + os::cmd::internal::run_until_exit_code "${cmd}" "os::cmd::internal::success_func" "${duration}" "${interval}" } -readonly -f os::test::junit::declare_test_end +readonly -f os::cmd::try_until_success -# os::test::junit::check_test_counters checks that we do not have any test suites or test cases in flight -# This function should be called at the very end of any test script using jUnit markers to make sure no error in -# marking has occurred. -# -# Globals: -# - NUM_OS_JUNIT_SUITES_IN_FLIGHT -# - NUM_OS_JUNIT_TESTS_IN_FLIGHT -# Arguments: -# None -# Returns: -# None -function os::test::junit::check_test_counters() { - if [[ "${NUM_OS_JUNIT_SUITES_IN_FLIGHT-}" -ne "0" ]]; then - echo "[ERROR] Expected no test suites to be marked as in-flight at the end of testing, got ${NUM_OS_JUNIT_SUITES_IN_FLIGHT-}" - return 1 - elif [[ "${NUM_OS_JUNIT_TESTS_IN_FLIGHT-}" -ne "0" ]]; then - echo "[ERROR] Expected no test cases to be marked as in-flight at the end of testing, got ${NUM_OS_JUNIT_TESTS_IN_FLIGHT-}" - return 1 - fi +# os::cmd::try_until_failure runs the cmd until either the command fails or times out +# the default time-out for os::cmd::try_until_failure is 60 seconds. +function os::cmd::try_until_failure() { + if [[ $# -lt 1 ]]; then echo "os::cmd::try_until_failure expects at least one argument, got $#"; return 1; fi + local cmd=$1 + local duration=${2:-$minute} + local interval=${3:-0.2} + + os::cmd::internal::run_until_exit_code "${cmd}" "os::cmd::internal::failure_func" "${duration}" "${interval}" } -readonly -f os::test::junit::check_test_counters +readonly -f os::cmd::try_until_failure -# os::test::junit::reconcile_output appends the necessary suite and test end statements to the jUnit output file -# in order to ensure that the file is in a consistent state to allow for parsing -# -# Globals: -# - NUM_OS_JUNIT_SUITES_IN_FLIGHT -# - NUM_OS_JUNIT_TESTS_IN_FLIGHT -# Arguments: -# None -# Returns: -# None -function os::test::junit::reconcile_output() { - if [[ "${NUM_OS_JUNIT_TESTS_IN_FLIGHT:-0}" = "1" ]]; then - os::test::junit::declare_test_end - fi +# os::cmd::try_until_text runs the cmd until either the command outputs the desired text or times out +# the default time-out for os::cmd::try_until_text is 60 seconds. +function os::cmd::try_until_text() { + if [[ $# -lt 2 ]]; then echo "os::cmd::try_until_text expects at least two arguments, got $#"; return 1; fi + local cmd=$1 + local text=$2 + local duration=${3:-$minute} + local interval=${4:-0.2} - for (( i = 0; i < ${NUM_OS_JUNIT_SUITES_IN_FLIGHT:-0}; i++ )); do - os::test::junit::declare_suite_end - done + os::cmd::internal::run_until_text "${cmd}" "${text}" "os::cmd::internal::success_func" "${duration}" "${interval}" } -readonly -f os::test::junit::reconcile_output +readonly -f os::cmd::try_until_text -# os::test::junit::generate_report determines which type of report is to -# be generated and does so from the raw output of the tests. -# -# Globals: -# - JUNIT_REPORT_OUTPUT -# - ARTIFACT_DIR -# Arguments: -# None -# Returns: -# None -function os::test::junit::generate_report() { - if [[ -z "${JUNIT_REPORT_OUTPUT:-}" || - -n "${JUNIT_REPORT_OUTPUT:-}" && ! -s "${JUNIT_REPORT_OUTPUT:-}" ]]; then - # we can't generate a report - return 0 - fi +# os::cmd::try_until_not_text runs the cmd until either the command doesnot output the text or times out +# the default time-out for os::cmd::try_until_not_text is 60 seconds. +function os::cmd::try_until_not_text() { + if [[ $# -lt 2 ]]; then echo "os::cmd::try_until_not_text expects at least two arguments, got $#"; return 1; fi + local cmd=$1 + local text=$2 + local duration=${3:-$minute} + local interval=${4:-0.2} - if grep -q "=== END TEST CASE ===" "${JUNIT_REPORT_OUTPUT}"; then - os::test::junit::reconcile_output - os::test::junit::check_test_counters - os::test::junit::internal::generate_report "oscmd" - fi + os::cmd::internal::run_until_text "${cmd}" "${text}" "os::cmd::internal::failure_func" "${duration}" "${interval}" } +readonly -f os::cmd::try_until_text -# os::test::junit::internal::generate_report generats an XML jUnit -# report for either ` + "`" + `os::cmd` + "`" + ` or ` + "`" + `go test` + "`" + `, based on the passed -# argument. If the ` + "`" + `junitreport` + "`" + ` binary is not present, it will be built. +# Functions in the os::cmd::internal namespace are discouraged from being used outside of os::cmd + +# In order to harvest stderr and stdout at the same time into different buckets, we need to stick them into files +# in an intermediate step +os_cmd_internal_tmpdir="${TMPDIR:-"/tmp"}/cmd" +os_cmd_internal_tmpout="${os_cmd_internal_tmpdir}/tmp_stdout.log" +os_cmd_internal_tmperr="${os_cmd_internal_tmpdir}/tmp_stderr.log" + +# os::cmd::internal::expect_exit_code_run_grep runs the provided test command and expects a specific +# exit code from that command as well as the success of a specified ` + "`" + `grep` + "`" + ` invocation. Output from the +# command to be tested is suppressed unless either ` + "`" + `VERBOSE=1` + "`" + ` or the test fails. This function bypasses +# any error exiting settings or traps set by upstream callers by masking the return code of the command +# with the return code of setting the result variable on failure. # # Globals: # - JUNIT_REPORT_OUTPUT -# - ARTIFACT_DIR +# - VERBOSE # Arguments: -# - 1: specify which type of tests command output should junitreport read +# - 1: the command to run +# - 2: command evaluation assertion to use +# - 3: text to test for +# - 4: text assertion to use # Returns: -# export JUNIT_REPORT_NUM_FAILED -function os::test::junit::internal::generate_report() { - local report_type="$1" - os::util::ensure::built_binary_exists 'junitreport' +# - 0: if all assertions met +# - 1: if any assertions fail +function os::cmd::internal::expect_exit_code_run_grep() { + local cmd=$1 + # default expected cmd code to 0 for success + local cmd_eval_func=${2:-os::cmd::internal::success_func} + # default to nothing + local grep_args=${3:-} + # default expected test code to 0 for success + local test_eval_func=${4:-os::cmd::internal::success_func} - local report_file - report_file="$( mktemp "${ARTIFACT_DIR}/${report_type}_report_XXXXX" ).xml" - os::log::info "jUnit XML report placed at $( os::util::repository_relative_path ${report_file} )" - junitreport --type "${report_type}" \ - --suites nested \ - --roots github.com/openshift/origin \ - --output "${report_file}" \ - <"${JUNIT_REPORT_OUTPUT}" + local -a junit_log - local summary - summary=$( junitreport summarize <"${report_file}" ) + os::cmd::internal::init_tempdir + os::test::junit::declare_test_start - JUNIT_REPORT_NUM_FAILED="$( grep -oE "[0-9]+ failed" <<<"${summary}" )" - export JUNIT_REPORT_NUM_FAILED + local name=$(os::cmd::internal::describe_call "${cmd}" "${cmd_eval_func}" "${grep_args}" "${test_eval_func}") + local preamble="Running ${name}..." + echo "${preamble}" + # for ease of parsing, we want the entire declaration on one line, so we replace '\n' with ';' + junit_log+=( "${name//$'\n'/;}" ) - echo "${summary}" -}`) + local start_time=$(os::cmd::internal::seconds_since_epoch) -func testExtendedTestdataCmdHackLibTestJunitShBytes() ([]byte, error) { - return _testExtendedTestdataCmdHackLibTestJunitSh, nil -} + local cmd_result=$( os::cmd::internal::run_collecting_output "${cmd}"; echo $? ) + local cmd_succeeded=$( ${cmd_eval_func} "${cmd_result}"; echo $? ) -func testExtendedTestdataCmdHackLibTestJunitSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdHackLibTestJunitShBytes() - if err != nil { - return nil, err - } + local test_result=0 + if [[ -n "${grep_args}" ]]; then + test_result=$( os::cmd::internal::run_collecting_output 'grep -Eq "${grep_args}" <(os::cmd::internal::get_results)'; echo $? ) + fi + local test_succeeded=$( ${test_eval_func} "${test_result}"; echo $? ) - info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/test/junit.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} + local end_time=$(os::cmd::internal::seconds_since_epoch) + local time_elapsed=$(echo $(( ${end_time} - ${start_time} )) | xargs printf '%5.3f') # in decimal seconds, we need leading zeroes for parsing later -var _testExtendedTestdataCmdHackLibUtilEnvironmentSh = []byte(`#!/usr/bin/env bash + # clear the preamble so we can print out the success or error message + os::text::clear_string "${preamble}" -# This script holds library functions for setting up the shell environment for OpenShift scripts + local return_code + if (( cmd_succeeded && test_succeeded )); then + os::text::print_green "SUCCESS after ${time_elapsed}s: ${name}" + junit_log+=( "SUCCESS after ${time_elapsed}s: ${name//$'\n'/;}" ) -# os::util::environment::use_sudo updates $USE_SUDO to be 'true', so that later scripts choosing between -# execution using 'sudo' and execution without it chose to use 'sudo' -# -# Globals: -# None -# Arguments: -# None -# Returns: -# - export USE_SUDO -function os::util::environment::use_sudo() { - USE_SUDO=true - export USE_SUDO -} -readonly -f os::util::environment::use_sudo + if [[ -n ${VERBOSE-} ]]; then + os::cmd::internal::print_results + fi + return_code=0 + else + local cause=$(os::cmd::internal::assemble_causes "${cmd_succeeded}" "${test_succeeded}") -# os::util::environment::setup_time_vars sets up environment variables that describe durations of time -# These variables can be used to specify times for other utility functions -# -# Globals: -# None -# Arguments: -# None -# Returns: -# - export TIME_MS -# - export TIME_SEC -# - export TIME_MIN -function os::util::environment::setup_time_vars() { - TIME_MS=1 - export TIME_MS - TIME_SEC="$(( 1000 * ${TIME_MS} ))" - export TIME_SEC - TIME_MIN="$(( 60 * ${TIME_SEC} ))" - export TIME_MIN -} -readonly -f os::util::environment::setup_time_vars + os::text::print_red_bold "FAILURE after ${time_elapsed}s: ${name}: ${cause}" + junit_log+=( "FAILURE after ${time_elapsed}s: ${name//$'\n'/;}: ${cause}" ) -# os::util::environment::setup_all_server_vars sets up all environment variables necessary to configure and start an OpenShift server -# -# Globals: -# - OS_ROOT -# - PATH -# - TMPDIR -# - LOG_DIR -# - ARTIFACT_DIR -# - KUBELET_SCHEME -# - KUBELET_BIND_HOST -# - KUBELET_HOST -# - KUBELET_PORT -# - BASETMPDIR -# - ETCD_PORT -# - ETCD_PEER_PORT -# - API_BIND_HOST -# - API_HOST -# - API_PORT -# - API_SCHEME -# - PUBLIC_MASTER_HOST -# - USE_IMAGES -# Arguments: -# - 1: the path under the root temporary directory for OpenShift where these subdirectories should be made -# Returns: -# - export PATH -# - export BASETMPDIR -# - export LOG_DIR -# - export VOLUME_DIR -# - export ARTIFACT_DIR -# - export FAKE_HOME_DIR -# - export KUBELET_SCHEME -# - export KUBELET_BIND_HOST -# - export KUBELET_HOST -# - export KUBELET_PORT -# - export ETCD_PORT -# - export ETCD_PEER_PORT -# - export ETCD_DATA_DIR -# - export API_BIND_HOST -# - export API_HOST -# - export API_PORT -# - export API_SCHEME -# - export SERVER_CONFIG_DIR -# - export MASTER_CONFIG_DIR -# - export NODE_CONFIG_DIR -# - export USE_IMAGES -# - export TAG -function os::util::environment::setup_all_server_vars() { - os::util::environment::setup_kubelet_vars - os::util::environment::setup_etcd_vars - os::util::environment::setup_server_vars - os::util::environment::setup_images_vars -} -readonly -f os::util::environment::setup_all_server_vars + os::text::print_red "$(os::cmd::internal::print_results)" + return_code=1 + fi -# os::util::environment::update_path_var updates $PATH so that OpenShift binaries are available -# -# Globals: -# - OS_ROOT -# - PATH -# Arguments: -# None -# Returns: -# - export PATH -function os::util::environment::update_path_var() { - local prefix - if os::util::find::system_binary 'go' >/dev/null 2>&1; then - prefix+="${OS_OUTPUT_BINPATH}/$(os::build::host_platform):" - fi - if [[ -n "${GOPATH:-}" ]]; then - prefix+="${GOPATH}/bin:" - fi + junit_log+=( "$(os::cmd::internal::print_results)" ) + # append inside of a subshell so that IFS doesn't get propagated out + ( IFS=$'\n'; echo "${junit_log[*]}" >> "${JUNIT_REPORT_OUTPUT:-/dev/null}" ) + os::test::junit::declare_test_end + return "${return_code}" +} +readonly -f os::cmd::internal::expect_exit_code_run_grep - PATH="${prefix:-}${PATH}" - export PATH +# os::cmd::internal::init_tempdir initializes the temporary directory +function os::cmd::internal::init_tempdir() { + mkdir -p "${os_cmd_internal_tmpdir}" + rm -f "${os_cmd_internal_tmpdir}"/tmp_std{out,err}.log } -readonly -f os::util::environment::update_path_var +readonly -f os::cmd::internal::init_tempdir -# os::util::environment::setup_tmpdir_vars sets up temporary directory path variables -# -# Globals: -# - TMPDIR -# Arguments: -# - 1: the path under the root temporary directory for OpenShift where these subdirectories should be made -# Returns: -# - export BASETMPDIR -# - export BASEOUTDIR -# - export LOG_DIR -# - export VOLUME_DIR -# - export ARTIFACT_DIR -# - export FAKE_HOME_DIR -# - export OS_TMP_ENV_SET -function os::util::environment::setup_tmpdir_vars() { - local sub_dir=$1 +# os::cmd::internal::describe_call determines the file:line of the latest function call made +# from outside of this file in the call stack, and the name of the function being called from +# that line, returning a string describing the call +function os::cmd::internal::describe_call() { + local cmd=$1 + local cmd_eval_func=$2 + local grep_args=${3:-} + local test_eval_func=${4:-} - BASETMPDIR="${TMPDIR:-/tmp}/openshift/${sub_dir}" - export BASETMPDIR - VOLUME_DIR="${BASETMPDIR}/volumes" - export VOLUME_DIR + local caller_id=$(os::cmd::internal::determine_caller) + local full_name="${caller_id}: executing '${cmd}'" - BASEOUTDIR="${OS_OUTPUT_SCRIPTPATH}/${sub_dir}" - export BASEOUTDIR - LOG_DIR="${ARTIFACT_DIR:-${BASEOUTDIR}}/logs" - export LOG_DIR - ARTIFACT_DIR="${ARTIFACT_DIR:-${BASEOUTDIR}/artifacts}" - export ARTIFACT_DIR - FAKE_HOME_DIR="${BASEOUTDIR}/openshift.local.home" - export FAKE_HOME_DIR + local cmd_expectation=$(os::cmd::internal::describe_expectation "${cmd_eval_func}") + local full_name="${full_name} expecting ${cmd_expectation}" - mkdir -p "${LOG_DIR}" "${VOLUME_DIR}" "${ARTIFACT_DIR}" "${FAKE_HOME_DIR}" + if [[ -n "${grep_args}" ]]; then + local text_expecting= + case "${test_eval_func}" in + "os::cmd::internal::success_func") + text_expecting="text" ;; + "os::cmd::internal::failure_func") + text_expecting="not text" ;; + esac + full_name="${full_name} and ${text_expecting} '${grep_args}'" + fi - export OS_TMP_ENV_SET="${sub_dir}" + echo "${full_name}" } -readonly -f os::util::environment::setup_tmpdir_vars +readonly -f os::cmd::internal::describe_call -# os::util::environment::setup_kubelet_vars sets up environment variables necessary for interacting with the kubelet -# -# Globals: -# - KUBELET_SCHEME -# - KUBELET_BIND_HOST -# - KUBELET_HOST -# - KUBELET_PORT -# Arguments: -# None -# Returns: -# - export KUBELET_SCHEME -# - export KUBELET_BIND_HOST -# - export KUBELET_HOST -# - export KUBELET_PORT -function os::util::environment::setup_kubelet_vars() { - KUBELET_SCHEME="${KUBELET_SCHEME:-https}" - export KUBELET_SCHEME - KUBELET_BIND_HOST="${KUBELET_BIND_HOST:-127.0.0.1}" - export KUBELET_BIND_HOST - KUBELET_HOST="${KUBELET_HOST:-${KUBELET_BIND_HOST}}" - export KUBELET_HOST - KUBELET_PORT="${KUBELET_PORT:-10250}" - export KUBELET_PORT -} -readonly -f os::util::environment::setup_kubelet_vars +# os::cmd::internal::determine_caller determines the file relative to the OpenShift Origin root directory +# and line number of the function call to the outer os::cmd wrapper function +function os::cmd::internal::determine_caller() { + local call_depth= + local len_sources="${#BASH_SOURCE[@]}" + for (( i=0; i<${len_sources}; i++ )); do + if [ ! $(echo "${BASH_SOURCE[i]}" | grep "hack/lib/cmd\.sh$") ]; then + call_depth=i + break + fi + done -# os::util::environment::setup_etcd_vars sets up environment variables necessary for interacting with etcd -# -# Globals: -# - BASETMPDIR -# - ETCD_HOST -# - ETCD_PORT -# - ETCD_PEER_PORT -# Arguments: -# None -# Returns: -# - export ETCD_HOST -# - export ETCD_PORT -# - export ETCD_PEER_PORT -# - export ETCD_DATA_DIR -function os::util::environment::setup_etcd_vars() { - ETCD_HOST="${ETCD_HOST:-127.0.0.1}" - export ETCD_HOST - ETCD_PORT="${ETCD_PORT:-4001}" - export ETCD_PORT - ETCD_PEER_PORT="${ETCD_PEER_PORT:-7001}" - export ETCD_PEER_PORT + local caller_file="${BASH_SOURCE[${call_depth}]}" + caller_file="$( os::util::repository_relative_path "${caller_file}" )" + local caller_line="${BASH_LINENO[${call_depth}-1]}" + echo "${caller_file}:${caller_line}" +} +readonly -f os::cmd::internal::determine_caller - ETCD_DATA_DIR="${BASETMPDIR}/etcd" - export ETCD_DATA_DIR +# os::cmd::internal::describe_expectation describes a command return code evaluation function +function os::cmd::internal::describe_expectation() { + local func=$1 + case "${func}" in + "os::cmd::internal::success_func") + echo "success" ;; + "os::cmd::internal::failure_func") + echo "failure" ;; + "os::cmd::internal::specific_code_func"*[0-9]) + local code=$(echo "${func}" | grep -Eo "[0-9]+$") + echo "exit code ${code}" ;; + "") + echo "any result" + esac +} +readonly -f os::cmd::internal::describe_expectation - mkdir -p "${ETCD_DATA_DIR}" +# os::cmd::internal::seconds_since_epoch returns the number of seconds elapsed since the epoch +# with milli-second precision +function os::cmd::internal::seconds_since_epoch() { + local ns=$(date +%s%N) + # if ` + "`" + `date` + "`" + ` doesn't support nanoseconds, return second precision + if [[ "$ns" == *N ]]; then + date "+%s.000" + return + fi + echo $(( ${ns}/1000000000 )) } -readonly -f os::util::environment::setup_etcd_vars +readonly -f os::cmd::internal::seconds_since_epoch -# os::util::environment::setup_server_vars sets up environment variables necessary for interacting with the server -# -# Globals: -# - BASETMPDIR -# - KUBELET_HOST -# - API_BIND_HOST -# - API_HOST -# - API_PORT -# - API_SCHEME -# - PUBLIC_MASTER_HOST -# Arguments: -# None -# Returns: -# - export API_BIND_HOST -# - export API_HOST -# - export API_PORT -# - export API_SCHEME -# - export SERVER_CONFIG_DIR -# - export MASTER_CONFIG_DIR -# - export NODE_CONFIG_DIR -function os::util::environment::setup_server_vars() { - # turn on cache mutation detector every time we start a server - KUBE_CACHE_MUTATION_DETECTOR="${KUBE_CACHE_MUTATION_DETECTOR:-true}" - export KUBE_CACHE_MUTATION_DETECTOR +# os::cmd::internal::run_collecting_output runs the command given, piping stdout and stderr into +# the given files, and returning the exit code of the command +function os::cmd::internal::run_collecting_output() { + local cmd=$1 - API_BIND_HOST="${API_BIND_HOST:-127.0.0.1}" - export API_BIND_HOST - API_HOST="${API_HOST:-${API_BIND_HOST}}" - export API_HOST - API_PORT="${API_PORT:-8443}" - export API_PORT - API_SCHEME="${API_SCHEME:-https}" - export API_SCHEME + local result= + $( eval "${cmd}" 1>>"${os_cmd_internal_tmpout}" 2>>"${os_cmd_internal_tmperr}" ) || result=$? + local result=${result:-0} # if we haven't set result yet, the command succeeded + + return "${result}" +} +readonly -f os::cmd::internal::run_collecting_output - MASTER_ADDR="${API_SCHEME}://${API_HOST}:${API_PORT}" - export MASTER_ADDR - PUBLIC_MASTER_HOST="${PUBLIC_MASTER_HOST:-${API_HOST}}" - export PUBLIC_MASTER_HOST +# os::cmd::internal::success_func determines if the input exit code denotes success +# this function returns 0 for false and 1 for true to be compatible with arithmetic tests +function os::cmd::internal::success_func() { + local exit_code=$1 - SERVER_CONFIG_DIR="${BASETMPDIR}/openshift.local.config" - export SERVER_CONFIG_DIR - MASTER_CONFIG_DIR="${SERVER_CONFIG_DIR}/master" - export MASTER_CONFIG_DIR - NODE_CONFIG_DIR="${SERVER_CONFIG_DIR}/node-${KUBELET_HOST}" - export NODE_CONFIG_DIR + # use a negated test to get output correct for (( )) + [[ "${exit_code}" -ne "0" ]] + return $? +} +readonly -f os::cmd::internal::success_func - ETCD_CLIENT_CERT="${MASTER_CONFIG_DIR}/master.etcd-client.crt" - export ETCD_CLIENT_CERT - ETCD_CLIENT_KEY="${MASTER_CONFIG_DIR}/master.etcd-client.key" - export ETCD_CLIENT_KEY - ETCD_CA_BUNDLE="${MASTER_CONFIG_DIR}/ca-bundle.crt" - export ETCD_CA_BUNDLE +# os::cmd::internal::failure_func determines if the input exit code denotes failure +# this function returns 0 for false and 1 for true to be compatible with arithmetic tests +function os::cmd::internal::failure_func() { + local exit_code=$1 - mkdir -p "${SERVER_CONFIG_DIR}" "${MASTER_CONFIG_DIR}" "${NODE_CONFIG_DIR}" + # use a negated test to get output correct for (( )) + [[ "${exit_code}" -eq "0" ]] + return $? } -readonly -f os::util::environment::setup_server_vars +readonly -f os::cmd::internal::failure_func -# os::util::environment::setup_images_vars sets up environment variables necessary for interacting with release images -# -# Globals: -# - OS_ROOT -# - USE_IMAGES -# Arguments: -# None -# Returns: -# - export USE_IMAGES -# - export TAG -# - export MAX_IMAGES_BULK_IMPORTED_PER_REPOSITORY -function os::util::environment::setup_images_vars() { - # Use either the latest release built images, or latest. - IMAGE_PREFIX="${OS_IMAGE_PREFIX:-"openshift/origin"}" - if [[ -z "${USE_IMAGES-}" ]]; then - TAG='latest' - export TAG - USE_IMAGES="${IMAGE_PREFIX}-\${component}:latest" - export USE_IMAGES +# os::cmd::internal::specific_code_func determines if the input exit code matches the given code +# this function returns 0 for false and 1 for true to be compatible with arithmetic tests +function os::cmd::internal::specific_code_func() { + local expected_code=$1 + local exit_code=$2 - if [[ -e "${OS_ROOT}/_output/local/releases/.commit" ]]; then - TAG="$(cat "${OS_ROOT}/_output/local/releases/.commit")" - export TAG - USE_IMAGES="${IMAGE_PREFIX}-\${component}:${TAG}" - export USE_IMAGES - fi - fi - export MAX_IMAGES_BULK_IMPORTED_PER_REPOSITORY="${MAX_IMAGES_BULK_IMPORTED_PER_REPOSITORY:-3}" + # use a negated test to get output correct for (( )) + [[ "${exit_code}" -ne "${expected_code}" ]] + return $? } -readonly -f os::util::environment::setup_images_vars -`) +readonly -f os::cmd::internal::specific_code_func -func testExtendedTestdataCmdHackLibUtilEnvironmentShBytes() ([]byte, error) { - return _testExtendedTestdataCmdHackLibUtilEnvironmentSh, nil +# os::cmd::internal::get_results prints the stderr and stdout files +function os::cmd::internal::get_results() { + cat "${os_cmd_internal_tmpout}" "${os_cmd_internal_tmperr}" } +readonly -f os::cmd::internal::get_results -func testExtendedTestdataCmdHackLibUtilEnvironmentSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdHackLibUtilEnvironmentShBytes() - if err != nil { - return nil, err - } +# os::cmd::internal::get_last_results prints the stderr and stdout from the last attempt +function os::cmd::internal::get_last_results() { + cat "${os_cmd_internal_tmpout}" | awk 'BEGIN { RS = "\x1e" } END { print $0 }' + cat "${os_cmd_internal_tmperr}" | awk 'BEGIN { RS = "\x1e" } END { print $0 }' +} +readonly -f os::cmd::internal::get_last_results - info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/util/environment.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil +# os::cmd::internal::mark_attempt marks the end of an attempt in the stdout and stderr log files +# this is used to make the try_until_* output more concise +function os::cmd::internal::mark_attempt() { + echo -e '\x1e' >> "${os_cmd_internal_tmpout}" + echo -e '\x1e' >> "${os_cmd_internal_tmperr}" } +readonly -f os::cmd::internal::mark_attempt -var _testExtendedTestdataCmdHackLibUtilMiscSh = []byte(`#!/usr/bin/env bash -# -# This library holds miscellaneous utility functions. If there begin to be groups of functions in this -# file that share intent or are thematically similar, they should be split into their own files. +# os::cmd::internal::compress_output compresses an output file into timeline representation +function os::cmd::internal::compress_output() { + local logfile=$1 -# os::util::describe_return_code describes an exit code -# -# Globals: -# - OS_SCRIPT_START_TIME -# Arguments: -# - 1: exit code to describe -# Returns: -# None -function os::util::describe_return_code() { - local return_code=$1 - local message="$( os::util::repository_relative_path $0 ) exited with code ${return_code} " + awk -f ${OS_ROOT}/hack/lib/compress.awk $logfile +} +readonly -f os::cmd::internal::compress_output - if [[ -n "${OS_SCRIPT_START_TIME:-}" ]]; then - local end_time - end_time="$(date +%s)" - local elapsed_time - elapsed_time="$(( end_time - OS_SCRIPT_START_TIME ))" - local formatted_time - formatted_time="$( os::util::format_seconds "${elapsed_time}" )" - message+="after ${formatted_time}" +# os::cmd::internal::print_results pretty-prints the stderr and stdout files. If attempt separators +# are present, this function returns a concise view of the stdout and stderr output files using a +# timeline format, where consecutive output lines that are the same are condensed into one line +# with a counter +function os::cmd::internal::print_results() { + if [[ -s "${os_cmd_internal_tmpout}" ]]; then + echo "Standard output from the command:" + if grep -q $'\x1e' "${os_cmd_internal_tmpout}"; then + os::cmd::internal::compress_output "${os_cmd_internal_tmpout}" + else + cat "${os_cmd_internal_tmpout}"; echo + fi + else + echo "There was no output from the command." fi - if [[ "${return_code}" = "0" ]]; then - os::log::info "${message}" + if [[ -s "${os_cmd_internal_tmperr}" ]]; then + echo "Standard error from the command:" + if grep -q $'\x1e' "${os_cmd_internal_tmperr}"; then + os::cmd::internal::compress_output "${os_cmd_internal_tmperr}" + else + cat "${os_cmd_internal_tmperr}"; echo + fi else - os::log::error "${message}" + echo "There was no error output from the command." fi } -readonly -f os::util::describe_return_code +readonly -f os::cmd::internal::print_results -# os::util::install_describe_return_code installs the return code describer for the EXIT trap -# If the EXIT trap is not initialized, installing this plugin will initialize it. -# -# Globals: -# None -# Arguments: -# None -# Returns: -# - export OS_DESCRIBE_RETURN_CODE -# - export OS_SCRIPT_START_TIME -function os::util::install_describe_return_code() { - export OS_DESCRIBE_RETURN_CODE="true" - OS_SCRIPT_START_TIME="$( date +%s )"; export OS_SCRIPT_START_TIME - os::util::trap::init_exit -} -readonly -f os::util::install_describe_return_code +# os::cmd::internal::assemble_causes determines from the two input booleans which part of the test +# failed and generates a nice delimited list of failure causes +function os::cmd::internal::assemble_causes() { + local cmd_succeeded=$1 + local test_succeeded=$2 -# OS_ORIGINAL_WD is the original working directory the script sourcing this utility file was called -# from. This is an important directory as if $0 is a relative path, we cannot use the following path -# utility without knowing from where $0 is relative. -if [[ -z "${OS_ORIGINAL_WD:-}" ]]; then - # since this could be sourced in a context where the utilities are already loaded, - # we want to ensure that this is re-entrant, so we only set $OS_ORIGINAL_WD if it - # is not set already - OS_ORIGINAL_WD="$( pwd )" - readonly OS_ORIGINAL_WD - export OS_ORIGINAL_WD -fi + local causes=() + if (( ! cmd_succeeded )); then + causes+=("the command returned the wrong error code") + fi + if (( ! test_succeeded )); then + causes+=("the output content test failed") + fi -# os::util::repository_relative_path returns the relative path from the $OS_ROOT directory to the -# given file, if the file is inside of the $OS_ROOT directory. If the file is outside of $OS_ROOT, -# this function will return the absolute path to the file + local list=$(printf '; %s' "${causes[@]}") + echo "${list:2}" +} +readonly -f os::cmd::internal::assemble_causes + +# os::cmd::internal::run_until_exit_code runs the provided command until the exit code test given +# succeeds or the timeout given runs out. Output from the command to be tested is suppressed unless +# either ` + "`" + `VERBOSE=1` + "`" + ` or the test fails. This function bypasses any error exiting settings or traps +# set by upstream callers by masking the return code of the command with the return code of setting +# the result variable on failure. # # Globals: -# - OS_ROOT +# - JUNIT_REPORT_OUTPUT +# - VERBOSE # Arguments: -# - 1: the path to relativize +# - 1: the command to run +# - 2: command evaluation assertion to use +# - 3: timeout duration +# - 4: interval duration # Returns: -# None -function os::util::repository_relative_path() { - local filename=$1 - local directory; directory="$( dirname "${filename}" )" - filename="$( basename "${filename}" )" +# - 0: if all assertions met before timeout +# - 1: if timeout occurs +function os::cmd::internal::run_until_exit_code() { + local cmd=$1 + local cmd_eval_func=$2 + local duration=$3 + local interval=$4 - if [[ "${directory}" != "${OS_ROOT}"* ]]; then - pushd "${OS_ORIGINAL_WD}" >/dev/null 2>&1 - directory="$( os::util::absolute_path "${directory}" )" - popd >/dev/null 2>&1 - fi + local -a junit_log - directory="${directory##*${OS_ROOT}/}" + os::cmd::internal::init_tempdir + os::test::junit::declare_test_start - echo "${directory}/${filename}" -} -readonly -f os::util::repository_relative_path + local description=$(os::cmd::internal::describe_call "${cmd}" "${cmd_eval_func}") + local duration_seconds=` + "`" + `echo $(( $(( duration )) / 1000 )) | xargs printf '%5.3f'` + "`" + ` + local description="${description}; re-trying every ${interval}s until completion or ${duration_seconds}s" + local preamble="Running ${description}..." + echo "${preamble}" + # for ease of parsing, we want the entire declaration on one line, so we replace '\n' with ';' + junit_log+=( "${description//$'\n'/;}" ) -# os::util::format_seconds formats a duration of time in seconds to print in HHh MMm SSs -# -# Globals: -# None -# Arguments: -# - 1: time in seconds to format -# Return: -# None -function os::util::format_seconds() { - local raw_seconds=$1 + local start_time=$(os::cmd::internal::seconds_since_epoch) - local hours minutes seconds - (( hours=raw_seconds/3600 )) - (( minutes=(raw_seconds%3600)/60 )) - (( seconds=raw_seconds%60 )) + local deadline=$(( $(date +%s000) + $duration )) + local cmd_succeeded=0 + while [ $(date +%s000) -lt $deadline ]; do + local cmd_result=$( os::cmd::internal::run_collecting_output "${cmd}"; echo $? ) + cmd_succeeded=$( ${cmd_eval_func} "${cmd_result}"; echo $? ) + if (( cmd_succeeded )); then + break + fi + sleep "${interval}" + os::cmd::internal::mark_attempt + done - printf '%02dh %02dm %02ds' "${hours}" "${minutes}" "${seconds}" -} -readonly -f os::util::format_seconds + local end_time=$(os::cmd::internal::seconds_since_epoch) + local time_elapsed=$(echo $(( ${end_time} - ${start_time} )) | xargs printf '%5.3f') # in decimal seconds, we need leading zeroes for parsing later -# os::util::sed attempts to make our Bash scripts agnostic to the platform -# on which they run ` + "`" + `sed` + "`" + ` by glossing over a discrepancy in flag use in GNU. -# -# Globals: -# None -# Arguments: -# - all: arguments to pass to ` + "`" + `sed -i` + "`" + ` -# Return: -# None -function os::util::sed() { - local sudo="${USE_SUDO:+sudo}" - if LANG=C sed --help 2>&1 | grep -q "GNU sed"; then - ${sudo} sed -i'' "$@" - else - ${sudo} sed -i '' "$@" - fi -} -readonly -f os::util::sed + # clear the preamble so we can print out the success or error message + os::text::clear_string "${preamble}" -# os::util::base64decode attempts to make our Bash scripts agnostic to the platform -# on which they run ` + "`" + `base64decode` + "`" + ` by glossing over a discrepancy in flag use in GNU. -# -# Globals: -# None -# Arguments: -# - all: arguments to pass to ` + "`" + `base64decode` + "`" + ` -# Return: -# None -function os::util::base64decode() { - if [[ "$(go env GOHOSTOS)" == "darwin" ]]; then - base64 -D "$@" + local return_code + if (( cmd_succeeded )); then + os::text::print_green "SUCCESS after ${time_elapsed}s: ${description}" + junit_log+=( "SUCCESS after ${time_elapsed}s: ${description//$'\n'/;}" ) + + if [[ -n ${VERBOSE-} ]]; then + os::cmd::internal::print_results + fi + return_code=0 else - base64 -d "$@" + os::text::print_red_bold "FAILURE after ${time_elapsed}s: ${description}: the command timed out" + junit_log+=( "FAILURE after ${time_elapsed}s: ${description//$'\n'/;}: the command timed out" ) + + os::text::print_red "$(os::cmd::internal::print_results)" + return_code=1 fi + + junit_log+=( "$(os::cmd::internal::print_results)" ) + ( IFS=$'\n'; echo "${junit_log[*]}" >> "${JUNIT_REPORT_OUTPUT:-/dev/null}" ) + os::test::junit::declare_test_end + return "${return_code}" } -readonly -f os::util::base64decode +readonly -f os::cmd::internal::run_until_exit_code -# os::util::curl_etcd sends a request to the backing etcd store for the master. -# We use the administrative client cert and key for access and re-encode them -# as necessary for OSX clients. +# os::cmd::internal::run_until_text runs the provided command until the assertion function succeeds with +# the given text on the command output or the timeout given runs out. This can be used to run until the +# output does or does not contain some text. Output from the command to be tested is suppressed unless +# either ` + "`" + `VERBOSE=1` + "`" + ` or the test fails. This function bypasses any error exiting settings or traps +# set by upstream callers by masking the return code of the command with the return code of setting +# the result variable on failure. # # Globals: -# MASTER_CONFIG_DIR -# API_SCHEME -# API_HOST -# ETCD_PORT +# - JUNIT_REPORT_OUTPUT +# - VERBOSE # Arguments: -# - 1: etcd-relative URL to curl, with leading slash +# - 1: the command to run +# - 2: text to test for +# - 3: text assertion to use +# - 4: timeout duration +# - 5: interval duration # Returns: -# None -function os::util::curl_etcd() { - local url="$1" - local full_url="${API_SCHEME}://${API_HOST}:${ETCD_PORT}${url}" +# - 0: if all assertions met before timeout +# - 1: if timeout occurs +function os::cmd::internal::run_until_text() { + local cmd=$1 + local text=$2 + local test_eval_func=${3:-os::cmd::internal::success_func} + local duration=$4 + local interval=$5 - local etcd_client_cert="${MASTER_CONFIG_DIR}/master.etcd-client.crt" - local etcd_client_key="${MASTER_CONFIG_DIR}/master.etcd-client.key" - local ca_bundle="${MASTER_CONFIG_DIR}/ca-bundle.crt" + local -a junit_log - if curl -V | grep -q 'SecureTransport'; then - # on newer OSX ` + "`" + `curl` + "`" + ` implementations, SSL is not used and client certs - # and keys are expected to be encoded in P12 format instead of PEM format, - # so we need to convert the secrets that the server wrote if we haven't - # already done so - local etcd_client_cert_p12="${MASTER_CONFIG_DIR}/master.etcd-client.crt.p12" - local etcd_client_cert_p12_password="${CURL_CERT_P12_PASSWORD:-'password'}" - if [[ ! -f "${etcd_client_cert_p12}" ]]; then - openssl pkcs12 -export \ - -in "${etcd_client_cert}" \ - -inkey "${etcd_client_key}" \ - -out "${etcd_client_cert_p12}" \ - -password "pass:${etcd_client_cert_p12_password}" + os::cmd::internal::init_tempdir + os::test::junit::declare_test_start + + local description=$(os::cmd::internal::describe_call "${cmd}" "" "${text}" "${test_eval_func}") + local duration_seconds=$(echo $(( $(( duration )) / 1000)) | xargs printf '%5.3f') + local description="${description}; re-trying every ${interval}s until completion or ${duration_seconds}s" + local preamble="Running ${description}..." + echo "${preamble}" + # for ease of parsing, we want the entire declaration on one line, so we replace '\n' with ';' + junit_log+=( "${description//$'\n'/;}" ) + + local start_time=$(os::cmd::internal::seconds_since_epoch) + + local deadline=$(( $(date +%s000) + $duration )) + local test_succeeded=0 + while [ $(date +%s000) -lt $deadline ]; do + local cmd_result=$( os::cmd::internal::run_collecting_output "${cmd}"; echo $? ) + local test_result + test_result=$( os::cmd::internal::run_collecting_output 'grep -Eq "${text}" <(os::cmd::internal::get_last_results)'; echo $? ) + test_succeeded=$( ${test_eval_func} "${test_result}"; echo $? ) + + if (( test_succeeded )); then + break fi + sleep "${interval}" + os::cmd::internal::mark_attempt + done - curl --fail --silent --cacert "${ca_bundle}" \ - --cert "${etcd_client_cert_p12}:${etcd_client_cert_p12_password}" "${full_url}" + local end_time=$(os::cmd::internal::seconds_since_epoch) + local time_elapsed=$(echo $(( ${end_time} - ${start_time} )) | xargs printf '%5.3f') # in decimal seconds, we need leading zeroes for parsing later + + # clear the preamble so we can print out the success or error message + os::text::clear_string "${preamble}" + + local return_code + if (( test_succeeded )); then + os::text::print_green "SUCCESS after ${time_elapsed}s: ${description}" + junit_log+=( "SUCCESS after ${time_elapsed}s: ${description//$'\n'/;}" ) + + if [[ -n ${VERBOSE-} ]]; then + os::cmd::internal::print_results + fi + return_code=0 else - curl --fail --silent --cacert "${ca_bundle}" \ - --cert "${etcd_client_cert}" --key "${etcd_client_key}" "${full_url}" + os::text::print_red_bold "FAILURE after ${time_elapsed}s: ${description}: the command timed out" + junit_log+=( "FAILURE after ${time_elapsed}s: ${description//$'\n'/;}: the command timed out" ) + + os::text::print_red "$(os::cmd::internal::print_results)" + return_code=1 fi + + junit_log+=( "$(os::cmd::internal::print_results)" ) + ( IFS=$'\n'; echo "${junit_log[*]}" >> "${JUNIT_REPORT_OUTPUT:-/dev/null}" ) + os::test::junit::declare_test_end + return "${return_code}" } +readonly -f os::cmd::internal::run_until_text +`) -# os::util::ensure_tmpfs ensures that the target dir is mounted on tmpfs -# -# Globals: -# OS_TMPFS_REQUIRED -# Arguments: -# - 1: target to check -# Returns: -# None -function os::util::ensure_tmpfs() { - if [[ -z "${OS_TMPFS_REQUIRED:-}" ]]; then - return 0 - fi +func testExtendedTestdataCmdHackLibCmdShBytes() ([]byte, error) { + return _testExtendedTestdataCmdHackLibCmdSh, nil +} - local target="$1" - if [[ ! -d "${target}" ]]; then - os::log::fatal "Target dir ${target} does not exist, cannot perform fstype check." - fi +func testExtendedTestdataCmdHackLibCmdSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdHackLibCmdShBytes() + if err != nil { + return nil, err + } - os::log::debug "Filesystem information: -$( df -h -T )" + info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/cmd.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} - os::log::debug "Mount information: -$( findmnt --all )" +var _testExtendedTestdataCmdHackLibCompressAwk = []byte(`# Helper functions +function trim(s) { + gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "", s); + return s; +} - local fstype - fstype="$( df --output=fstype "${target}" | tail -n 1 )" - if [[ "${fstype}" != "tmpfs" ]]; then - local message="Expected \` + "`" + `${target}\` + "`" + ` to be mounted on \` + "`" + `tmpfs\` + "`" + ` but found \` + "`" + `${fstype}\` + "`" + ` instead." - os::log::fatal "${message}" - fi +function printRecordAndCount(record, count) { + print record; + if (count > 1) { + printf("... repeated %d times\n", count) + } +} + +BEGIN { + # Before processing, set the record separator to the ASCII record separator character \x1e + RS = "\x1e"; +} + +# This action is executed for each record +{ + # Build our current var from the trimmed record + current = trim($0); + + # Bump the count of times we have seen it + seen[current]++; + + # Print the previous record and its count (if it is not identical to the current record) + if (previous && previous != current) { + printRecordAndCount(previous, seen[previous]); + } + + # Store the current record as the previous record + previous = current; +} + +END { + # After processing, print the last record and count if it is non-empty + if (previous) { + printRecordAndCount(previous, seen[previous]); + } }`) -func testExtendedTestdataCmdHackLibUtilMiscShBytes() ([]byte, error) { - return _testExtendedTestdataCmdHackLibUtilMiscSh, nil +func testExtendedTestdataCmdHackLibCompressAwkBytes() ([]byte, error) { + return _testExtendedTestdataCmdHackLibCompressAwk, nil } -func testExtendedTestdataCmdHackLibUtilMiscSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdHackLibUtilMiscShBytes() +func testExtendedTestdataCmdHackLibCompressAwk() (*asset, error) { + bytes, err := testExtendedTestdataCmdHackLibCompressAwkBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/util/misc.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/compress.awk", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdHackLibUtilTextSh = []byte(`#!/usr/bin/env bash +var _testExtendedTestdataCmdHackLibConstantsSh = []byte(`#!/usr/bin/env bash -# This file contains helpful aliases for manipulating the output text to the terminal as -# well as functions for one-command augmented printing. +readonly OS_OUTPUT_BASEPATH="${OS_OUTPUT_BASEPATH:-_output}" +readonly OS_BASE_OUTPUT="${OS_ROOT}/${OS_OUTPUT_BASEPATH}" +readonly OS_OUTPUT_SCRIPTPATH="${OS_OUTPUT_SCRIPTPATH:-"${OS_BASE_OUTPUT}/scripts"}" +`) -# os::text::reset resets the terminal output to default if it is called in a TTY -function os::text::reset() { - if os::text::internal::is_tty; then - tput sgr0 - fi +func testExtendedTestdataCmdHackLibConstantsShBytes() ([]byte, error) { + return _testExtendedTestdataCmdHackLibConstantsSh, nil } -readonly -f os::text::reset -# os::text::bold sets the terminal output to bold text if it is called in a TTY -function os::text::bold() { - if os::text::internal::is_tty; then - tput bold - fi -} -readonly -f os::text::bold +func testExtendedTestdataCmdHackLibConstantsSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdHackLibConstantsShBytes() + if err != nil { + return nil, err + } -# os::text::red sets the terminal output to red text if it is called in a TTY -function os::text::red() { - if os::text::internal::is_tty; then - tput setaf 1 - fi + info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/constants.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil } -readonly -f os::text::red -# os::text::green sets the terminal output to green text if it is called in a TTY -function os::text::green() { - if os::text::internal::is_tty; then - tput setaf 2 - fi -} -readonly -f os::text::green +var _testExtendedTestdataCmdHackLibInitSh = []byte(`#!/usr/bin/env bash -# os::text::blue sets the terminal output to blue text if it is called in a TTY -function os::text::blue() { - if os::text::internal::is_tty; then - tput setaf 4 - fi -} -readonly -f os::text::blue +# This script is meant to be the entrypoint for OpenShift Bash scripts to import all of the support +# libraries at once in order to make Bash script preambles as minimal as possible. This script recur- +# sively ` + "`" + `source` + "`" + `s *.sh files in this directory tree. As such, no files should be ` + "`" + `source` + "`" + `ed outside +# of this script to ensure that we do not attempt to overwrite read-only variables. -# os::text::yellow sets the terminal output to yellow text if it is called in a TTY -function os::text::yellow() { - if os::text::internal::is_tty; then - tput setaf 11 +set -o errexit +set -o nounset +set -o pipefail + +OS_SCRIPT_START_TIME="$( date +%s )"; export OS_SCRIPT_START_TIME + +# os::util::absolute_path returns the absolute path to the directory provided +function os::util::absolute_path() { + local relative_path="$1" + local absolute_path + + pushd "${relative_path}" >/dev/null + relative_path="$( pwd )" + if [[ -h "${relative_path}" ]]; then + absolute_path="$( readlink "${relative_path}" )" + else + absolute_path="${relative_path}" fi + popd >/dev/null + + echo "${absolute_path}" } -readonly -f os::text::yellow +readonly -f os::util::absolute_path -# os::text::clear_last_line clears the text from the last line of output to the -# terminal and leaves the cursor on that line to allow for overwriting that text -# if it is called in a TTY -function os::text::clear_last_line() { - if os::text::internal::is_tty; then - tput cuu 1 - tput el +# find the absolute path to the root of the Origin source tree +init_source="$( dirname "${BASH_SOURCE[0]}" )/../.." +OS_ROOT="$( os::util::absolute_path "${init_source}" )" +export OS_ROOT +cd "${OS_ROOT}" + +source "${OS_ROOT}/hack/lib/constants.sh" +source "${OS_ROOT}/hack/lib/cmd.sh" + +for library_file in $( find "${OS_ROOT}/hack/lib/log" -type f -name '*.sh' -not -path '*/hack/lib/init.sh' ); do + source "${library_file}" +done +for library_file in $( find "${OS_ROOT}/hack/lib/test" -type f -name '*.sh' -not -path '*/hack/lib/init.sh' ); do + source "${library_file}" +done +for library_file in $( find "${OS_ROOT}/hack/lib/util" -type f -name '*.sh' -not -path '*/hack/lib/init.sh' ); do + source "${library_file}" +done + +unset library_files library_file init_source + +# all of our Bash scripts need to have the stacktrace +# handler installed to deal with errors +os::log::stacktrace::install + +# All of our Bash scripts need to have access to the +# binaries that we build so we don't have to find +# them before every invocation. +os::util::environment::update_path_var + +if [[ -z "${OS_TMP_ENV_SET-}" ]]; then + # if this file is run via 'source', then $0 will be "-bash" and won't work with basename + if [[ "${0}" =~ .*\.sh ]]; then + os::util::environment::setup_tmpdir_vars "$( basename "${0}" ".sh" )" + else + os::util::environment::setup_tmpdir_vars "shell" fi -} -readonly -f os::text::clear_last_line +fi -# os::text::clear_string attempts to clear the entirety of a string from the terminal. -# If the string contains literal tabs or other characters that take up more than one -# character space in output, or if the window size is changed before this function -# is called, it will not function correctly. -# No action is taken if this is called outside of a TTY -function os::text::clear_string() { - local -r string="$1" - if os::text::internal::is_tty; then - echo "${string}" | while read line; do - # num_lines is the number of terminal lines this one line of output - # would have taken up with the current terminal width in columns - local num_lines=$(( ${#line} / $( tput cols ) )) - for (( i = 0; i <= num_lines; i++ )); do - os::text::clear_last_line - done - done - fi -} +# Allow setting $JUNIT_REPORT to toggle output behavior +if [[ -n "${JUNIT_REPORT:-}" ]]; then + export JUNIT_REPORT_OUTPUT="${LOG_DIR}/raw_test_output.log" +fi -# os::text::internal::is_tty determines if we are outputting to a TTY -function os::text::internal::is_tty() { - [[ -t 1 && -n "${TERM:-}" ]] -} -readonly -f os::text::internal::is_tty -# os::text::print_bold prints all input in bold text -function os::text::print_bold() { - os::text::bold - echo "${*}" - os::text::reset -} -readonly -f os::text::print_bold +cp ${KUBECONFIG_TESTS} /kubeconfig +chmod 644 /kubeconfig +export KUBECONFIG=/kubeconfig -# os::text::print_red prints all input in red text -function os::text::print_red() { - os::text::red - echo "${*}" - os::text::reset +namespace="cmd-${TEST_NAME}" +oc new-project "${namespace}" +`) + +func testExtendedTestdataCmdHackLibInitShBytes() ([]byte, error) { + return _testExtendedTestdataCmdHackLibInitSh, nil } -readonly -f os::text::print_red -# os::text::print_red_bold prints all input in bold red text -function os::text::print_red_bold() { - os::text::red - os::text::bold - echo "${*}" - os::text::reset +func testExtendedTestdataCmdHackLibInitSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdHackLibInitShBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/init.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil } -readonly -f os::text::print_red_bold -# os::text::print_green prints all input in green text -function os::text::print_green() { - os::text::green - echo "${*}" - os::text::reset +var _testExtendedTestdataCmdHackLibLogOutputSh = []byte(`#!/usr/bin/env bash + +# This file contains functions used for writing log messages +# to stdout and stderr from scripts while they run. + +# os::log::info writes the message to stdout. +# +# Arguments: +# - all: message to write +function os::log::info() { + local message; message="$( os::log::internal::prefix_lines "[INFO]" "$*" )" + os::log::internal::to_logfile "${message}" + echo "${message}" } -readonly -f os::text::print_green +readonly -f os::log::info -# os::text::print_green_bold prints all input in bold green text -function os::text::print_green_bold() { - os::text::green - os::text::bold - echo "${*}" - os::text::reset +# os::log::warning writes the message to stderr. +# A warning indicates something went wrong but +# not so wrong that we cannot recover. +# +# Arguments: +# - all: message to write +function os::log::warning() { + local message; message="$( os::log::internal::prefix_lines "[WARNING]" "$*" )" + os::log::internal::to_logfile "${message}" + os::text::print_yellow "${message}" 1>&2 } -readonly -f os::text::print_green_bold +readonly -f os::log::warning -# os::text::print_blue prints all input in blue text -function os::text::print_blue() { - os::text::blue - echo "${*}" - os::text::reset +# os::log::error writes the message to stderr. +# An error indicates that something went wrong +# and we will most likely fail after this. +# +# Arguments: +# - all: message to write +function os::log::error() { + local message; message="$( os::log::internal::prefix_lines "[ERROR]" "$*" )" + os::log::internal::to_logfile "${message}" + os::text::print_red "${message}" 1>&2 } -readonly -f os::text::print_blue +readonly -f os::log::error -# os::text::print_blue_bold prints all input in bold blue text -function os::text::print_blue_bold() { - os::text::blue - os::text::bold - echo "${*}" - os::text::reset +# os::log::fatal writes the message to stderr and +# returns a non-zero code to force a process exit. +# A fatal error indicates that there is no chance +# of recovery. +# +# Arguments: +# - all: message to write +function os::log::fatal() { + local message; message="$( os::log::internal::prefix_lines "[FATAL]" "$*" )" + os::log::internal::to_logfile "${message}" + os::text::print_red "${message}" 1>&2 + exit 1 } -readonly -f os::text::print_blue_bold +readonly -f os::log::fatal -# os::text::print_yellow prints all input in yellow text -function os::text::print_yellow() { - os::text::yellow - echo "${*}" - os::text::reset +# os::log::debug writes the message to stderr if +# the ${OS_DEBUG} variable is set. +# +# Globals: +# - OS_DEBUG +# Arguments: +# - all: message to write +function os::log::debug() { + local message; message="$( os::log::internal::prefix_lines "[DEBUG]" "$*" )" + os::log::internal::to_logfile "${message}" + if [[ -n "${OS_DEBUG:-}" ]]; then + os::text::print_blue "${message}" 1>&2 + fi } -readonly -f os::text::print_yellow +readonly -f os::log::debug -# os::text::print_yellow_bold prints all input in bold yellow text -function os::text::print_yellow_bold() { - os::text::yellow - os::text::bold - echo "${*}" - os::text::reset +# os::log::internal::to_logfile makes a best-effort +# attempt to write the message to the script logfile +# +# Globals: +# - LOG_DIR +# Arguments: +# - all: message to write +function os::log::internal::to_logfile() { + if [[ -n "${LOG_DIR:-}" && -d "${LOG_DIR-}" ]]; then + echo "$*" >>"${LOG_DIR}/scripts.log" + fi } -readonly -f os::text::print_yellow_bold -`) -func testExtendedTestdataCmdHackLibUtilTextShBytes() ([]byte, error) { - return _testExtendedTestdataCmdHackLibUtilTextSh, nil +# os::log::internal::prefix_lines prints out the +# original content with the given prefix at the +# start of every line. +# +# Arguments: +# - 1: prefix for lines +# - 2: content to prefix +function os::log::internal::prefix_lines() { + local prefix="$1" + local content="$2" + + local old_ifs="${IFS}" + IFS=$'\n' + for line in ${content}; do + echo "${prefix} ${line}" + done + IFS="${old_ifs}" +}`) + +func testExtendedTestdataCmdHackLibLogOutputShBytes() ([]byte, error) { + return _testExtendedTestdataCmdHackLibLogOutputSh, nil } -func testExtendedTestdataCmdHackLibUtilTextSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdHackLibUtilTextShBytes() +func testExtendedTestdataCmdHackLibLogOutputSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdHackLibLogOutputShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/util/text.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/log/output.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdHackLibUtilTrapSh = []byte(`#!/usr/bin/env bash +var _testExtendedTestdataCmdHackLibLogStacktraceSh = []byte(`#!/usr/bin/env bash # -# This library defines the trap handlers for the ERR and EXIT signals. Any new handler for these signals -# must be added to these handlers and activated by the environment variable mechanism that the rest use. -# These functions ensure that no handler can ever alter the exit code that was emitted by a command -# in a test script. +# This library contains an implementation of a stack trace for Bash scripts. -# os::util::trap::init_err initializes the privileged handler for the ERR signal if it hasn't -# been registered already. This will overwrite any other handlers registered on the signal. +# os::log::stacktrace::install installs the stacktrace as a handler for the ERR signal if one +# has not already been installed and sets ` + "`" + `set -o errtrace` + "`" + ` in order to propagate the handler +# If the ERR trap is not initialized, installing this plugin will initialize it. # # Globals: # None # Arguments: # None # Returns: -# None -function os::util::trap::init_err() { - if ! trap -p ERR | grep -q 'os::util::trap::err_handler'; then - trap 'os::util::trap::err_handler;' ERR - fi +# - export OS_USE_STACKTRACE +function os::log::stacktrace::install() { + # setting 'errtrace' propagates our ERR handler to functions, expansions and subshells + set -o errtrace + + # OS_USE_STACKTRACE is read by os::util::trap at runtime to request a stacktrace + export OS_USE_STACKTRACE=true + + os::util::trap::init_err } -readonly -f os::util::trap::init_err +readonly -f os::log::stacktrace::install -# os::util::trap::init_exit initializes the privileged handler for the EXIT signal if it hasn't -# been registered already. This will overwrite any other handlers registered on the signal. +# os::log::stacktrace::print prints the stacktrace and exits with the return code from the script that +# called for a stack trace. This function will always return 0 if it is not handling the signal, and if it +# is handling the signal, this function will always ` + "`" + `exit` + "`" + `, not return, the return code it receives as +# its first argument. # # Globals: -# None +# - BASH_SOURCE +# - BASH_LINENO +# - FUNCNAME # Arguments: -# None +# - 1: the return code of the command in the script that generated the ERR signal +# - 2: the last command that ran before handlers were invoked +# - 3: whether or not ` + "`" + `set -o errexit` + "`" + ` was set in the script that generated the ERR signal # Returns: # None -function os::util::trap::init_exit() { - if ! trap -p EXIT | grep -q 'os::util::trap::exit_handler'; then - trap 'os::util::trap::exit_handler;' EXIT +function os::log::stacktrace::print() { + local return_code=$1 + local last_command=$2 + local errexit_set=${3:-} + + if [[ "${return_code}" = "0" ]]; then + # we're not supposed to respond when no error has occurred + return 0 + fi + + if [[ -z "${errexit_set}" ]]; then + # if errexit wasn't set in the shell when the ERR signal was issued, then we can ignore the signal + # as this is not cause for failure + return 0 fi + + # dump the entire stack for debugging purposes + os::log::debug "$( os::util::repository_relative_path "${BASH_SOURCE[0]}:${LINENO}: ${BASH_COMMAND}" )" + for (( i = 0; i < ${#BASH_LINENO[@]}; i++ )); do + os::log::debug "$( os::util::repository_relative_path "${BASH_SOURCE[$i+1]:-"$( os::util::repository_relative_path "$0" )"}" ):${BASH_LINENO[$i]}: ${FUNCNAME[$i]}" + done + + # iterate backwards through the stack until we leave library files, so we can be sure we start logging + # actual script code and not this handler's call + local stack_begin_index + for (( stack_begin_index = 0; stack_begin_index < ${#BASH_SOURCE[@]}; stack_begin_index++ )); do + if [[ ! "${BASH_SOURCE[${stack_begin_index}]}" =~ hack/lib/(log/stacktrace|util/trap)\.sh ]]; then + break + fi + done + + local preamble_finished + local stack_index=1 + local i + for (( i = stack_begin_index; i < ${#BASH_SOURCE[@]}; i++ )); do + local bash_source + bash_source="$( os::util::repository_relative_path "${BASH_SOURCE[$i]}" )" + if [[ -z "${preamble_finished:-}" ]]; then + preamble_finished=true + os::log::error "${bash_source}:${BASH_LINENO[$i-1]}: \` + "`" + `${last_command}\` + "`" + ` exited with status ${return_code}." >&2 + exit "${return_code}" + fi + stack_index=$(( stack_index + 1 )) + done + + # we know we're the privileged handler in this chain, so we can safely exit the shell without + # starving another handler of the privilege of reacting to this signal + os::log::info " Exiting with code ${return_code}." >&2 + exit "${return_code}" } -readonly -f os::util::trap::init_exit +readonly -f os::log::stacktrace::print +`) -# os::util::trap::err_handler is the handler for the ERR signal. +func testExtendedTestdataCmdHackLibLogStacktraceShBytes() ([]byte, error) { + return _testExtendedTestdataCmdHackLibLogStacktraceSh, nil +} + +func testExtendedTestdataCmdHackLibLogStacktraceSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdHackLibLogStacktraceShBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/log/stacktrace.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _testExtendedTestdataCmdHackLibLogSystemSh = []byte(`#!/usr/bin/env bash +# +# This library holds all of the system logging functions for OpenShift bash scripts. + +# os::log::system::install_cleanup installs os::log::system::clean_up as a trap on exit. +# If any traps are currently set for these signals, os::log::system::clean_up is prefixed. # # Globals: -# - OS_TRAP_DEBUG -# - OS_USE_STACKTRACE +# None # Arguments: # None # Returns: -# - returns original return code, allows privileged handler to exit if necessary -function os::util::trap::err_handler() { - local -r return_code=$? - local -r last_command="${BASH_COMMAND}" - - if set +o | grep -q '\-o errexit'; then - local -r errexit_set=true - fi - - if [[ "${OS_TRAP_DEBUG:-}" = "true" ]]; then - echo "[DEBUG] Error handler executing with return code \` + "`" + `${return_code}\` + "`" + `, last command \` + "`" + `${last_command}\` + "`" + `, and errexit set \` + "`" + `${errexit_set:-}\` + "`" + `" - fi - - if [[ "${OS_USE_STACKTRACE:-}" = "true" ]]; then - # the OpenShift stacktrace function is treated as a privileged handler for this signal - # and is therefore allowed to run outside of a subshell in order to allow it to ` + "`" + `exit` + "`" + ` - # if necessary - os::log::stacktrace::print "${return_code}" "${last_command}" "${errexit_set:-}" - fi - - return "${return_code}" +# None +function os::log::system::install_cleanup() { + trap "os::log::system::clean_up; $(trap -p EXIT | awk -F"'" '{print $2}')" EXIT } -readonly -f os::util::trap::err_handler +readonly -f os::log::system::install_cleanup -# os::util::trap::exit_handler is the handler for the EXIT signal. +# os::log::system::clean_up should be trapped so that it can stop the logging utility once the script that +# installed it is finished. +# This function stops logging and generates plots of data for easy consumption. # # Globals: -# - OS_TRAP_DEBUG -# - OS_DESCRIBE_RETURN_CODE +# - LOG_DIR +# - LOGGER_PID +# - SAR_LOGFILE # Arguments: # None # Returns: -# - original exit code of the script that exited -function os::util::trap::exit_handler() { - local -r return_code=$? +# None +function os::log::system::clean_up() { + local return_code=$? - # we do not want these traps to be able to trigger more errors, we can let them fail silently + # we don't want failures in this logger to set +o errexit - if [[ "${OS_TRAP_DEBUG:-}" = "true" ]]; then - echo "[DEBUG] Exit handler executing with return code \` + "`" + `${return_code}\` + "`" + `" - fi + if jobs -pr | grep -q "${LOGGER_PID}"; then + kill -SIGTERM "${LOGGER_PID}" + # give logger ten seconds to gracefully exit before killing it + for (( i = 0; i < 10; i++ )); do + if ! jobs -pr | grep -q "${LOGGER_PID}"; then + # the logger has shutdown, we don't need to wait on it any longer + break + fi + done - # the following envars selectively enable optional exit traps, all of which are run inside of - # a subshell in order to sandbox them and not allow them to influence how this script will exit - if [[ "${OS_DESCRIBE_RETURN_CODE:-}" = "true" ]]; then - ( os::util::describe_return_code "${return_code}" ) + if jobs -pr | grep -q "${LOGGER_PID}"; then + # the logger has not shutdown, so kill it + kill -SIGKILL "${LOGGER_PID}" + fi fi - exit "${return_code}" -} -readonly -f os::util::trap::exit_handler -`) + if ! which sadf >/dev/null 2>&1; then + os::log::warning "System logger data could not be unpacked and graphed, 'sadf' binary not found in this environment." + return 0 + fi -func testExtendedTestdataCmdHackLibUtilTrapShBytes() ([]byte, error) { - return _testExtendedTestdataCmdHackLibUtilTrapSh, nil -} + if [[ ! -s "${SAR_LOGFILE:-}" ]]; then + os::log::warning "No system logger data could be found, log file missing." + return 0 + fi -func testExtendedTestdataCmdHackLibUtilTrapSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdHackLibUtilTrapShBytes() - if err != nil { - return nil, err - } + local log_subset_flags=( "-b" "-B" "-u ALL" "-q" "-r" ) - info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/util/trap.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} + local log_subset_names=( "iops" "paging" "cpu" "queue" "memory" ) -var _testExtendedTestdataCmdTestCmdAdminSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT + local log_subset_file + local i + for (( i = 0; i < "${#log_subset_flags[@]}"; i++ )); do + log_subset_file="${LOG_DIR}/${log_subset_names[$i]}.txt" + # use sadf utility to extract data into easily-parseable format + sadf -d "${SAR_LOGFILE}" -- ${log_subset_flags[$i]} > "${log_subset_file}" -# Cleanup cluster resources created by this test -( - set +e - oc delete project/example project/ui-test-project project/recreated-project &>/dev/null || true - oc delete groups/shortoutputgroup &>/dev/null || true - oc delete groups/group1 &>/dev/null || true - oc delete groups/cascaded-group &>/dev/null || true - oc delete groups/orphaned-group &>/dev/null || true - oc delete users/cascaded-user &>/dev/null || true - oc delete users/orphaned-user &>/dev/null || true - oc delete identities/alwaysallow:orphaned-user &>/dev/null || true - oc delete identities/alwaysallow:cascaded-user &>/dev/null || true - oc delete clusterroles/basic-users2 &>/dev/null || true - oc delete clusterroles/basic-user2 &>/dev/null || true - oc delete clusterrolebindings/basic-users2 &>/dev/null || true - oc delete clusterrolebindings/basic-user2 &>/dev/null || true - oc delete user/test-cmd-user &>/dev/null || true - oc delete namespace example &>/dev/null || true - oc delete identities.user.openshift.io/test-idp:test-uid &>/dev/null || true - oc delete images.image.openshift.io/sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6 &>/dev/null || true - oc delete -n default imagestreams.image.openshift.io/busybox &>/dev/null || true - oc wait --for=delete namespace/example --timeout=60s || true -# oc auth reconcile --remove-extra-permissions --remove-extra-subjects -f "${BASE_RBAC_DATA}" - exit 0 -) &>/dev/null + local ignored_columns="hostname,interval," -project="$( oc project -q )" + # special cases for special output from SAR, because the tool often gives us columns full of baloney + if [[ "${log_subset_names[$i]}" == "cpu" ]]; then + ignored_columns="${ignored_columns}CPU," + fi -defaultimage="openshift/origin-\${component}:latest" -USE_IMAGES=${USE_IMAGES:-$defaultimage} + os::log::system::internal::prune_datafile "${log_subset_file}" "${ignored_columns}" + os::log::system::internal::plot "${log_subset_file}" + done -os::test::junit::declare_suite_start "cmd/admin" -# This test validates admin level commands including system policy + # remove the ` + "`" + `sar` + "`" + ` log file for space constraints + rm -f "${SAR_LOGFILE}" -os::test::junit::declare_suite_start "cmd/admin/start" -# Check failure modes of various system commands + return "${return_code}" +} +readonly -f os::log::system::clean_up -os::test::junit::declare_suite_start "cmd/admin/certs" -# check encrypt/decrypt of plain text -os::cmd::expect_success "echo -n 'secret data 1' | oc adm ca encrypt --genkey='${ARTIFACT_DIR}/secret.key' --out='${ARTIFACT_DIR}/secret.encrypted'" -os::cmd::expect_success_and_text "oc adm ca decrypt --in='${ARTIFACT_DIR}/secret.encrypted' --key='${ARTIFACT_DIR}/secret.key'" 'secret data 1' -# create a file with trailing whitespace -echo "data with newline" > "${ARTIFACT_DIR}/secret.whitespace.data" -os::cmd::expect_success_and_text "oc adm ca encrypt --key='${ARTIFACT_DIR}/secret.key' --in='${ARTIFACT_DIR}/secret.whitespace.data' --out='${ARTIFACT_DIR}/secret.whitespace.encrypted'" 'Warning.*whitespace' -os::cmd::expect_success "oc adm ca decrypt --key='${ARTIFACT_DIR}/secret.key' --in='${ARTIFACT_DIR}/secret.whitespace.encrypted' --out='${ARTIFACT_DIR}/secret.whitespace.decrypted'" -os::cmd::expect_success "diff '${ARTIFACT_DIR}/secret.whitespace.data' '${ARTIFACT_DIR}/secret.whitespace.decrypted'" -# create a binary file -echo "hello" | gzip > "${ARTIFACT_DIR}/secret.data" -# encrypt using file and pipe input/output -os::cmd::expect_success "oc adm ca encrypt --key='${ARTIFACT_DIR}/secret.key' --in='${ARTIFACT_DIR}/secret.data' --out='${ARTIFACT_DIR}/secret.file-in-file-out.encrypted'" -os::cmd::expect_success "oc adm ca encrypt --key='${ARTIFACT_DIR}/secret.key' --in='${ARTIFACT_DIR}/secret.data' > '${ARTIFACT_DIR}/secret.file-in-pipe-out.encrypted'" -os::cmd::expect_success "oc adm ca encrypt --key='${ARTIFACT_DIR}/secret.key' < '${ARTIFACT_DIR}/secret.data' > '${ARTIFACT_DIR}/secret.pipe-in-pipe-out.encrypted'" -# decrypt using all three methods -os::cmd::expect_success "oc adm ca decrypt --key='${ARTIFACT_DIR}/secret.key' --in='${ARTIFACT_DIR}/secret.file-in-file-out.encrypted' --out='${ARTIFACT_DIR}/secret.file-in-file-out.decrypted'" -os::cmd::expect_success "oc adm ca decrypt --key='${ARTIFACT_DIR}/secret.key' --in='${ARTIFACT_DIR}/secret.file-in-pipe-out.encrypted' > '${ARTIFACT_DIR}/secret.file-in-pipe-out.decrypted'" -os::cmd::expect_success "oc adm ca decrypt --key='${ARTIFACT_DIR}/secret.key' < '${ARTIFACT_DIR}/secret.pipe-in-pipe-out.encrypted' > '${ARTIFACT_DIR}/secret.pipe-in-pipe-out.decrypted'" -# verify lossless roundtrip -os::cmd::expect_success "diff '${ARTIFACT_DIR}/secret.data' '${ARTIFACT_DIR}/secret.file-in-file-out.decrypted'" -os::cmd::expect_success "diff '${ARTIFACT_DIR}/secret.data' '${ARTIFACT_DIR}/secret.file-in-pipe-out.decrypted'" -os::cmd::expect_success "diff '${ARTIFACT_DIR}/secret.data' '${ARTIFACT_DIR}/secret.pipe-in-pipe-out.decrypted'" -echo "certs: ok" -os::test::junit::declare_suite_end +# os::log::system::internal::prune_datafile removes the given columns from a datafile created by 'sadf -d' +# +# Globals: +# None +# Arguments: +# - 1: datafile +# - 2: comma-delimited columns to remove, with trailing comma +# Returns: +# None +function os::log::system::internal::prune_datafile() { + local datafile=$1 + local column_names=$2 -os::test::junit::declare_suite_start "cmd/admin/groups" -os::cmd::expect_success_and_text 'oc adm groups new shortoutputgroup -o name' 'group.user.openshift.io/shortoutputgroup' -# test --dry-run flag for this command -os::cmd::expect_success_and_text 'oc adm groups new mygroup --dry-run' 'group.user.openshift.io/mygroup created \(dry run\)' -os::cmd::expect_success_and_text 'oc adm groups new mygroup --dry-run -o name' 'group.user.openshift.io/mygroup' -# ensure group was not actually created -os::cmd::expect_failure_and_text 'oc get groups mygroup' 'groups.user.openshift.io "mygroup" not found' -os::cmd::expect_success_and_text 'oc adm groups new shortoutputgroup -o name --dry-run' 'group.user.openshift.io/shortoutputgroup' -os::cmd::expect_failure_and_text 'oc adm groups new shortoutputgroup' 'groups.user.openshift.io "shortoutputgroup" already exists' -os::cmd::expect_failure_and_text 'oc adm groups new errorgroup -o blah' 'unable to match a printer suitable for the output format "blah"' -os::cmd::expect_failure_and_text 'oc get groups/errorgroup' 'groups.user.openshift.io "errorgroup" not found' -# update cmd to use --template once it is wired across all Origin commands. -# see -os::cmd::expect_success_and_text 'oc adm groups new group1 foo bar -o yaml' '\- foo' -os::cmd::expect_success_and_text 'oc get groups/group1 --no-headers' 'foo, bar' -os::cmd::expect_success 'oc adm groups add-users group1 baz' -os::cmd::expect_success_and_text 'oc get groups/group1 --no-headers' 'baz' -os::cmd::expect_success 'oc adm groups remove-users group1 bar' -os::cmd::expect_success_and_not_text 'oc get groups/group1 --no-headers' 'bar' -os::cmd::expect_success_and_text 'oc adm prune auth users/baz' 'group.user.openshift.io/group1 updated' -echo "groups: ok" -os::test::junit::declare_suite_end + if [[ "${#column_names}" -eq 0 ]]; then + return 0 + fi -os::test::junit::declare_suite_start "cmd/admin/admin-scc" -os::cmd::expect_success 'oc adm policy who-can get pods' -os::cmd::expect_success 'oc adm policy who-can get pods -n default' -os::cmd::expect_success 'oc adm policy who-can get pods --all-namespaces' -# check to make sure that the resource arg conforms to resource rules -os::cmd::expect_success_and_text 'oc adm policy who-can get Pod' "Resource: pods" -os::cmd::expect_success_and_text 'oc adm policy who-can get PodASDF' "Resource: PodASDF" -os::cmd::expect_success_and_text 'oc adm policy who-can get hpa.autoscaling -n default' "Resource: horizontalpodautoscalers.autoscaling" -os::cmd::expect_success_and_text 'oc adm policy who-can get hpa.v1.autoscaling -n default' "Resource: horizontalpodautoscalers.autoscaling" -os::cmd::expect_success_and_text 'oc adm policy who-can get hpa -n default' "Resource: horizontalpodautoscalers.autoscaling" + local columns_in_order + columns_in_order=( $( head -n 1 "${datafile}" | sed 's/^# //g' | tr ';' ' ' ) ) -os::cmd::expect_success 'oc adm policy add-role-to-group --rolebinding-name=cluster-admin cluster-admin system:unauthenticated' -os::cmd::expect_success 'oc adm policy add-role-to-user --rolebinding-name=cluster-admin cluster-admin system:no-user' -os::cmd::expect_success 'oc adm policy add-role-to-user --rolebinding-name=admin admin -z fake-sa' -os::cmd::expect_success_and_text 'oc get rolebinding/admin -o jsonpath={.subjects}' 'fake-sa' -os::cmd::expect_success 'oc adm policy remove-role-from-user admin -z fake-sa' -os::cmd::expect_success_and_not_text 'oc get rolebinding/admin -o jsonpath={.subjects}' 'fake-sa' -os::cmd::expect_success 'oc adm policy add-role-to-user --rolebinding-name=admin admin -z fake-sa' -os::cmd::expect_success_and_text 'oc get rolebinding/admin -o jsonpath={.subjects}' 'fake-sa' -os::cmd::expect_success "oc adm policy remove-role-from-user admin system:serviceaccount:$(oc project -q):fake-sa" -os::cmd::expect_success_and_not_text 'oc get rolebinding/admin -o jsonpath={.subjects}' 'fake-sa' -os::cmd::expect_success 'oc adm policy remove-role-from-group cluster-admin system:unauthenticated' -os::cmd::expect_success 'oc adm policy remove-role-from-user cluster-admin system:no-user' -os::cmd::expect_failure_and_text 'oc adm policy remove-role-from-user admin ghost' 'error: unable to find target \[ghost\]' -os::cmd::expect_failure_and_text 'oc adm policy remove-role-from-user admin -z ghost' 'error: unable to find target \[ghost\]' -os::cmd::expect_success 'oc adm policy remove-group system:unauthenticated' -os::cmd::expect_success 'oc adm policy remove-user system:no-user' -os::cmd::expect_success 'oc adm policy add-cluster-role-to-group cluster-admin system:unauthenticated' -os::cmd::expect_success 'oc adm policy remove-cluster-role-from-group cluster-admin system:unauthenticated' -os::cmd::expect_success 'oc adm policy add-cluster-role-to-user cluster-admin system:no-user' -os::cmd::expect_success 'oc adm policy remove-cluster-role-from-user cluster-admin system:no-user' -os::cmd::expect_success 'oc adm policy add-role-to-user view foo' -os::cmd::expect_success 'oc adm policy add-role-to-user view bar --rolebinding-name=custom' -os::cmd::expect_success 'oc adm policy add-role-to-user view baz --rolebinding-name=custom' -#os::cmd::expect_success_and_text 'oc get rolebinding/view -o jsonpath="{.metadata.name},{.roleRef.name},{.userNames[*]}"' '^view,view,foo$' -#os::cmd::expect_success_and_text 'oc get rolebinding/custom -o jsonpath="{.metadata.name},{.roleRef.name},{.userNames[*]}"' '^custom,view,bar baz$' -os::cmd::expect_failure_and_text 'oc adm policy add-role-to-user other fuz --rolebinding-name=custom' '^error: rolebinding custom found for role view, not other$' -#os::cmd::expect_success_and_text 'oc adm policy remove-cluster-role-from-group self-provisioner system:authenticated:oauth' "Warning: Your changes may get lost whenever a master is restarted, unless you prevent reconciliation of this rolebinding using the following command: oc annotate clusterrolebinding.rbac self-provisioners 'rbac.authorization.kubernetes.io/autoupdate=false' --overwrite" -os::cmd::expect_success 'oc adm policy add-cluster-role-to-group --rolebinding-name=self-provisioners self-provisioner system:authenticated:oauth' -#os::cmd::expect_success 'oc annotate clusterrolebinding.rbac self-provisioners "rbac.authorization.kubernetes.io/autoupdate=false" --overwrite' -#os::cmd::expect_success_and_not_text 'oc adm policy remove-cluster-role-from-group self-provisioner system:authenticated:oauth' "Warning" -#os::cmd::expect_success 'oc adm policy add-cluster-role-to-group --rolebinding-name=self-provisioners self-provisioner system:authenticated:oauth' + local columns_to_keep + local i + for (( i = 0; i < "${#columns_in_order[@]}"; i++ )); do + if ! echo "${column_names}" | grep -q "${columns_in_order[$i]},"; then + # this is a column we need to keep, adding one as 'cut' is 1-indexed + columns_to_keep+=( "$(( i + 1 ))" ) + fi + done -# os::cmd::expect_success 'oc adm policy add-scc-to-user privileged fake-user' -# os::cmd::expect_success_and_text 'oc get scc/privileged -o yaml' 'fake-user' -# os::cmd::expect_success 'oc adm policy add-scc-to-user privileged -z fake-sa' -# os::cmd::expect_success_and_text 'oc get scc/privileged -o yaml' "system:serviceaccount:$(oc project -q):fake-sa" -# os::cmd::expect_success 'oc adm policy add-scc-to-group privileged fake-group' -# os::cmd::expect_success_and_text 'oc get scc/privileged -o yaml' 'fake-group' -# os::cmd::expect_success 'oc adm policy remove-scc-from-user privileged fake-user' -# os::cmd::expect_success_and_not_text 'oc get scc/privileged -o yaml' 'fake-user' -# os::cmd::expect_success 'oc adm policy remove-scc-from-user privileged -z fake-sa' -# os::cmd::expect_success_and_not_text 'oc get scc/privileged -o yaml' "system:serviceaccount:$(oc project -q):fake-sa" -# os::cmd::expect_success 'oc adm policy remove-scc-from-group privileged fake-group' -# os::cmd::expect_success_and_not_text 'oc get scc/privileged -o yaml' 'fake-group' + # for the proper flag format for 'cut', we join the list delimiting with commas + columns_to_keep="$( IFS=','; echo "${columns_to_keep[*]}" )" -# check pruning -os::cmd::expect_success 'oc adm policy add-scc-to-user privileged fake-user' -os::cmd::expect_success_and_text 'oc adm prune auth users/fake-user' 'privileged updated' -os::cmd::expect_success 'oc adm policy add-scc-to-group privileged fake-group' -os::cmd::expect_success_and_text 'oc adm prune auth groups/fake-group' 'privileged updated' -echo "admin-scc: ok" -os::test::junit::declare_suite_end + cut --delimiter=';' -f"${columns_to_keep}" "${datafile}" > "${datafile}.tmp" + sed -i '1s/^/# /' "${datafile}.tmp" + mv "${datafile}.tmp" "${datafile}" +} +readonly -f os::log::system::internal::prune_datafile -os::test::junit::declare_suite_start "cmd/admin/role-reapers" -#os::cmd::expect_success "oc process -f ${TEST_DATA}/roles/policy-roles.yaml -p NAMESPACE='${project}' | oc create -f -" -#os::cmd::expect_success "oc get rolebinding/basic-users" -#os::cmd::expect_success "oc adm prune auth role/basic-user" -#os::cmd::try_until_failure "oc get rolebinding/basic-users" -#os::cmd::expect_success "oc delete role/basic-user" -#os::cmd::expect_success "oc create -f ${TEST_DATA}/roles/policy-clusterroles.yaml" -#os::cmd::expect_success "oc get clusterrolebinding/basic-users2" -#os::cmd::expect_success "oc adm prune auth clusterrole/basic-user2" -#os::cmd::try_until_failure "oc get clusterrolebinding/basic-users2" -#os::cmd::expect_success "oc delete clusterrole/basic-user2" -#os::cmd::expect_success "oc policy add-role-to-user edit foo" -#os::cmd::expect_success "oc get rolebinding/edit" -#os::cmd::expect_success "oc adm prune auth clusterrole/edit" -#os::cmd::try_until_failure "oc get rolebinding/edit" -#os::cmd::expect_success "oc delete clusterrole/edit" -#os::cmd::expect_success 'oc auth reconcile --remove-extra-permissions --remove-extra-subjects -f "${BASE_RBAC_DATA}"' -# -#os::cmd::expect_success "oc process -f ${TEST_DATA}/roles/policy-roles.yaml -p NAMESPACE='${project}' | oc create -f -" -#os::cmd::expect_success "oc get rolebinding/basic-users" -#os::cmd::expect_success_and_text "oc adm prune auth role/basic-user" "rolebinding.rbac.authorization.k8s.io/basic-users deleted" -#os::cmd::expect_success "oc get role/basic-user" -#os::cmd::expect_success "oc delete role/basic-user" +# os::log::system::internal::plot uses gnuplot to make a plot of some data across time points. This function is intended to be used +# on the output of a 'sar -f' read of a sar binary file. Plots will be made of all columns and stacked on each other with one x axis. +# This function needs the non-data columns of the file to be prefixed with comments. # -#os::cmd::expect_success "oc create -f ${TEST_DATA}/roles/policy-clusterroles.yaml" -#os::cmd::expect_success "oc get clusterrolebinding/basic-users2" -#os::cmd::expect_success_and_text "oc adm prune auth clusterrole/basic-user2" "clusterrolebinding.rbac.authorization.k8s.io/basic-users2 deleted" -#os::cmd::expect_success "oc get clusterrole/basic-user2" -#os::cmd::expect_success "oc delete clusterrole/basic-user2" -echo "admin-role-reapers: ok" -os::test::junit::declare_suite_end - -os::test::junit::declare_suite_start "cmd/admin/role-selectors" -os::cmd::expect_success "oc create -f ${TEST_DATA}/roles/policy-clusterroles.yaml" -os::cmd::expect_success "oc get clusterrole/basic-user2" -os::cmd::expect_success "oc label clusterrole/basic-user2 foo=bar" -os::cmd::expect_success_and_not_text "oc get clusterroles --selector=foo=bar" "No resources found" -os::cmd::expect_success_and_text "oc get clusterroles --selector=foo=unknown" "No resources found" -os::cmd::expect_success "oc get clusterrolebinding/basic-users2" -os::cmd::expect_success "oc label clusterrolebinding/basic-users2 foo=bar" -os::cmd::expect_success_and_not_text "oc get clusterrolebindings --selector=foo=bar" "No resources found" -os::cmd::expect_success_and_text "oc get clusterroles --selector=foo=unknown" "No resources found" -os::cmd::expect_success "oc delete clusterrole/basic-user2" -os::test::junit::declare_suite_end -echo "admin-role-selectors: ok" - -os::test::junit::declare_suite_start "cmd/admin/ui-project-commands" -# Test the commands the UI projects page tells users to run -# These should match what is described in projects.html -os::cmd::expect_success 'oc adm new-project ui-test-project --admin="createuser"' -os::cmd::expect_success 'oc adm policy add-role-to-user --rolebinding-name=admin admin adduser -n ui-test-project' -# Make sure project can be listed by oc (after auth cache syncs) -os::cmd::try_until_text 'oc get projects' 'ui\-test\-project' -# Make sure users got added -os::cmd::expect_success_and_text "oc get rolebinding admin -n ui-test-project -o jsonpath='{.subjects[*].name}'" '^createuser adduser$' -echo "ui-project-commands: ok" -os::test::junit::declare_suite_end - -os::test::junit::declare_suite_start "cmd/admin/new-project" -# Test deleting and recreating a project -os::cmd::expect_success 'oc adm new-project recreated-project --admin="createuser1"' -os::cmd::expect_success 'oc delete project recreated-project' -os::cmd::try_until_failure 'oc get project recreated-project' -os::cmd::expect_success 'oc adm new-project recreated-project --admin="createuser2"' -os::cmd::expect_success_and_text "oc get rolebinding admin -n recreated-project -o jsonpath='{.subjects[*].name}'" '^createuser2$' -echo "new-project: ok" -os::test::junit::declare_suite_end +# Globals: +# - LOG_DIR +# Arguments: +# - 1: data file +# Returns: +# None +function os::log::system::internal::plot() { + local datafile=$1 + local plotname + plotname="$(basename "${datafile}" .txt)" -os::test::junit::declare_suite_start "cmd/admin/build-chain" -# Test building a dependency tree -os::cmd::expect_success 'oc process -f ${TEST_DATA}/application-template-stibuild.json -l build=sti | oc create -f -' -# Test both the type/name resource syntax and the fact that istag/origin-ruby-sample:latest is still -# not created but due to a buildConfig pointing to it, we get back its graph of deps. -os::cmd::expect_success_and_text 'oc adm build-chain istag/origin-ruby-sample' 'istag/origin-ruby-sample:latest' -os::cmd::expect_success_and_text 'oc adm build-chain ruby-27-centos7 -o dot' 'digraph "ruby-27-centos7:latest"' -os::cmd::expect_success 'oc delete all -l build=sti' -echo "ex build-chain: ok" -os::test::junit::declare_suite_end + # we are expecting the output of a 'sadf -d' read, so the headers will be on the first line of the file + local headers + headers=( $( head -n 1 "${datafile}" | sed 's/^# //g' | tr ';' ' ' ) ) -os::test::junit::declare_suite_start "cmd/admin/complex-scenarios" -# Make sure no one commits data with allocated values that could flake -os::cmd::expect_failure 'grep -r "clusterIP.*172" ${TEST_DATA}/app-scenarios' -os::cmd::expect_success 'oc adm new-project example --admin="createuser"' -os::cmd::expect_success 'oc project example' -os::cmd::try_until_success 'oc get serviceaccount default' -#os::cmd::expect_success 'oc create -f ${TEST_DATA}/app-scenarios' -os::cmd::expect_success 'oc status' -os::cmd::expect_success_and_text 'oc status -o dot' '"example"' -echo "complex-scenarios: ok" -os::test::junit::declare_suite_end + local records + local width + records="$(( $( wc -l < "${datafile}" ) - 1 ))" # one of these lines will be the header comment + if [[ "${records}" -gt 90 ]]; then + width="$(echo "8.5 + ${records}*0.025" | bc )" + else + width="8.5" + fi -os::test::junit::declare_suite_start "cmd/admin/rolebinding-allowed" -# Admin can bind local roles without cluster-admin permissions -#os::cmd::expect_success "oc create -f ${TEST_DATA}/roles/empty-role.yaml -n '${project}'" -#os::cmd::expect_success 'oc adm policy add-role-to-user admin local-admin -n '${project}'' -#os::cmd::expect_success 'oc login -u local-admin -p pw' -#os::cmd::expect_success 'oc policy add-role-to-user empty-role other --role-namespace='${project}' -n '${project}'' -#os::cmd::expect_success 'oc login -u system:admin' -#os::cmd::expect_success "oc delete role/empty-role -n '${project}'" -echo "cmd/admin/rolebinding-allowed: ok" -os::test::junit::declare_suite_end + local gnuplot_directive=( "set terminal pdf size ${width}in,$(( 2 * (${#headers[@]} - 1) ))in" \ + "set output \"${LOG_DIR}/${plotname}.pdf\"" \ + "set datafile separator \";\"" \ + "set xdata time" \ + "set timefmt '%Y-%m-%d %H:%M:%S UTC'" \ + "set tmargin 1" \ + "set bmargin 1" \ + "set lmargin 20" \ + "set rmargin 20" \ + "set multiplot layout ${#headers[@]},1 title \"\n${plotname}\n\"" \ + "unset title" ) -os::test::junit::declare_suite_start "cmd/admin/rolebinding-local-only" -# Admin cannot bind local roles from different namespace -otherproject='someotherproject' -#os::cmd::expect_success "oc new-project '${otherproject}'" -#os::cmd::expect_success "oc create -f ${TEST_DATA}/roles/empty-role.yaml -n '${project}'" -#os::cmd::expect_success 'oc adm policy add-role-to-user admin local-admin -n '${otherproject}'' -#os::cmd::expect_success 'oc login -u local-admin -p pw' -#os::cmd::expect_failure_and_text 'oc policy add-role-to-user empty-role other --role-namespace='${project}' -n '${otherproject}'' "role binding in namespace \"${otherproject}\" can't reference role in different namespace \"${project}\"" -#os::cmd::expect_success 'oc login -u system:admin' -#os::cmd::expect_success "oc delete role/empty-role -n '${project}'" -echo "rolebinding-local-only: ok" -os::test::junit::declare_suite_end + local i + for (( i = 1; i < "${#headers[@]}"; i++ )); do + local header + header="${headers[$i]}" -#os::test::junit::declare_suite_start "cmd/admin/user-group-cascade" -## Create test users/identities and groups -#os::cmd::expect_success 'oc login -u cascaded-user -p pw' -#os::cmd::expect_success 'oc login -u orphaned-user -p pw' -#os::cmd::expect_success 'oc login -u system:admin' -## switch to using --template once template printing is available to all cmds through the genericclioptions printer -#os::cmd::expect_success_and_text 'oc adm groups new cascaded-group cascaded-user orphaned-user -o yaml' '\- cascaded\-user' -## switch to using --template once template printing is available to all cmds through the genericclioptions printer -#os::cmd::expect_success_and_text 'oc adm groups new orphaned-group cascaded-user orphaned-user -o yaml' '\- orphaned\-user' -## Add roles, sccs to users/groups -#os::cmd::expect_success 'oc adm policy add-scc-to-user restricted cascaded-user orphaned-user' -#os::cmd::expect_success 'oc adm policy add-scc-to-group restricted cascaded-group orphaned-group' -#os::cmd::expect_success 'oc adm policy add-role-to-user --rolebinding-name=cluster-admin cluster-admin cascaded-user orphaned-user -n default' -#os::cmd::expect_success 'oc adm policy add-role-to-group --rolebinding-name=cluster-admin cluster-admin cascaded-group orphaned-group -n default' -#os::cmd::expect_success 'oc adm policy add-cluster-role-to-user --rolebinding-name=cluster-admin cluster-admin cascaded-user orphaned-user' -#os::cmd::expect_success 'oc adm policy add-cluster-role-to-group --rolebinding-name=cluster-admin cluster-admin cascaded-group orphaned-group' -# -## Delete users -#os::cmd::expect_success 'oc adm prune auth user/cascaded-user' -#os::cmd::expect_success 'oc delete user cascaded-user' -#os::cmd::expect_success 'oc delete user orphaned-user --cascade=false' -## Verify all identities remain -#os::cmd::expect_success 'oc get identities/alwaysallow:cascaded-user' -#os::cmd::expect_success 'oc get identities/alwaysallow:orphaned-user' -## Verify orphaned user references are left -#os::cmd::expect_success_and_text "oc get clusterrolebindings/cluster-admins clusterrolebindings/cluster-admin -o jsonpath='{ .items[*].subjects }'" 'orphaned-user' -#os::cmd::expect_success_and_text "oc get rolebindings/cluster-admin --template='{{.subjects}}' -n default" 'orphaned-user' -#os::cmd::expect_success_and_text "oc get scc/restricted --template='{{.users}}'" 'orphaned-user' -#os::cmd::expect_success_and_text "oc get group/cascaded-group --template='{{.users}}'" 'orphaned-user' -## Verify cascaded user references are removed -#os::cmd::expect_success_and_not_text "oc get clusterrolebindings/cluster-admins clusterrolebindings/cluster-admin -o jsonpath='{ .items[*].subjects }'" 'cascaded-user' -#os::cmd::expect_success_and_not_text "oc get rolebindings/cluster-admin --template='{{.subjects}}' -n default" 'cascaded-user' -#os::cmd::expect_success_and_not_text "oc get scc/restricted --template='{{.users}}'" 'cascaded-user' -#os::cmd::expect_success_and_not_text "oc get group/cascaded-group --template='{{.users}}'" 'cascaded-user' -# -## Delete groups -#os::cmd::expect_success "oc adm prune auth group/cascaded-group" -#os::cmd::expect_success 'oc delete group cascaded-group' -#os::cmd::expect_success 'oc delete group orphaned-group --cascade=false' -## Verify orphaned group references are left -#os::cmd::expect_success_and_text "oc get clusterrolebindings/cluster-admins clusterrolebindings/cluster-admin -o jsonpath='{ .items[*].subjects }'" 'orphaned-group' -#os::cmd::expect_success_and_text "oc get rolebindings/cluster-admin --template='{{.subjects}}' -n default" 'orphaned-group' -#os::cmd::expect_success_and_text "oc get scc/restricted --template='{{.groups}}'" 'orphaned-group' -## Verify cascaded group references are removed -#os::cmd::expect_success_and_not_text "oc get clusterrolebindings/cluster-admins clusterrolebindings/cluster-admin -o jsonpath='{ .items[*].subjects }'" 'cascaded-group' -#os::cmd::expect_success_and_not_text "oc get rolebindings/cluster-admin --template='{{.subjects}}' -n default" 'cascaded-group' -#os::cmd::expect_success_and_not_text "oc get scc/restricted --template='{{.groups}}'" 'cascaded-group' -#echo "user-group-cascade: ok" -#os::test::junit::declare_suite_end + if (( i == ${#headers[@]} - 1 )); then + # we need x-tick labels on the bottom plot + gnuplot_directive+=( "set xtics format '%H:%M:%S' rotate by -90" ) + else + gnuplot_directive+=( "set format x ''" ) + fi -os::test::junit::declare_suite_start "cmd/admin/serviceaccounts" -# create a new service account -os::cmd::expect_success_and_text 'oc create serviceaccount my-sa-name' 'serviceaccount/my-sa-name created' -os::cmd::expect_success 'oc get sa my-sa-name' + gnuplot_directive+=( "plot \"${datafile}\" using 1:$(( i + 1 )) title \"${header}\" with lines" ) + done -# extract token and ensure it links us back to the service account -os::cmd::try_until_success 'oc sa get-token my-sa-name' -# TODO re-enable once we can use tokens instead of certs -#os::cmd::expect_success_and_text 'oc get user/~ --token="$( oc sa get-token my-sa-name )"' 'system:serviceaccount:.+:my-sa-name' + # concatenate the array with newlines to get the final directive to send to gnuplot + gnuplot_directive="$( IFS=$'\n'; echo "${gnuplot_directive[*]}" )" -# add a new token and ensure it links us back to the service account -# TODO re-enable once we can use tokens instead of certs -#os::cmd::expect_success_and_text 'oc get user/~ --token="$( oc sa new-token my-sa-name )"' 'system:serviceaccount:.+:my-sa-name' + { + printf '$ gnuplot <<< %s\n' "${gnuplot_directive}" + gnuplot <<< "${gnuplot_directive}" 2>&1 + printf '\n\n' + } >> "${LOG_DIR}/gnuplot.log" -# add a new labeled token and ensure the label stuck -os::cmd::expect_success 'oc sa new-token my-sa-name --labels="mykey=myvalue,myotherkey=myothervalue"' -os::cmd::expect_success_and_text 'oc get secrets --selector="mykey=myvalue"' 'my-sa-name' -os::cmd::expect_success_and_text 'oc get secrets --selector="myotherkey=myothervalue"' 'my-sa-name' -os::cmd::expect_success_and_text 'oc get secrets --selector="mykey=myvalue,myotherkey=myothervalue"' 'my-sa-name' -echo "serviceacounts: ok" -os::test::junit::declare_suite_end + os::log::debug "Stacked plot for log subset \"${plotname}\" written to ${LOG_DIR}/${plotname}.pdf" +} +readonly -f os::log::system::internal::plot -# user creation -os::test::junit::declare_suite_start "cmd/admin/user-creation" -os::cmd::expect_success 'oc create user test-cmd-user' -os::cmd::expect_success 'oc create identity test-idp:test-uid' -os::cmd::expect_success 'oc create useridentitymapping test-idp:test-uid test-cmd-user' -os::cmd::expect_success_and_text 'oc describe identity test-idp:test-uid' 'test-cmd-user' -os::cmd::expect_success_and_text 'oc describe user test-cmd-user' 'test-idp:test-uid' -os::test::junit::declare_suite_end +# os::log::system::start installs the system logger and begins logging +# +# Globals: +# - LOG_DIR +# Arguments: +# None +# Returns: +# - export LOGGER_PID +# - export SAR_LOGFILE +function os::log::system::start() { + if ! which sar >/dev/null 2>&1; then + os::log::debug "System logger could not be started, 'sar' binary not found in this environment." + return 0 + fi -# images -os::test::junit::declare_suite_start "cmd/admin/images" + readonly SAR_LOGFILE="${LOG_DIR}/sar.log" + export SAR_LOGFILE -# import image and check its information -os::cmd::expect_success "oc create -f ${TEST_DATA}/stable-busybox.yaml" -os::cmd::expect_success_and_text "oc adm top images" "sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6\W+default/busybox \(latest\)\W+\W+\W+yes\W+653\.4KiB" -os::cmd::expect_success_and_text "oc adm top imagestreams" "default/busybox\W+653\.4KiB\W+1\W+1" -os::cmd::expect_success "oc delete is/busybox -n default" + os::log::system::internal::run "${SAR_LOGFILE}" "${LOG_DIR}/sar_stderr.log" -# log in as an image-pruner and test that oc adm prune images works against the atomic binary -#os::cmd::expect_success "oc adm policy add-cluster-role-to-user system:image-pruner pruner --config='${MASTER_CONFIG_DIR}/admin.kubeconfig'" -#os::cmd::expect_success "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${MASTER_CONFIG_DIR}/server-ca.crt' -u pruner -p anything" -#os::cmd::expect_success_and_text "oc adm prune images" "Dry run enabled - no modifications will be made. Add --confirm to remove images" + os::log::system::install_cleanup +} +readonly -f os::log::system::start -echo "images: ok" -os::test::junit::declare_suite_end +# os::log::system::internal::run runs the system logger in the background. +# 'sar' is configured to run once a second for 24 hours, so the cleanup trap should be installed to ensure that +# the process is killed once the parent script is finished. +# +# Globals: +# None +# Arguments: +# - 1: file to log binary outut to +# - 2: file to log stderr of the logger to +# Returns: +# None +function os::log::system::internal::run() { + local binary_logfile=$1 + local stderr_logfile=$2 -# oc adm must-gather -os::test::junit::declare_suite_start "cmd/admin/must-gather" -os::cmd::expect_success "oc adm must-gather --help" -os::test::junit::declare_suite_end + sar -A -o "${binary_logfile}" 1 86400 1>/dev/null 2>"${stderr_logfile}" & -os::test::junit::declare_suite_end + LOGGER_PID=$! + readonly LOGGER_PID + export LOGGER_PID +} +readonly -f os::log::system::internal::run `) -func testExtendedTestdataCmdTestCmdAdminShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdAdminSh, nil +func testExtendedTestdataCmdHackLibLogSystemShBytes() ([]byte, error) { + return _testExtendedTestdataCmdHackLibLogSystemSh, nil } -func testExtendedTestdataCmdTestCmdAdminSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdAdminShBytes() +func testExtendedTestdataCmdHackLibLogSystemSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdHackLibLogSystemShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/admin.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/log/system.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdAnnotationsSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT +var _testExtendedTestdataCmdHackLibTestJunitSh = []byte(`#!/usr/bin/env bash +# This utility file contains functions that format test output to be parsed into jUnit XML -# Cleanup cluster resources created by this test -( - set +e - oc delete all,templates --all - exit 0 -) &>/dev/null +# os::test::junit::declare_suite_start prints a message declaring the start of a test suite +# Any number of suites can be in flight at any time, so there is no failure condition for this +# script based on the number of suites in flight. +# +# Globals: +# - JUNIT_REPORT_OUTPUT +# - NUM_OS_JUNIT_SUITES_IN_FLIGHT +# Arguments: +# - 1: the suite name that is starting +# Returns: +# - increment NUM_OS_JUNIT_SUITES_IN_FLIGHT +function os::test::junit::declare_suite_start() { + local suite_name=$1 + local num_suites=${NUM_OS_JUNIT_SUITES_IN_FLIGHT:-0} + echo "=== BEGIN TEST SUITE github.com/openshift/origin/test/${suite_name} ===" >> "${JUNIT_REPORT_OUTPUT:-/dev/null}" + NUM_OS_JUNIT_SUITES_IN_FLIGHT=$(( ${num_suites} + 1 )) + export NUM_OS_JUNIT_SUITES_IN_FLIGHT +} +readonly -f os::test::junit::declare_suite_start -os::test::junit::declare_suite_start "cmd/annotate" -# This test validates empty values in key-value pairs set by the annotate command -os::cmd::expect_success_and_text 'oc create -f ${TEST_DATA}/hello-openshift/hello-pod.json' 'pod/hello-openshift created' -os::cmd::expect_success_and_text 'oc annotate pod hello-openshift node-selector=""' 'pod/hello-openshift annotated' -os::cmd::expect_success_and_not_text 'oc get pod hello-openshift --template="{{index .metadata.annotations \"node-selector\"}}"' '.' +# os::test::junit::declare_suite_end prints a message declaring the end of a test suite +# If there aren't any suites in flight, this function will fail. +# +# Globals: +# - JUNIT_REPORT_OUTPUT +# - NUM_OS_JUNIT_SUITES_IN_FLIGHT +# Arguments: +# - 1: the suite name that is starting +# Returns: +# - export/decrement NUM_OS_JUNIT_SUITES_IN_FLIGHT +function os::test::junit::declare_suite_end() { + local num_suites=${NUM_OS_JUNIT_SUITES_IN_FLIGHT:-0} + if [[ "${num_suites}" -lt "1" ]]; then + # we can't end a suite if none have been started yet + echo "[ERROR] jUnit suite marker could not be placed, expected suites in flight, got ${num_suites}" + return 1 + fi -echo "annotate: ok" -os::test::junit::declare_suite_end + echo "=== END TEST SUITE ===" >> "${JUNIT_REPORT_OUTPUT:-/dev/null}" + NUM_OS_JUNIT_SUITES_IN_FLIGHT=$(( ${num_suites} - 1 )) + export NUM_OS_JUNIT_SUITES_IN_FLIGHT +} +readonly -f os::test::junit::declare_suite_end -os::test::junit::declare_suite_start "cmd/label" -# This test validates empty values in key-value pairs set by the label command -os::cmd::expect_success_and_text 'oc label pod hello-openshift label2=""' 'pod/hello-openshift labeled' -os::cmd::expect_success_and_not_text 'oc get pod hello-openshift --template="{{.metadata.labels.label2}}"' '.' +# os::test::junit::declare_test_start prints a message declaring the start of a test case +# If there is already a test marked as being in flight, this function will fail. +# +# Globals: +# - JUNIT_REPORT_OUTPUT +# - NUM_OS_JUNIT_TESTS_IN_FLIGHT +# Arguments: +# None +# Returns: +# - increment NUM_OS_JUNIT_TESTS_IN_FLIGHT +function os::test::junit::declare_test_start() { + local num_tests=${NUM_OS_JUNIT_TESTS_IN_FLIGHT:-0} + if [[ "${num_tests}" -ne "0" ]]; then + # someone's declaring the starting of a test when a test is already in flight + echo "[ERROR] jUnit test marker could not be placed, expected no tests in flight, got ${num_tests}" + return 1 + fi -echo "label: ok" -os::test::junit::declare_suite_end -`) + local num_suites=${NUM_OS_JUNIT_SUITES_IN_FLIGHT:-0} + if [[ "${num_suites}" -lt "1" ]]; then + # we can't end a test if no suites are in flight + echo "[ERROR] jUnit test marker could not be placed, expected suites in flight, got ${num_suites}" + return 1 + fi -func testExtendedTestdataCmdTestCmdAnnotationsShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdAnnotationsSh, nil + echo "=== BEGIN TEST CASE ===" >> "${JUNIT_REPORT_OUTPUT:-/dev/null}" + NUM_OS_JUNIT_TESTS_IN_FLIGHT=$(( ${num_tests} + 1 )) + export NUM_OS_JUNIT_TESTS_IN_FLIGHT } +readonly -f os::test::junit::declare_test_start -func testExtendedTestdataCmdTestCmdAnnotationsSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdAnnotationsShBytes() - if err != nil { - return nil, err - } +# os::test::junit::declare_test_end prints a message declaring the end of a test case +# If there is no test marked as being in flight, this function will fail. +# +# Globals: +# - JUNIT_REPORT_OUTPUT +# - NUM_OS_JUNIT_TESTS_IN_FLIGHT +# Arguments: +# None +# Returns: +# - decrement NUM_OS_JUNIT_TESTS_IN_FLIGHT +function os::test::junit::declare_test_end() { + local num_tests=${NUM_OS_JUNIT_TESTS_IN_FLIGHT:-0} + if [[ "${num_tests}" -ne "1" ]]; then + # someone's declaring the end of a test when a test is not in flight + echo "[ERROR] jUnit test marker could not be placed, expected one test in flight, got ${num_tests}" + return 1 + fi - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/annotations.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil + echo "=== END TEST CASE ===" >> "${JUNIT_REPORT_OUTPUT:-/dev/null}" + NUM_OS_JUNIT_TESTS_IN_FLIGHT=$(( ${num_tests} - 1 )) + export NUM_OS_JUNIT_TESTS_IN_FLIGHT } +readonly -f os::test::junit::declare_test_end -var _testExtendedTestdataCmdTestCmdApiresourcesSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT +# os::test::junit::check_test_counters checks that we do not have any test suites or test cases in flight +# This function should be called at the very end of any test script using jUnit markers to make sure no error in +# marking has occurred. +# +# Globals: +# - NUM_OS_JUNIT_SUITES_IN_FLIGHT +# - NUM_OS_JUNIT_TESTS_IN_FLIGHT +# Arguments: +# None +# Returns: +# None +function os::test::junit::check_test_counters() { + if [[ "${NUM_OS_JUNIT_SUITES_IN_FLIGHT-}" -ne "0" ]]; then + echo "[ERROR] Expected no test suites to be marked as in-flight at the end of testing, got ${NUM_OS_JUNIT_SUITES_IN_FLIGHT-}" + return 1 + elif [[ "${NUM_OS_JUNIT_TESTS_IN_FLIGHT-}" -ne "0" ]]; then + echo "[ERROR] Expected no test cases to be marked as in-flight at the end of testing, got ${NUM_OS_JUNIT_TESTS_IN_FLIGHT-}" + return 1 + fi +} +readonly -f os::test::junit::check_test_counters -os::test::junit::declare_suite_start "cmd/apiresources" +# os::test::junit::reconcile_output appends the necessary suite and test end statements to the jUnit output file +# in order to ensure that the file is in a consistent state to allow for parsing +# +# Globals: +# - NUM_OS_JUNIT_SUITES_IN_FLIGHT +# - NUM_OS_JUNIT_TESTS_IN_FLIGHT +# Arguments: +# None +# Returns: +# None +function os::test::junit::reconcile_output() { + if [[ "${NUM_OS_JUNIT_TESTS_IN_FLIGHT:-0}" = "1" ]]; then + os::test::junit::declare_test_end + fi -os::cmd::expect_success_and_text 'oc api-resources' 'imagestreamtags' -os::cmd::expect_success_and_text 'oc api-resources --api-group=build.openshift.io' 'BuildConfig' -os::cmd::expect_success_and_text 'oc api-resources --namespaced=false' 'Image' -os::cmd::expect_success_and_text 'oc api-resources --verbs=get' 'project.openshift.io' + for (( i = 0; i < ${NUM_OS_JUNIT_SUITES_IN_FLIGHT:-0}; i++ )); do + os::test::junit::declare_suite_end + done +} +readonly -f os::test::junit::reconcile_output -os::cmd::expect_success_and_text 'oc api-versions' 'route.openshift.io/v1' +# os::test::junit::generate_report determines which type of report is to +# be generated and does so from the raw output of the tests. +# +# Globals: +# - JUNIT_REPORT_OUTPUT +# - ARTIFACT_DIR +# Arguments: +# None +# Returns: +# None +function os::test::junit::generate_report() { + if [[ -z "${JUNIT_REPORT_OUTPUT:-}" || + -n "${JUNIT_REPORT_OUTPUT:-}" && ! -s "${JUNIT_REPORT_OUTPUT:-}" ]]; then + # we can't generate a report + return 0 + fi -echo "apiresources: ok" -os::test::junit::declare_suite_end -`) + if grep -q "=== END TEST CASE ===" "${JUNIT_REPORT_OUTPUT}"; then + os::test::junit::reconcile_output + os::test::junit::check_test_counters + os::test::junit::internal::generate_report "oscmd" + fi +} -func testExtendedTestdataCmdTestCmdApiresourcesShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdApiresourcesSh, nil +# os::test::junit::internal::generate_report generats an XML jUnit +# report for either ` + "`" + `os::cmd` + "`" + ` or ` + "`" + `go test` + "`" + `, based on the passed +# argument. If the ` + "`" + `junitreport` + "`" + ` binary is not present, it will be built. +# +# Globals: +# - JUNIT_REPORT_OUTPUT +# - ARTIFACT_DIR +# Arguments: +# - 1: specify which type of tests command output should junitreport read +# Returns: +# export JUNIT_REPORT_NUM_FAILED +function os::test::junit::internal::generate_report() { + local report_type="$1" + os::util::ensure::built_binary_exists 'junitreport' + + local report_file + report_file="$( mktemp "${ARTIFACT_DIR}/${report_type}_report_XXXXX" ).xml" + os::log::info "jUnit XML report placed at $( os::util::repository_relative_path ${report_file} )" + junitreport --type "${report_type}" \ + --suites nested \ + --roots github.com/openshift/origin \ + --output "${report_file}" \ + <"${JUNIT_REPORT_OUTPUT}" + + local summary + summary=$( junitreport summarize <"${report_file}" ) + + JUNIT_REPORT_NUM_FAILED="$( grep -oE "[0-9]+ failed" <<<"${summary}" )" + export JUNIT_REPORT_NUM_FAILED + + echo "${summary}" +}`) + +func testExtendedTestdataCmdHackLibTestJunitShBytes() ([]byte, error) { + return _testExtendedTestdataCmdHackLibTestJunitSh, nil } -func testExtendedTestdataCmdTestCmdApiresourcesSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdApiresourcesShBytes() +func testExtendedTestdataCmdHackLibTestJunitSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdHackLibTestJunitShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/apiresources.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/test/junit.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdAuthenticationSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT - -project="$( oc project -q )" -if [[ "${project}" == "default" ]]; then - echo "Test must be run from a non-default namespace" - exit 1 -fi - -# Cleanup cluster resources created by this test -( - set +e - oc delete oauthaccesstokens --all - oc adm policy remove-cluster-role-from-user cluster-debugger user3 - exit 0 -) &>/dev/null +var _testExtendedTestdataCmdHackLibUtilEnvironmentSh = []byte(`#!/usr/bin/env bash -os::test::junit::declare_suite_start "cmd/authentication" +# This script holds library functions for setting up the shell environment for OpenShift scripts -## Logging in prints useful messages -#os::test::junit::declare_suite_start "cmd/authentication/existing-credentials" -#os::cmd::expect_success_and_text 'oc login -u user1 -p pw' 'Login successful' -#os::cmd::expect_success_and_text 'oc login -u user2 -p pw' 'Login successful' -## Switching to another user using existing credentials informs you -#os::cmd::expect_success_and_text 'oc login -u user1' 'Logged into ".*" as "user1" using existing credentials' -## Completing a login as the same user using existing credentials informs you -#os::cmd::expect_success_and_text 'oc login -u user1' 'Logged into ".*" as "user1" using existing credentials' -## Return to the system:admin user -#os::cmd::expect_success "oc login -u system:admin -n '${project}'" -#os::test::junit::declare_suite_end -# -#os::test::junit::declare_suite_start "cmd/authentication/scopedtokens" -#os::cmd::expect_success 'oc adm policy add-role-to-user admin scoped-user' -# -## initialize the user object -#os::cmd::expect_success 'oc login -u scoped-user -p asdf' -#os::cmd::expect_success 'oc login -u system:admin' -#username="$(oc get user/scoped-user -o jsonpath='{.metadata.name}')" -#useruid="$(oc get user/scoped-user -o jsonpath='{.metadata.uid}')" -#os::cmd::expect_success_and_text "oc policy can-i --list -n '${project}' --as=scoped-user" 'get.*pods' -#os::cmd::expect_success "oc policy can-i --list --output=yaml" -#os::cmd::expect_success "oc policy can-i --list --output=json" -#os::cmd::expect_success "oc policy can-i --list" -# -#whoamitoken="$(oc process -f "${OS_ROOT}/test/testdata/authentication/scoped-token-template.yaml" TOKEN_PREFIX=whoami SCOPE=user:info USER_NAME="${username}" USER_UID="${useruid}" | oc create -f - -o name | awk -F/ '{print $2}')" -#os::cmd::expect_success_and_text "oc get user/~ --token='${whoamitoken}'" "${username}" -#os::cmd::expect_success_and_text "oc whoami --token='${whoamitoken}'" "${username}" -#os::cmd::expect_failure_and_text "oc get pods --token='${whoamitoken}' -n '${project}'" "pods is forbidden: User \"scoped-user\" cannot list resource \"pods\" in API group \"\" in the namespace \"${project}\"" -# -#listprojecttoken="$(oc process -f "${OS_ROOT}/test/testdata/authentication/scoped-token-template.yaml" TOKEN_PREFIX=listproject SCOPE=user:list-scoped-projects USER_NAME="${username}" USER_UID="${useruid}" | oc create -f - -o name | awk -F/ '{print $2}')" -## this token doesn't have rights to see any projects even though it can hit the list endpoint, so an empty list is correct -## we'll add another scope that allows listing all known projects even if this token has no other powers in them. -#os::cmd::expect_success_and_not_text "oc get projects --token='${listprojecttoken}'" "${project}" -#os::cmd::expect_failure_and_text "oc get user/~ --token='${listprojecttoken}'" 'User "scoped-user" cannot get resource "users" in API group "user.openshift.io" at the cluster scope' -#os::cmd::expect_failure_and_text "oc get pods --token='${listprojecttoken}' -n '${project}'" "User \"scoped-user\" cannot list resource \"pods\" in API group \"\" in the namespace \"${project}\"" -# -#listprojecttoken="$(oc process -f "${OS_ROOT}/test/testdata/authentication/scoped-token-template.yaml" TOKEN_PREFIX=listallprojects SCOPE=user:list-projects USER_NAME="${username}" USER_UID="${useruid}" | oc create -f - -o name | awk -F/ '{print $2}')" -#os::cmd::expect_success_and_text "oc get projects --token='${listprojecttoken}'" "${project}" +# os::util::environment::use_sudo updates $USE_SUDO to be 'true', so that later scripts choosing between +# execution using 'sudo' and execution without it chose to use 'sudo' # -#adminnonescalatingpowerstoken="$(oc process -f "${OS_ROOT}/test/testdata/authentication/scoped-token-template.yaml" TOKEN_PREFIX=admin SCOPE=role:admin:* USER_NAME="${username}" USER_UID="${useruid}" | oc create -f - -o name | awk -F/ '{print $2}')" -#os::cmd::expect_failure_and_text "oc get user/~ --token='${adminnonescalatingpowerstoken}'" 'User "scoped-user" cannot get resource "users" in API group "user.openshift.io" at the cluster scope' -#os::cmd::expect_failure_and_text "oc get secrets --token='${adminnonescalatingpowerstoken}' -n '${project}'" "User \"scoped-user\" cannot list resource \"secrets\" in API group \"\" in the namespace \"${project}\"" -#os::cmd::expect_success_and_text "oc get 'projects/${project}' --token='${adminnonescalatingpowerstoken}' -n '${project}'" "${project}" +# Globals: +# None +# Arguments: +# None +# Returns: +# - export USE_SUDO +function os::util::environment::use_sudo() { + USE_SUDO=true + export USE_SUDO +} +readonly -f os::util::environment::use_sudo + +# os::util::environment::setup_time_vars sets up environment variables that describe durations of time +# These variables can be used to specify times for other utility functions # -#allescalatingpowerstoken="$(oc process -f "${OS_ROOT}/test/testdata/authentication/scoped-token-template.yaml" TOKEN_PREFIX=clusteradmin SCOPE='role:cluster-admin:*:!' USER_NAME="${username}" USER_UID="${useruid}" | oc create -f - -o name | awk -F/ '{print $2}')" -#os::cmd::expect_success_and_text "oc get user/~ --token='${allescalatingpowerstoken}'" "${username}" -#os::cmd::expect_success "oc get secrets --token='${allescalatingpowerstoken}' -n '${project}'" -## scopes allow it, but authorization doesn't -#os::cmd::try_until_failure "oc get secrets --token='${allescalatingpowerstoken}' -n default" -#os::cmd::expect_failure_and_text "oc get secrets --token='${allescalatingpowerstoken}' -n default" 'cannot list resource "secrets" in API group "" in the namespace' -#os::cmd::expect_success_and_text "oc get projects --token='${allescalatingpowerstoken}'" "${project}" -#os::cmd::expect_success_and_text "oc policy can-i --list --token='${allescalatingpowerstoken}' -n '${project}'" 'get.*pods' +# Globals: +# None +# Arguments: +# None +# Returns: +# - export TIME_MS +# - export TIME_SEC +# - export TIME_MIN +function os::util::environment::setup_time_vars() { + TIME_MS=1 + export TIME_MS + TIME_SEC="$(( 1000 * ${TIME_MS} ))" + export TIME_SEC + TIME_MIN="$(( 60 * ${TIME_SEC} ))" + export TIME_MIN +} +readonly -f os::util::environment::setup_time_vars + +# os::util::environment::setup_all_server_vars sets up all environment variables necessary to configure and start an OpenShift server # -#accesstoken="$(oc process -f "${OS_ROOT}/test/testdata/authentication/scoped-token-template.yaml" TOKEN_PREFIX=access SCOPE=user:check-access USER_NAME="${username}" USER_UID="${useruid}" | oc create -f - -o name | awk -F/ '{print $2}')" -#os::cmd::expect_success_and_text "curl -k -XPOST -H 'Content-Type: application/json' -H 'Authorization: Bearer ${accesstoken}' '${API_SCHEME}://${API_HOST}:${API_PORT}/apis/authorization.openshift.io/v1/namespaces/${project}/localsubjectaccessreviews' -d '{\"kind\":\"LocalSubjectAccessReview\",\"apiVersion\":\"authorization.openshift.io/v1\",\"namespace\":\"${project}\",\"verb\":\"create\",\"resource\":\"pods\"}'" '"kind": "SubjectAccessReviewResponse"' -## verify group and kind defaulting works correctly -#os::cmd::expect_success_and_text "curl -k -XPOST -H 'Content-Type: application/json' -H 'Authorization: Bearer ${accesstoken}' '${API_SCHEME}://${API_HOST}:${API_PORT}/apis/authorization.openshift.io/v1/subjectaccessreviews' -d '{\"namespace\":\"${project}\",\"verb\":\"create\",\"resource\":\"pods\"}'" '"kind": "SubjectAccessReviewResponse"' -#os::cmd::expect_success_and_text "oc policy can-i create pods --token='${accesstoken}' -n '${project}' --ignore-scopes" 'yes' -#os::cmd::expect_success_and_text "oc policy can-i create pods --token='${accesstoken}' -n '${project}'" 'no' -#os::cmd::expect_success_and_text "oc policy can-i create subjectaccessreviews.authorization.openshift.io --token='${accesstoken}' -n '${project}'" 'no' -#os::cmd::expect_success_and_text "oc policy can-i create subjectaccessreviews.authorization.openshift.io --token='${accesstoken}' -n '${project}' --ignore-scopes" 'yes' -#os::cmd::expect_success_and_text "oc policy can-i create pods --token='${accesstoken}' -n '${project}' --scopes='role:admin:*'" 'yes' -#os::cmd::expect_success_and_text "oc policy can-i --list --token='${accesstoken}' -n '${project}' --scopes='role:admin:*'" 'get.*pods' -#os::cmd::expect_success_and_not_text "oc policy can-i --list --token='${accesstoken}' -n '${project}'" 'get.*pods' +# Globals: +# - OS_ROOT +# - PATH +# - TMPDIR +# - LOG_DIR +# - ARTIFACT_DIR +# - KUBELET_SCHEME +# - KUBELET_BIND_HOST +# - KUBELET_HOST +# - KUBELET_PORT +# - BASETMPDIR +# - ETCD_PORT +# - ETCD_PEER_PORT +# - API_BIND_HOST +# - API_HOST +# - API_PORT +# - API_SCHEME +# - PUBLIC_MASTER_HOST +# - USE_IMAGES +# Arguments: +# - 1: the path under the root temporary directory for OpenShift where these subdirectories should be made +# Returns: +# - export PATH +# - export BASETMPDIR +# - export LOG_DIR +# - export VOLUME_DIR +# - export ARTIFACT_DIR +# - export FAKE_HOME_DIR +# - export KUBELET_SCHEME +# - export KUBELET_BIND_HOST +# - export KUBELET_HOST +# - export KUBELET_PORT +# - export ETCD_PORT +# - export ETCD_PEER_PORT +# - export ETCD_DATA_DIR +# - export API_BIND_HOST +# - export API_HOST +# - export API_PORT +# - export API_SCHEME +# - export SERVER_CONFIG_DIR +# - export MASTER_CONFIG_DIR +# - export NODE_CONFIG_DIR +# - export USE_IMAGES +# - export TAG +function os::util::environment::setup_all_server_vars() { + os::util::environment::setup_kubelet_vars + os::util::environment::setup_etcd_vars + os::util::environment::setup_server_vars + os::util::environment::setup_images_vars +} +readonly -f os::util::environment::setup_all_server_vars + +# os::util::environment::update_path_var updates $PATH so that OpenShift binaries are available # -#os::test::junit::declare_suite_end +# Globals: +# - OS_ROOT +# - PATH +# Arguments: +# None +# Returns: +# - export PATH +function os::util::environment::update_path_var() { + local prefix + if os::util::find::system_binary 'go' >/dev/null 2>&1; then + prefix+="${OS_OUTPUT_BINPATH}/$(os::build::host_platform):" + fi + if [[ -n "${GOPATH:-}" ]]; then + prefix+="${GOPATH}/bin:" + fi + + PATH="${prefix:-}${PATH}" + export PATH +} +readonly -f os::util::environment::update_path_var + +# os::util::environment::setup_tmpdir_vars sets up temporary directory path variables # -#os::test::junit::declare_suite_start "cmd/authentication/debugging" -#os::cmd::expect_success_and_text 'oc login -u user3 -p pw' 'Login successful' -#os::cmd::expect_success 'oc login -u system:admin' -#os::cmd::expect_failure_and_text 'oc get --raw /debug/pprof/ --as=user3' 'Forbidden' -#os::cmd::expect_failure_and_text 'oc get --raw /metrics --as=user3' 'Forbidden' -#os::cmd::expect_success_and_text 'oc get --raw /healthz --as=user3' 'ok' -#os::cmd::expect_success 'oc adm policy add-cluster-role-to-user cluster-debugger user3' -#os::cmd::try_until_text 'oc get --raw /debug/pprof/ --as=user3' 'full goroutine stack dump' -#os::cmd::expect_success_and_text 'oc get --raw /debug/pprof/ --as=user3' 'full goroutine stack dump' -#os::cmd::expect_success_and_text 'oc get --raw /metrics --as=user3' 'apiserver_request_latencies' -#os::cmd::expect_success_and_text 'oc get --raw /healthz --as=user3' 'ok' -## TODO validate controller -#os::test::junit::declare_suite_end +# Globals: +# - TMPDIR +# Arguments: +# - 1: the path under the root temporary directory for OpenShift where these subdirectories should be made +# Returns: +# - export BASETMPDIR +# - export BASEOUTDIR +# - export LOG_DIR +# - export VOLUME_DIR +# - export ARTIFACT_DIR +# - export FAKE_HOME_DIR +# - export OS_TMP_ENV_SET +function os::util::environment::setup_tmpdir_vars() { + local sub_dir=$1 -os::test::junit::declare_suite_start "cmd/authentication/scopedtokens" + BASETMPDIR="${TMPDIR:-/tmp}/openshift/${sub_dir}" + export BASETMPDIR + VOLUME_DIR="${BASETMPDIR}/volumes" + export VOLUME_DIR + BASEOUTDIR="${OS_OUTPUT_SCRIPTPATH}/${sub_dir}" + export BASEOUTDIR + LOG_DIR="${ARTIFACT_DIR:-${BASEOUTDIR}}/logs" + export LOG_DIR + ARTIFACT_DIR="${ARTIFACT_DIR:-${BASEOUTDIR}/artifacts}" + export ARTIFACT_DIR + FAKE_HOME_DIR="${BASEOUTDIR}/openshift.local.home" + export FAKE_HOME_DIR -os::test::junit::declare_suite_end -`) + mkdir -p "${LOG_DIR}" "${VOLUME_DIR}" "${ARTIFACT_DIR}" "${FAKE_HOME_DIR}" -func testExtendedTestdataCmdTestCmdAuthenticationShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdAuthenticationSh, nil + export OS_TMP_ENV_SET="${sub_dir}" } +readonly -f os::util::environment::setup_tmpdir_vars -func testExtendedTestdataCmdTestCmdAuthenticationSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdAuthenticationShBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/authentication.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil +# os::util::environment::setup_kubelet_vars sets up environment variables necessary for interacting with the kubelet +# +# Globals: +# - KUBELET_SCHEME +# - KUBELET_BIND_HOST +# - KUBELET_HOST +# - KUBELET_PORT +# Arguments: +# None +# Returns: +# - export KUBELET_SCHEME +# - export KUBELET_BIND_HOST +# - export KUBELET_HOST +# - export KUBELET_PORT +function os::util::environment::setup_kubelet_vars() { + KUBELET_SCHEME="${KUBELET_SCHEME:-https}" + export KUBELET_SCHEME + KUBELET_BIND_HOST="${KUBELET_BIND_HOST:-127.0.0.1}" + export KUBELET_BIND_HOST + KUBELET_HOST="${KUBELET_HOST:-${KUBELET_BIND_HOST}}" + export KUBELET_HOST + KUBELET_PORT="${KUBELET_PORT:-10250}" + export KUBELET_PORT } +readonly -f os::util::environment::setup_kubelet_vars -var _testExtendedTestdataCmdTestCmdBasicresourcesSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT +# os::util::environment::setup_etcd_vars sets up environment variables necessary for interacting with etcd +# +# Globals: +# - BASETMPDIR +# - ETCD_HOST +# - ETCD_PORT +# - ETCD_PEER_PORT +# Arguments: +# None +# Returns: +# - export ETCD_HOST +# - export ETCD_PORT +# - export ETCD_PEER_PORT +# - export ETCD_DATA_DIR +function os::util::environment::setup_etcd_vars() { + ETCD_HOST="${ETCD_HOST:-127.0.0.1}" + export ETCD_HOST + ETCD_PORT="${ETCD_PORT:-4001}" + export ETCD_PORT + ETCD_PEER_PORT="${ETCD_PEER_PORT:-7001}" + export ETCD_PEER_PORT -# Cleanup cluster resources created by this test -( - set +e - oc delete all,templates,secrets,pods,jobs --all - oc delete image v1-image - oc delete group patch-group - oc delete project test-project-admin - oc delete oauthaccesstokens.oauth.openshift.io/DYGZDLucARCPIfUeKPhsgPfn0WBLR_9KdeREH0c9iod - oc delete -f ${TEST_DATA}/multiport-service.yaml - exit 0 -) &>/dev/null + ETCD_DATA_DIR="${BASETMPDIR}/etcd" + export ETCD_DATA_DIR -function escape_regex() { - sed 's/[]\.|$(){}?+*^]/\\&/g' <<< "$*" + mkdir -p "${ETCD_DATA_DIR}" } +readonly -f os::util::environment::setup_etcd_vars -project="$( oc project -q )" +# os::util::environment::setup_server_vars sets up environment variables necessary for interacting with the server +# +# Globals: +# - BASETMPDIR +# - KUBELET_HOST +# - API_BIND_HOST +# - API_HOST +# - API_PORT +# - API_SCHEME +# - PUBLIC_MASTER_HOST +# Arguments: +# None +# Returns: +# - export API_BIND_HOST +# - export API_HOST +# - export API_PORT +# - export API_SCHEME +# - export SERVER_CONFIG_DIR +# - export MASTER_CONFIG_DIR +# - export NODE_CONFIG_DIR +function os::util::environment::setup_server_vars() { + # turn on cache mutation detector every time we start a server + KUBE_CACHE_MUTATION_DETECTOR="${KUBE_CACHE_MUTATION_DETECTOR:-true}" + export KUBE_CACHE_MUTATION_DETECTOR -os::test::junit::declare_suite_start "cmd/basicresources" -# This test validates basic resource retrieval and command interaction + API_BIND_HOST="${API_BIND_HOST:-127.0.0.1}" + export API_BIND_HOST + API_HOST="${API_HOST:-${API_BIND_HOST}}" + export API_HOST + API_PORT="${API_PORT:-8443}" + export API_PORT + API_SCHEME="${API_SCHEME:-https}" + export API_SCHEME -os::test::junit::declare_suite_start "cmd/basicresources/versionreporting" -# Test to make sure that we're reporting the correct version information from endpoints and the correct -# User-Agent information from our clients regardless of which resources they're trying to access -#os::build::version::get_vars -#os_git_regex="$( escape_regex "${OS_GIT_VERSION%%-*}" )" -#kube_git_regex="$( escape_regex "${KUBE_GIT_VERSION%%-*}" )" -#etcd_version="$(echo "${ETCD_GIT_VERSION}" | sed -E "s/\-.*//g" | sed -E "s/v//")" -#etcd_git_regex="$( escape_regex "${etcd_version%%-*}" )" -#os::cmd::expect_success_and_text 'oc version' "Client Version: .*GitVersion:\"${os_git_regex}" -#os::cmd::expect_success_and_text 'oc version' "Server Version: .*GitVersion:\"${kube_git_regex}" -#os::cmd::expect_success_and_text "curl -k '${API_SCHEME}://${API_HOST}:${API_PORT}/version'" "${kube_git_regex}" -#os::cmd::expect_success_and_text "curl -k '${API_SCHEME}://${API_HOST}:${API_PORT}/version'" "${OS_GIT_COMMIT}" + MASTER_ADDR="${API_SCHEME}://${API_HOST}:${API_PORT}" + export MASTER_ADDR + PUBLIC_MASTER_HOST="${PUBLIC_MASTER_HOST:-${API_HOST}}" + export PUBLIC_MASTER_HOST -# variants I know I have to worry about -# 1. oc (kube and openshift resources) -# 2. oc adm (kube and openshift resources) + SERVER_CONFIG_DIR="${BASETMPDIR}/openshift.local.config" + export SERVER_CONFIG_DIR + MASTER_CONFIG_DIR="${SERVER_CONFIG_DIR}/master" + export MASTER_CONFIG_DIR + NODE_CONFIG_DIR="${SERVER_CONFIG_DIR}/node-${KUBELET_HOST}" + export NODE_CONFIG_DIR -# example User-Agent: oc/v1.2.0 (linux/amd64) kubernetes/bc4550d -#os::cmd::expect_success_and_text 'oc get pods --loglevel=7 2>&1 | grep -A4 "pods" | grep User-Agent' "oc/${kube_git_regex} .* kubernetes/" -## example User-Agent: oc/v1.2.0 (linux/amd64) kubernetes/bc4550d -#os::cmd::expect_success_and_text 'oc get dc --loglevel=7 2>&1 | grep -A4 "deploymentconfig" | grep User-Agent' "oc/${kube_git_regex} .* kubernetes/" -## example User-Agent: oc/v1.1.3 (linux/amd64) openshift/b348c2f -#os::cmd::expect_success_and_text 'oc adm policy who-can get pods --loglevel=7 2>&1 | grep -A4 "localresourceaccessreviews" | grep User-Agent' "oc/${kube_git_regex} .* kubernetes/" -#echo "version reporting: ok" -os::test::junit::declare_suite_end + ETCD_CLIENT_CERT="${MASTER_CONFIG_DIR}/master.etcd-client.crt" + export ETCD_CLIENT_CERT + ETCD_CLIENT_KEY="${MASTER_CONFIG_DIR}/master.etcd-client.key" + export ETCD_CLIENT_KEY + ETCD_CA_BUNDLE="${MASTER_CONFIG_DIR}/ca-bundle.crt" + export ETCD_CA_BUNDLE -os::test::junit::declare_suite_start "cmd/basicresources/status" -os::cmd::expect_success_and_text 'oc status -h' 'oc describe buildconfig' -os::cmd::expect_success_and_text 'oc status' 'oc new-app' -echo "status help output: ok" -os::test::junit::declare_suite_end + mkdir -p "${SERVER_CONFIG_DIR}" "${MASTER_CONFIG_DIR}" "${NODE_CONFIG_DIR}" +} +readonly -f os::util::environment::setup_server_vars -os::test::junit::declare_suite_start "cmd/basicresources/explain" -os::cmd::expect_failure_and_text 'oc get' 'oc api-resources' -os::cmd::expect_success_and_text 'oc get all --loglevel=6' 'buildconfigs' -os::cmd::expect_success_and_text 'oc explain pods' 'Pod is a collection of containers that can run on a host' -os::cmd::expect_success_and_text 'oc explain pods.spec' 'SecurityContext holds pod-level security attributes' -# TODO unbreak explain -#os::cmd::expect_success_and_text 'oc explain deploymentconfig' 'a desired deployment state' -#os::cmd::expect_success_and_text 'oc explain deploymentconfig.spec' 'ensures that this deployment config will have zero replicas' -echo "explain: ok" -os::test::junit::declare_suite_end +# os::util::environment::setup_images_vars sets up environment variables necessary for interacting with release images +# +# Globals: +# - OS_ROOT +# - USE_IMAGES +# Arguments: +# None +# Returns: +# - export USE_IMAGES +# - export TAG +# - export MAX_IMAGES_BULK_IMPORTED_PER_REPOSITORY +function os::util::environment::setup_images_vars() { + # Use either the latest release built images, or latest. + IMAGE_PREFIX="${OS_IMAGE_PREFIX:-"openshift/origin"}" + if [[ -z "${USE_IMAGES-}" ]]; then + TAG='latest' + export TAG + USE_IMAGES="${IMAGE_PREFIX}-\${component}:latest" + export USE_IMAGES -os::test::junit::declare_suite_start "cmd/basicresources/resource-builder" -# Test resource builder filtering of files with expected extensions inside directories, and individual files without expected extensions -os::cmd::expect_success 'oc create -f ${TEST_DATA}/resource-builder/directory -f ${TEST_DATA}/resource-builder/json-no-extension -f ${TEST_DATA}/resource-builder/yml-no-extension' -# Explicitly specified extensionless files -os::cmd::expect_success 'oc get secret json-no-extension yml-no-extension' -# Scanned files with extensions inside directories -os::cmd::expect_success 'oc get secret json-with-extension yml-with-extension' -# Ensure extensionless files inside directories are not processed by resource-builder -os::cmd::expect_failure_and_text 'oc get secret json-no-extension-in-directory' 'not found' -echo "resource-builder: ok" -os::test::junit::declare_suite_end + if [[ -e "${OS_ROOT}/_output/local/releases/.commit" ]]; then + TAG="$(cat "${OS_ROOT}/_output/local/releases/.commit")" + export TAG + USE_IMAGES="${IMAGE_PREFIX}-\${component}:${TAG}" + export USE_IMAGES + fi + fi + export MAX_IMAGES_BULK_IMPORTED_PER_REPOSITORY="${MAX_IMAGES_BULK_IMPORTED_PER_REPOSITORY:-3}" +} +readonly -f os::util::environment::setup_images_vars +`) -os::test::junit::declare_suite_start "cmd/basicresources/pods" -os::cmd::expect_success 'oc get pods' -os::cmd::expect_success_and_text 'oc create -f ${TEST_DATA}/hello-openshift/hello-pod.json' 'pod/hello-openshift created' -os::cmd::expect_success 'oc describe pod hello-openshift' -os::cmd::expect_success 'oc delete pods hello-openshift --grace-period=0 --force' -echo "pods: ok" -os::test::junit::declare_suite_end +func testExtendedTestdataCmdHackLibUtilEnvironmentShBytes() ([]byte, error) { + return _testExtendedTestdataCmdHackLibUtilEnvironmentSh, nil +} -os::test::junit::declare_suite_start "cmd/basicresources/label" -os::cmd::expect_success_and_text 'oc create -f ${TEST_DATA}/hello-openshift/hello-pod.json -o name' 'pod/hello-openshift' -os::cmd::try_until_success 'oc label pod/hello-openshift acustom=label' # can race against scheduling and status updates -os::cmd::expect_success_and_text 'oc describe pod/hello-openshift' 'acustom=label' -os::cmd::try_until_success 'oc annotate pod/hello-openshift foo=bar' # can race against scheduling and status updates -os::cmd::expect_success_and_text 'oc get -o yaml pod/hello-openshift' 'foo: bar' -os::cmd::expect_failure_and_not_text 'oc annotate pod hello-openshift description="test" --resource-version=123' 'may only be used with a single resource' -os::cmd::expect_failure_and_text 'oc annotate pod hello-openshift hello-openshift description="test" --resource-version=123' 'may only be used with a single resource' -os::cmd::expect_success 'oc delete pods -l acustom=label --grace-period=0 --force' -os::cmd::expect_failure 'oc get pod/hello-openshift' +func testExtendedTestdataCmdHackLibUtilEnvironmentSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdHackLibUtilEnvironmentShBytes() + if err != nil { + return nil, err + } -# show-labels should work for projects -os::cmd::expect_success "oc label namespace '${project}' foo=bar" -os::cmd::expect_success_and_text "oc get project '${project}' --show-labels" "foo=bar" + info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/util/environment.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} -echo "label: ok" -os::test::junit::declare_suite_end +var _testExtendedTestdataCmdHackLibUtilMiscSh = []byte(`#!/usr/bin/env bash +# +# This library holds miscellaneous utility functions. If there begin to be groups of functions in this +# file that share intent or are thematically similar, they should be split into their own files. -os::test::junit::declare_suite_start "cmd/basicresources/services" -os::cmd::expect_success 'oc get services' -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-service.json' -os::cmd::expect_success 'oc delete services frontend' -# TODO: reenable with a permission check -# os::cmd::expect_failure_and_text 'oc create -f test/integration/testdata/test-service-with-finalizer.json' "finalizers are disabled" -echo "services: ok" -os::test::junit::declare_suite_end +# os::util::describe_return_code describes an exit code +# +# Globals: +# - OS_SCRIPT_START_TIME +# Arguments: +# - 1: exit code to describe +# Returns: +# None +function os::util::describe_return_code() { + local return_code=$1 + local message="$( os::util::repository_relative_path $0 ) exited with code ${return_code} " -# TODO rewrite the yaml for this test to actually work -os::test::junit::declare_suite_start "cmd/basicresources/list-version-conversion" -os::cmd::expect_success 'oc create -f ${TEST_DATA}/mixed-api-versions.yaml' -os::cmd::expect_success 'oc get -f ${TEST_DATA}/mixed-api-versions.yaml -o yaml' -os::cmd::expect_success 'oc label -f ${TEST_DATA}/mixed-api-versions.yaml mylabel=a' -os::cmd::expect_success 'oc annotate -f ${TEST_DATA}/mixed-api-versions.yaml myannotation=b' -# Make sure all six resources, with different API versions, got labeled and annotated -os::cmd::expect_success_and_text 'oc get -f ${TEST_DATA}/mixed-api-versions.yaml --output=jsonpath="{..metadata.labels.mylabel}"' '^a a a a$' -os::cmd::expect_success_and_text 'oc get -f ${TEST_DATA}/mixed-api-versions.yaml --output=jsonpath="{..metadata.annotations.myannotation}"' '^b b b b$' -os::cmd::expect_success 'oc delete -f ${TEST_DATA}/mixed-api-versions.yaml' -echo "list version conversion: ok" -os::test::junit::declare_suite_end + if [[ -n "${OS_SCRIPT_START_TIME:-}" ]]; then + local end_time + end_time="$(date +%s)" + local elapsed_time + elapsed_time="$(( end_time - OS_SCRIPT_START_TIME ))" + local formatted_time + formatted_time="$( os::util::format_seconds "${elapsed_time}" )" + message+="after ${formatted_time}" + fi -os::test::junit::declare_suite_start "cmd/basicresources/nodes" -os::cmd::expect_success 'oc get nodes' -( - # subshell so we can unset kubeconfig - cfg="${KUBECONFIG}" - unset KUBECONFIG - os::cmd::expect_success "kubectl get nodes --kubeconfig='${cfg}'" -) -echo "nodes: ok" -os::test::junit::declare_suite_end + if [[ "${return_code}" = "0" ]]; then + os::log::info "${message}" + else + os::log::error "${message}" + fi +} +readonly -f os::util::describe_return_code +# os::util::install_describe_return_code installs the return code describer for the EXIT trap +# If the EXIT trap is not initialized, installing this plugin will initialize it. +# +# Globals: +# None +# Arguments: +# None +# Returns: +# - export OS_DESCRIBE_RETURN_CODE +# - export OS_SCRIPT_START_TIME +function os::util::install_describe_return_code() { + export OS_DESCRIBE_RETURN_CODE="true" + OS_SCRIPT_START_TIME="$( date +%s )"; export OS_SCRIPT_START_TIME + os::util::trap::init_exit +} +readonly -f os::util::install_describe_return_code -os::test::junit::declare_suite_start "cmd/basicresources/create" -os::cmd::expect_success 'oc create dc my-nginx --image=nginx' -os::cmd::expect_success 'oc delete dc my-nginx' -os::cmd::expect_success 'oc create clusterquota limit-bob --project-label-selector=openshift.io/requester=user-bob --hard=pods=10' -os::cmd::expect_success 'oc delete clusterquota/limit-bob' -echo "create subcommands: ok" -os::test::junit::declare_suite_end +# OS_ORIGINAL_WD is the original working directory the script sourcing this utility file was called +# from. This is an important directory as if $0 is a relative path, we cannot use the following path +# utility without knowing from where $0 is relative. +if [[ -z "${OS_ORIGINAL_WD:-}" ]]; then + # since this could be sourced in a context where the utilities are already loaded, + # we want to ensure that this is re-entrant, so we only set $OS_ORIGINAL_WD if it + # is not set already + OS_ORIGINAL_WD="$( pwd )" + readonly OS_ORIGINAL_WD + export OS_ORIGINAL_WD +fi -os::test::junit::declare_suite_start "cmd/basicresources/statefulsets" -os::cmd::expect_success 'oc create -f ${TEST_DATA}/statefulset.yaml' -os::cmd::try_until_success 'oc get pods testapp-0' -os::cmd::expect_success_and_text 'oc describe statefulset testapp' 'app=testapp' -os::cmd::expect_success 'oc delete -f ${TEST_DATA}/statefulset.yaml' -echo "statefulsets: ok" -os::test::junit::declare_suite_end +# os::util::repository_relative_path returns the relative path from the $OS_ROOT directory to the +# given file, if the file is inside of the $OS_ROOT directory. If the file is outside of $OS_ROOT, +# this function will return the absolute path to the file +# +# Globals: +# - OS_ROOT +# Arguments: +# - 1: the path to relativize +# Returns: +# None +function os::util::repository_relative_path() { + local filename=$1 + local directory; directory="$( dirname "${filename}" )" + filename="$( basename "${filename}" )" + if [[ "${directory}" != "${OS_ROOT}"* ]]; then + pushd "${OS_ORIGINAL_WD}" >/dev/null 2>&1 + directory="$( os::util::absolute_path "${directory}" )" + popd >/dev/null 2>&1 + fi -os::test::junit::declare_suite_start "cmd/basicresources/setprobe" -# Validate the probe command -arg="-f ${TEST_DATA}/hello-openshift/hello-pod.json" -os::cmd::expect_failure_and_text "oc set probe" "error: one or more resources" -os::cmd::expect_failure_and_text "oc set probe ${arg}" "error: you must specify" -os::cmd::expect_failure_and_text "oc set probe ${arg} --local -o yaml --liveness --get-url=https://127.0.0.1/path" "port must be specified as part of a url" -os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness" 'livenessProbe: \{\}' -os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --initial-delay-seconds=10" "livenessProbe:" -os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --initial-delay-seconds=10" "initialDelaySeconds: 10" -os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness -- echo test" "livenessProbe:" -os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --readiness -- echo test" "readinessProbe:" -os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness -- echo test" "exec:" -os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness -- echo test" "\- echo" -os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness -- echo test" "\- test" -os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --open-tcp=3306" "tcpSocket:" -os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --open-tcp=3306" "port: 3306" -os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --open-tcp=port" "port: port" -os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --get-url=https://127.0.0.1:8080/path" "port: 8080" -os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --get-url=https://127.0.0.1:8080/path" "path: /path" -os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --get-url=https://127.0.0.1:8080/path" "scheme: HTTPS" -os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --get-url=http://127.0.0.1:8080/path" "scheme: HTTP" -os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --get-url=https://127.0.0.1:8080/path" "host: 127.0.0.1" -os::cmd::expect_success "oc create -f ${TEST_DATA}/test-deployment-config.yaml" -os::cmd::expect_failure_and_text "oc set probe dc/test-deployment-config --liveness" "Required value: must specify a handler type" -os::cmd::expect_success_and_text "oc set probe dc test-deployment-config --liveness --open-tcp=8080" "updated" -os::cmd::expect_success_and_text "oc set probe dc/test-deployment-config --liveness --open-tcp=8080 --v=1" "was not changed" -os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "livenessProbe:" -os::cmd::expect_success_and_text "oc set probe dc/test-deployment-config --liveness --initial-delay-seconds=10" "updated" -os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "initialDelaySeconds: 10" -os::cmd::expect_success_and_text "oc set probe dc/test-deployment-config --liveness --initial-delay-seconds=20" "updated" -os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "initialDelaySeconds: 20" -os::cmd::expect_success_and_text "oc set probe dc/test-deployment-config --liveness --failure-threshold=2" "updated" -os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "initialDelaySeconds: 20" -os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "failureThreshold: 2" -os::cmd::expect_success_and_text "oc set probe dc/test-deployment-config --readiness --success-threshold=4 -- echo test" "updated" -os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "initialDelaySeconds: 20" -os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "successThreshold: 4" -os::cmd::expect_success_and_text "oc set probe dc test-deployment-config --liveness --period-seconds=5" "updated" -os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "periodSeconds: 5" -os::cmd::expect_success_and_text "oc set probe dc/test-deployment-config --liveness --timeout-seconds=6" "updated" -os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "timeoutSeconds: 6" -os::cmd::expect_success_and_text "oc set probe dc --all --liveness --timeout-seconds=7" "updated" -os::cmd::expect_success_and_text "oc get dc -o yaml" "timeoutSeconds: 7" -os::cmd::expect_success_and_text "oc set probe dc/test-deployment-config --liveness --remove" "updated" -os::cmd::expect_success_and_not_text "oc get dc/test-deployment-config -o yaml" "livenessProbe" -os::cmd::expect_success "oc delete dc/test-deployment-config" -echo "set probe: ok" -os::test::junit::declare_suite_end + directory="${directory##*${OS_ROOT}/}" -os::test::junit::declare_suite_start "cmd/basicresources/setenv" -os::cmd::expect_success "oc create -f ${TEST_DATA}/test-deployment-config.yaml" -os::cmd::expect_success "oc create -f ${TEST_DATA}/test-buildcli.json" -os::cmd::expect_success_and_text "oc set env dc/test-deployment-config FOO=1st" "updated" -os::cmd::expect_success_and_text "oc set env dc/test-deployment-config FOO=2nd" "updated" -os::cmd::expect_success_and_text "oc set env dc/test-deployment-config FOO=bar --overwrite" "updated" -os::cmd::expect_failure_and_text "oc set env dc/test-deployment-config FOO=zee --overwrite=false" "already has a value" -os::cmd::expect_success_and_text "oc set env dc/test-deployment-config --list" "FOO=bar" -os::cmd::expect_success_and_text "oc set env dc/test-deployment-config FOO-" "updated" -os::cmd::expect_success_and_text "oc set env bc --all FOO=bar" "updated" -os::cmd::expect_success_and_text "oc set env bc --all --list" "FOO=bar" -os::cmd::expect_success_and_text "oc set env bc --all FOO-" "updated" -os::cmd::expect_success "oc create secret generic mysecret --from-literal='foo.bar=secret'" -os::cmd::expect_success_and_text "oc set env --from=secret/mysecret --prefix=PREFIX_ dc/test-deployment-config" "updated" -os::cmd::expect_success_and_text "oc set env dc/test-deployment-config --list" "PREFIX_FOO_BAR from secret mysecret, key foo.bar" -os::cmd::expect_success_and_text "oc set env dc/test-deployment-config --list --resolve" "PREFIX_FOO_BAR=secret" -os::cmd::expect_success "oc delete secret mysecret" -os::cmd::expect_failure_and_text "oc set env dc/test-deployment-config --list --resolve" "error retrieving reference for PREFIX_FOO_BAR" -# switch to view user to ensure view-only users can't get secrets through env var resolution -new="$(mktemp -d)/tempconfig" -os::cmd::expect_success "oc config view --raw > $new" -export KUBECONFIG=$new -project=$(oc project -q) -#os::cmd::expect_success 'oc policy add-role-to-user view view-user' -#os::cmd::expect_success 'oc login -u view-user -p anything' -#os::cmd::try_until_success 'oc project ${project}' -#os::cmd::expect_failure_and_text "oc set env dc/test-deployment-config --list --resolve" 'cannot get resource "secrets" in API group "" in the namespace' -#oc login -u system:admin -# clean up -os::cmd::expect_success "oc delete dc/test-deployment-config" -os::cmd::expect_success "oc delete bc/ruby-sample-build-validtag" -echo "set env: ok" -os::test::junit::declare_suite_end + echo "${directory}/${filename}" +} +readonly -f os::util::repository_relative_path -os::test::junit::declare_suite_start "cmd/basicresources/expose" -# Expose service as a route -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-service.json' -os::cmd::expect_failure 'oc expose service frontend --create-external-load-balancer' -os::cmd::expect_failure 'oc expose service frontend --port=40 --type=NodePort' -os::cmd::expect_success 'oc expose service frontend --path=/test' -os::cmd::expect_success_and_text "oc get route.v1.route.openshift.io frontend --template='{{.spec.path}}'" "/test" -os::cmd::expect_success_and_text "oc get route.v1.route.openshift.io frontend --template='{{.spec.to.name}}'" "frontend" # routes to correct service -os::cmd::expect_success_and_text "oc get route.v1.route.openshift.io frontend --template='{{.spec.port.targetPort}}'" "" -os::cmd::expect_success 'oc delete svc,route -l name=frontend' -# Test that external services are exposable -os::cmd::expect_success 'oc create -f ${TEST_DATA}/external-service.yaml' -os::cmd::expect_success 'oc expose svc/external' -os::cmd::expect_success_and_text 'oc get route external' 'external' -os::cmd::expect_success 'oc delete route external' -os::cmd::expect_success 'oc delete svc external' -# Expose multiport service and verify we set a port in the route -os::cmd::expect_success 'oc create -f ${TEST_DATA}/multiport-service.yaml' -os::cmd::expect_success 'oc expose svc/frontend --name route-with-set-port' -os::cmd::expect_success_and_text "oc get route route-with-set-port --template='{{.spec.port.targetPort}}'" "web" -echo "expose: ok" -os::test::junit::declare_suite_end +# os::util::format_seconds formats a duration of time in seconds to print in HHh MMm SSs +# +# Globals: +# None +# Arguments: +# - 1: time in seconds to format +# Return: +# None +function os::util::format_seconds() { + local raw_seconds=$1 -# Test OAuth access token describer -os::cmd::expect_success 'oc create -f ${TEST_DATA}/oauthaccesstoken.yaml' -os::cmd::expect_success_and_text "oc describe oauthaccesstoken DYGZDLucARCPIfUeKPhsgPfn0WBLR_9KdeREH0c9iod" "DYGZDLucARCPIfUeKPhsgPfn0WBLR_9KdeREH0c9iod" -echo "OAuth descriptor: ok" + local hours minutes seconds + (( hours=raw_seconds/3600 )) + (( minutes=(raw_seconds%3600)/60 )) + (( seconds=raw_seconds%60 )) + + printf '%02dh %02dm %02ds' "${hours}" "${minutes}" "${seconds}" +} +readonly -f os::util::format_seconds + +# os::util::sed attempts to make our Bash scripts agnostic to the platform +# on which they run ` + "`" + `sed` + "`" + ` by glossing over a discrepancy in flag use in GNU. +# +# Globals: +# None +# Arguments: +# - all: arguments to pass to ` + "`" + `sed -i` + "`" + ` +# Return: +# None +function os::util::sed() { + local sudo="${USE_SUDO:+sudo}" + if LANG=C sed --help 2>&1 | grep -q "GNU sed"; then + ${sudo} sed -i'' "$@" + else + ${sudo} sed -i '' "$@" + fi +} +readonly -f os::util::sed -os::cmd::expect_success 'oc delete all --all' +# os::util::base64decode attempts to make our Bash scripts agnostic to the platform +# on which they run ` + "`" + `base64decode` + "`" + ` by glossing over a discrepancy in flag use in GNU. +# +# Globals: +# None +# Arguments: +# - all: arguments to pass to ` + "`" + `base64decode` + "`" + ` +# Return: +# None +function os::util::base64decode() { + if [[ "$(go env GOHOSTOS)" == "darwin" ]]; then + base64 -D "$@" + else + base64 -d "$@" + fi +} +readonly -f os::util::base64decode -os::test::junit::declare_suite_start "cmd/basicresources/projectadmin" -# switch to test user to be sure that default project admin policy works properly -temp_config="$(mktemp -d)/tempconfig" -os::cmd::expect_success "oc config view --raw > '${temp_config}'" -export KUBECONFIG="${temp_config}" -#os::cmd::expect_success 'oc policy add-role-to-user admin project-admin' -#os::cmd::expect_success 'oc login -u project-admin -p anything' -#os::cmd::expect_success 'oc new-project test-project-admin' -#os::cmd::try_until_success "oc project test-project-admin" +# os::util::curl_etcd sends a request to the backing etcd store for the master. +# We use the administrative client cert and key for access and re-encode them +# as necessary for OSX clients. +# +# Globals: +# MASTER_CONFIG_DIR +# API_SCHEME +# API_HOST +# ETCD_PORT +# Arguments: +# - 1: etcd-relative URL to curl, with leading slash +# Returns: +# None +function os::util::curl_etcd() { + local url="$1" + local full_url="${API_SCHEME}://${API_HOST}:${ETCD_PORT}${url}" -os::cmd::expect_success 'oc create deploymentconfig --image=openshift/hello-openshift test' -os::cmd::expect_success 'oc run --image=openshift/hello-openshift --restart=Never test3' -os::cmd::expect_success 'oc create job --image=openshift/hello-openshift test4' -os::cmd::expect_success 'oc delete dc/test pod/test3 job/test4' + local etcd_client_cert="${MASTER_CONFIG_DIR}/master.etcd-client.crt" + local etcd_client_key="${MASTER_CONFIG_DIR}/master.etcd-client.key" + local ca_bundle="${MASTER_CONFIG_DIR}/ca-bundle.crt" -os::cmd::expect_success_and_text 'oc create deploymentconfig --dry-run foo --image=bar -o name' 'deploymentconfig.apps.openshift.io/foo' -os::cmd::expect_success_and_text 'oc run --dry-run foo --image=bar -o name --restart=Never' 'pod/foo' -os::cmd::expect_success_and_text 'oc create job --dry-run foo --image=bar -o name' 'job.batch/foo' -os::cmd::expect_success_and_text 'oc create deploymentconfig --dry-run foo --image=bar -o name' 'deploymentconfig.apps.openshift.io/foo' -os::cmd::expect_success_and_text 'oc run --dry-run foo --image=bar -o name --generator=run-pod/v1' 'pod/foo' + if curl -V | grep -q 'SecureTransport'; then + # on newer OSX ` + "`" + `curl` + "`" + ` implementations, SSL is not used and client certs + # and keys are expected to be encoded in P12 format instead of PEM format, + # so we need to convert the secrets that the server wrote if we haven't + # already done so + local etcd_client_cert_p12="${MASTER_CONFIG_DIR}/master.etcd-client.crt.p12" + local etcd_client_cert_p12_password="${CURL_CERT_P12_PASSWORD:-'password'}" + if [[ ! -f "${etcd_client_cert_p12}" ]]; then + openssl pkcs12 -export \ + -in "${etcd_client_cert}" \ + -inkey "${etcd_client_key}" \ + -out "${etcd_client_cert_p12}" \ + -password "pass:${etcd_client_cert_p12_password}" + fi -os::cmd::expect_success 'oc process -f ${TEST_DATA}/application-template-stibuild.json -l name=mytemplate | oc create -f -' -os::cmd::expect_success 'oc delete all -l name=mytemplate' -#os::cmd::expect_success 'oc new-app https://github.com/openshift/ruby-hello-world' -#os::cmd::expect_success 'oc get dc/ruby-hello-world' + curl --fail --silent --cacert "${ca_bundle}" \ + --cert "${etcd_client_cert_p12}:${etcd_client_cert_p12_password}" "${full_url}" + else + curl --fail --silent --cacert "${ca_bundle}" \ + --cert "${etcd_client_cert}" --key "${etcd_client_key}" "${full_url}" + fi +} -#os::cmd::expect_success_and_text "oc get dc/ruby-hello-world --template='{{ .spec.replicas }}'" '1' -#patch='{"spec": {"replicas": 2}}' -#os::cmd::expect_success "oc patch dc/ruby-hello-world -p '${patch}'" -#os::cmd::expect_success_and_text "oc get dc/ruby-hello-world --template='{{ .spec.replicas }}'" '2' +# os::util::ensure_tmpfs ensures that the target dir is mounted on tmpfs # -#os::cmd::expect_success 'oc delete all -l app=ruby-hello-world' -#os::cmd::expect_failure 'oc get dc/ruby-hello-world' -echo "delete all: ok" -os::test::junit::declare_suite_end +# Globals: +# OS_TMPFS_REQUIRED +# Arguments: +# - 1: target to check +# Returns: +# None +function os::util::ensure_tmpfs() { + if [[ -z "${OS_TMPFS_REQUIRED:-}" ]]; then + return 0 + fi -# service accounts should not be allowed to request new projects -# TODO re-enable once we can use tokens instead of certs -#os::cmd::expect_failure_and_text "oc new-project --token='$( oc sa get-token builder )' will-fail" 'Error from server \(Forbidden\): You may not request a new project via this API.' + local target="$1" + if [[ ! -d "${target}" ]]; then + os::log::fatal "Target dir ${target} does not exist, cannot perform fstype check." + fi -os::test::junit::declare_suite_start "cmd/basicresources/patch" -# Validate patching works correctly -#os::cmd::expect_success 'oc login -u system:admin' -group_json='{"kind":"Group","apiVersion":"v1","metadata":{"name":"patch-group"}}' -os::cmd::expect_success "echo '${group_json}' | oc create -f -" -os::cmd::expect_success "oc patch group patch-group -p 'users: [\"myuser\"]' --loglevel=8" -os::cmd::expect_success_and_text 'oc get group patch-group -o yaml' 'myuser' -os::cmd::expect_success "oc patch group patch-group -p 'users: []' --loglevel=8" -# applying the same patch twice results in exit code 0, and "not patched" text -os::cmd::expect_success_and_text "oc patch group patch-group -p 'users: []'" "patched \(no change\)" -# applying an invalid patch results in exit code 1 and an error -os::cmd::expect_failure_and_text "oc patch group patch-group -p 'users: \"\"'" "cannot restore slice from string" -os::cmd::expect_success_and_text 'oc get group patch-group -o yaml' 'users: \[\]' -echo "patch: ok" -os::test::junit::declare_suite_end + os::log::debug "Filesystem information: +$( df -h -T )" -os::test::junit::declare_suite_end -`) + os::log::debug "Mount information: +$( findmnt --all )" -func testExtendedTestdataCmdTestCmdBasicresourcesShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdBasicresourcesSh, nil + local fstype + fstype="$( df --output=fstype "${target}" | tail -n 1 )" + if [[ "${fstype}" != "tmpfs" ]]; then + local message="Expected \` + "`" + `${target}\` + "`" + ` to be mounted on \` + "`" + `tmpfs\` + "`" + ` but found \` + "`" + `${fstype}\` + "`" + ` instead." + os::log::fatal "${message}" + fi +}`) + +func testExtendedTestdataCmdHackLibUtilMiscShBytes() ([]byte, error) { + return _testExtendedTestdataCmdHackLibUtilMiscSh, nil } -func testExtendedTestdataCmdTestCmdBasicresourcesSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdBasicresourcesShBytes() +func testExtendedTestdataCmdHackLibUtilMiscSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdHackLibUtilMiscShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/basicresources.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/util/misc.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdBuildsSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT - -# Cleanup cluster resources created by this test -( - set +e - oc delete all,templates --all - exit 0 -) &>/dev/null - +var _testExtendedTestdataCmdHackLibUtilTextSh = []byte(`#!/usr/bin/env bash -url=":${API_PORT:-6443}" -project="$(oc project -q)" +# This file contains helpful aliases for manipulating the output text to the terminal as +# well as functions for one-command augmented printing. -os::test::junit::declare_suite_start "cmd/builds" -# This test validates builds and build related commands -# Disabled because git is required in the container running the test -#os::cmd::expect_success 'oc new-build centos/ruby-26-centos7 https://github.com/openshift/ruby-hello-world.git' -#os::cmd::expect_success 'oc get bc/ruby-hello-world' +# os::text::reset resets the terminal output to default if it is called in a TTY +function os::text::reset() { + if os::text::internal::is_tty; then + tput sgr0 + fi +} +readonly -f os::text::reset -#os::cmd::expect_success "cat '${OS_ROOT}/examples/hello-openshift/Dockerfile' | oc new-build -D - --name=test" -#os::cmd::expect_success 'oc get bc/test' +# os::text::bold sets the terminal output to bold text if it is called in a TTY +function os::text::bold() { + if os::text::internal::is_tty; then + tput bold + fi +} +readonly -f os::text::bold -template='{{with .spec.output.to}}{{.kind}} {{.name}}{{end}}' +# os::text::red sets the terminal output to red text if it is called in a TTY +function os::text::red() { + if os::text::internal::is_tty; then + tput setaf 1 + fi +} +readonly -f os::text::red -# Build from Dockerfile with output to ImageStreamTag -os::cmd::expect_success "oc new-build --to=tests:custom --dockerfile=\$'FROM image-registry.openshift-image-registry.svc:5000/openshift/tests:latest\nRUN yum install -y httpd'" -os::cmd::expect_success_and_text "oc get bc/tests --template '${template}'" '^ImageStreamTag tests:custom$' +# os::text::green sets the terminal output to green text if it is called in a TTY +function os::text::green() { + if os::text::internal::is_tty; then + tput setaf 2 + fi +} +readonly -f os::text::green -# Build from a binary with no inputs requires name -os::cmd::expect_failure_and_text "oc new-build --binary" "you must provide a --name" +# os::text::blue sets the terminal output to blue text if it is called in a TTY +function os::text::blue() { + if os::text::internal::is_tty; then + tput setaf 4 + fi +} +readonly -f os::text::blue -# Build from a binary with inputs creates a binary build -os::cmd::expect_success "oc new-build --binary --name=binary-test" -os::cmd::expect_success_and_text "oc get bc/binary-test" 'Binary' +# os::text::yellow sets the terminal output to yellow text if it is called in a TTY +function os::text::yellow() { + if os::text::internal::is_tty; then + tput setaf 11 + fi +} +readonly -f os::text::yellow -os::cmd::expect_success 'oc delete is/binary-test bc/binary-test bc/tests' +# os::text::clear_last_line clears the text from the last line of output to the +# terminal and leaves the cursor on that line to allow for overwriting that text +# if it is called in a TTY +function os::text::clear_last_line() { + if os::text::internal::is_tty; then + tput cuu 1 + tput el + fi +} +readonly -f os::text::clear_last_line -# Build from Dockerfile with output to DockerImage -os::cmd::expect_success "oc new-build -D \$'FROM image-registry.openshift-image-registry.svc:5000/openshift/tests:latest' --to-docker" -os::cmd::expect_success_and_text "oc get bc/tests --template '${template}'" '^DockerImage tests:latest$' +# os::text::clear_string attempts to clear the entirety of a string from the terminal. +# If the string contains literal tabs or other characters that take up more than one +# character space in output, or if the window size is changed before this function +# is called, it will not function correctly. +# No action is taken if this is called outside of a TTY +function os::text::clear_string() { + local -r string="$1" + if os::text::internal::is_tty; then + echo "${string}" | while read line; do + # num_lines is the number of terminal lines this one line of output + # would have taken up with the current terminal width in columns + local num_lines=$(( ${#line} / $( tput cols ) )) + for (( i = 0; i <= num_lines; i++ )); do + os::text::clear_last_line + done + done + fi +} -os::cmd::expect_success 'oc delete is/tests bc/tests' +# os::text::internal::is_tty determines if we are outputting to a TTY +function os::text::internal::is_tty() { + [[ -t 1 && -n "${TERM:-}" ]] +} +readonly -f os::text::internal::is_tty -# Build from Dockerfile with given output ImageStreamTag spec -os::cmd::expect_success "oc new-build -D \$'FROM image-registry.openshift-image-registry.svc:5000/openshift/tests:latest\nENV ok=1' --to origin-test:v1.1" -os::cmd::expect_success_and_text "oc get bc/origin-test --template '${template}'" '^ImageStreamTag origin-test:v1.1$' +# os::text::print_bold prints all input in bold text +function os::text::print_bold() { + os::text::bold + echo "${*}" + os::text::reset +} +readonly -f os::text::print_bold -os::cmd::expect_success 'oc delete is/tests bc/origin-test' +# os::text::print_red prints all input in red text +function os::text::print_red() { + os::text::red + echo "${*}" + os::text::reset +} +readonly -f os::text::print_red -# Build from Dockerfile with given output DockerImage spec -os::cmd::expect_success "oc new-build -D \$'FROM image-registry.openshift-image-registry.svc:5000/openshift/tests:latest\nENV ok=1' --to-docker --to openshift/origin:v1.1-test" -os::cmd::expect_success_and_text "oc get bc/origin --template '${template}'" '^DockerImage openshift/origin:v1.1-test$' +# os::text::print_red_bold prints all input in bold red text +function os::text::print_red_bold() { + os::text::red + os::text::bold + echo "${*}" + os::text::reset +} +readonly -f os::text::print_red_bold -os::cmd::expect_success 'oc delete is/tests' +# os::text::print_green prints all input in green text +function os::text::print_green() { + os::text::green + echo "${*}" + os::text::reset +} +readonly -f os::text::print_green -# Build from Dockerfile with custom name and given output ImageStreamTag spec -os::cmd::expect_success "oc new-build -D \$'FROM image-registry.openshift-image-registry.svc:5000/openshift/tests:latest\nENV ok=1' --to origin-name-test --name origin-test2" -os::cmd::expect_success_and_text "oc get bc/origin-test2 --template '${template}'" '^ImageStreamTag origin-name-test:latest$' +# os::text::print_green_bold prints all input in bold green text +function os::text::print_green_bold() { + os::text::green + os::text::bold + echo "${*}" + os::text::reset +} +readonly -f os::text::print_green_bold -#os::cmd::try_until_text 'oc get is ruby-26-centos7' 'latest' -#os::cmd::expect_failure_and_text 'oc new-build ruby-26-centos7~https://github.com/sclorg/ruby-ex ruby-26-centos7~https://github.com/sclorg/ruby-ex --to invalid/argument' 'error: only one component with source can be used when specifying an output image reference' +# os::text::print_blue prints all input in blue text +function os::text::print_blue() { + os::text::blue + echo "${*}" + os::text::reset +} +readonly -f os::text::print_blue -os::cmd::expect_success 'oc delete all --all' +# os::text::print_blue_bold prints all input in bold blue text +function os::text::print_blue_bold() { + os::text::blue + os::text::bold + echo "${*}" + os::text::reset +} +readonly -f os::text::print_blue_bold -os::cmd::expect_success "oc new-build -D \$'FROM image-registry.openshift-image-registry.svc:5000/openshift/tests:latest' --no-output" -os::cmd::expect_success_and_not_text 'oc get bc/tests -o=jsonpath="{.spec.output.to}"' '.' +# os::text::print_yellow prints all input in yellow text +function os::text::print_yellow() { + os::text::yellow + echo "${*}" + os::text::reset +} +readonly -f os::text::print_yellow -# Ensure output is valid JSON -#os::cmd::expect_success 'oc new-build -D "FROM image-registry.openshift-image-registry.svc:5000/openshift/tests:latest" -o json | python -m json.tool' +# os::text::print_yellow_bold prints all input in bold yellow text +function os::text::print_yellow_bold() { + os::text::yellow + os::text::bold + echo "${*}" + os::text::reset +} +readonly -f os::text::print_yellow_bold +`) -os::cmd::expect_success 'oc delete all --all' -os::cmd::expect_success 'oc process -f ${TEST_DATA}/application-template-dockerbuild.json -l build=docker | oc create -f -' -os::cmd::expect_success 'oc get buildConfigs' -os::cmd::expect_success 'oc get bc' -os::cmd::expect_success 'oc get builds' +func testExtendedTestdataCmdHackLibUtilTextShBytes() ([]byte, error) { + return _testExtendedTestdataCmdHackLibUtilTextSh, nil +} -# make sure the imagestream has the latest tag before trying to test it or start a build with it -os::cmd::try_until_success 'oc get istag ruby-27-centos7:latest' +func testExtendedTestdataCmdHackLibUtilTextSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdHackLibUtilTextShBytes() + if err != nil { + return nil, err + } -os::test::junit::declare_suite_start "cmd/builds/patch-anon-fields" -REAL_OUTPUT_TO=$(oc get bc/ruby-sample-build --template='{{ .spec.output.to.name }}') -os::cmd::expect_success "oc patch bc/ruby-sample-build -p '{\"spec\":{\"output\":{\"to\":{\"name\":\"different:tag1\"}}}}'" -os::cmd::expect_success_and_text "oc get bc/ruby-sample-build --template='{{ .spec.output.to.name }}'" 'different' -os::cmd::expect_success "oc patch bc/ruby-sample-build -p '{\"spec\":{\"output\":{\"to\":{\"name\":\"${REAL_OUTPUT_TO}\"}}}}'" -echo "patchAnonFields: ok" -os::test::junit::declare_suite_end + info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/util/text.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} -os::test::junit::declare_suite_start "cmd/builds/config" -os::cmd::expect_success_and_text 'oc describe buildConfigs ruby-sample-build' "${url}/apis/build.openshift.io/v1/namespaces/${project}/buildconfigs/ruby-sample-build/webhooks//github" -os::cmd::expect_success_and_text 'oc describe buildConfigs ruby-sample-build' "Webhook GitHub" -os::cmd::expect_success_and_text 'oc describe buildConfigs ruby-sample-build' "${url}/apis/build.openshift.io/v1/namespaces/${project}/buildconfigs/ruby-sample-build/webhooks//generic" -os::cmd::expect_success_and_text 'oc describe buildConfigs ruby-sample-build' "Webhook Generic" -os::cmd::expect_success_and_text 'oc set triggers bc/ruby-sample-build --from-gitlab' "triggers updated" -os::cmd::expect_success_and_text 'oc set triggers bc/ruby-sample-build --from-bitbucket' "triggers updated" -os::cmd::expect_success 'oc start-build --list-webhooks=all ruby-sample-build' -os::cmd::expect_success_and_text 'oc start-build --list-webhooks=all bc/ruby-sample-build' 'generic' -os::cmd::expect_success_and_text 'oc start-build --list-webhooks=all ruby-sample-build' 'github' -os::cmd::expect_success_and_text 'oc start-build --list-webhooks=all ruby-sample-build' 'gitlab' -os::cmd::expect_success_and_text 'oc start-build --list-webhooks=all ruby-sample-build' 'bitbucket' -os::cmd::expect_success_and_text 'oc start-build --list-webhooks=github ruby-sample-build' '' -os::cmd::expect_failure 'oc start-build --list-webhooks=blah' -hook=$(oc start-build --list-webhooks='generic' ruby-sample-build | head -n 1) -hook=${hook//secret101} -os::cmd::expect_success_and_text "oc start-build --from-webhook=${hook}" "build.build.openshift.io/ruby-sample-build-[0-9] started" -os::cmd::expect_failure_and_text "oc start-build --from-webhook=${hook}/foo" "error: server rejected our request" -os::cmd::expect_success "oc patch bc/ruby-sample-build -p '{\"spec\":{\"strategy\":{\"dockerStrategy\":{\"from\":{\"name\":\"asdf:7\"}}}}}'" -os::cmd::expect_failure_and_text "oc start-build --from-webhook=${hook}" "Error resolving ImageStreamTag asdf:7" -os::cmd::expect_success 'oc get builds' -os::cmd::expect_success 'oc set triggers bc/ruby-sample-build --from-github --remove' -os::cmd::expect_success_and_not_text 'oc describe buildConfigs ruby-sample-build' "Webhook GitHub" -# make sure we describe webhooks using secretReferences properly -os::cmd::expect_success "oc patch bc/ruby-sample-build -p '{\"spec\":{\"triggers\":[{\"github\":{\"secretReference\":{\"name\":\"mysecret\"}},\"type\":\"GitHub\"}]}}'" -os::cmd::expect_success_and_text 'oc describe buildConfigs ruby-sample-build' "Webhook GitHub" -os::cmd::expect_success 'oc delete all -l build=docker' +var _testExtendedTestdataCmdHackLibUtilTrapSh = []byte(`#!/usr/bin/env bash +# +# This library defines the trap handlers for the ERR and EXIT signals. Any new handler for these signals +# must be added to these handlers and activated by the environment variable mechanism that the rest use. +# These functions ensure that no handler can ever alter the exit code that was emitted by a command +# in a test script. -echo "buildConfig: ok" -os::test::junit::declare_suite_end +# os::util::trap::init_err initializes the privileged handler for the ERR signal if it hasn't +# been registered already. This will overwrite any other handlers registered on the signal. +# +# Globals: +# None +# Arguments: +# None +# Returns: +# None +function os::util::trap::init_err() { + if ! trap -p ERR | grep -q 'os::util::trap::err_handler'; then + trap 'os::util::trap::err_handler;' ERR + fi +} +readonly -f os::util::trap::init_err -os::test::junit::declare_suite_start "cmd/builds/start-build" -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-buildcli.json' -# a build for which there is not an upstream tag in the corresponding imagerepo, so -# the build should use the image field as defined in the buildconfig -# Use basename to transform "build/build-name" into "build-name" -started="$(basename $(oc start-build -o=name ruby-sample-build-invalidtag))" -os::cmd::expect_success_and_text "oc describe build ${started}" 'openshift/ruby$' -frombuild="$(basename $(oc start-build -o=name --from-build="${started}"))" -os::cmd::expect_success_and_text "oc describe build ${frombuild}" 'openshift/ruby$' -os::cmd::expect_failure_and_text "oc start-build ruby-sample-build-invalid-tag --from-dir=. --from-build=${started}" "cannot use '--from-build' flag with binary builds" -os::cmd::expect_failure_and_text "oc start-build ruby-sample-build-invalid-tag --from-file=. --from-build=${started}" "cannot use '--from-build' flag with binary builds" -os::cmd::expect_failure_and_text "oc start-build ruby-sample-build-invalid-tag --from-repo=. --from-build=${started}" "cannot use '--from-build' flag with binary builds" -# --incremental flag should override Spec.Strategy.SourceStrategy.Incremental -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-s2i-build.json' -build_name="$(oc start-build -o=name test)" -os::cmd::expect_success_and_not_text "oc describe ${build_name}" 'Incremental Build' -build_name="$(oc start-build -o=name --incremental test)" -os::cmd::expect_success_and_text "oc describe ${build_name}" 'Incremental Build' -os::cmd::expect_success "oc patch bc/test -p '{\"spec\":{\"strategy\":{\"sourceStrategy\":{\"incremental\": true}}}}'" -build_name="$(oc start-build -o=name test)" -os::cmd::expect_success_and_text "oc describe ${build_name}" 'Incremental Build' -build_name="$(oc start-build -o=name --incremental=false test)" -os::cmd::expect_success_and_not_text "oc describe ${build_name}" 'Incremental Build' -os::cmd::expect_success "oc patch bc/test -p '{\"spec\":{\"strategy\":{\"sourceStrategy\":{\"incremental\": false}}}}'" -build_name="$(oc start-build -o=name test)" -os::cmd::expect_success_and_not_text "oc describe ${build_name}" 'Incremental Build' -build_name="$(oc start-build -o=name --incremental test)" -os::cmd::expect_success_and_text "oc describe ${build_name}" 'Incremental Build' -os::cmd::expect_failure_and_text "oc start-build test --no-cache" 'Cannot specify Docker build specific options' -os::cmd::expect_failure_and_text "oc start-build test --build-arg=a=b" 'Cannot specify Docker build specific options' -os::cmd::expect_success 'oc delete all --selector="name=test"' -# --no-cache flag should override Spec.Strategy.SourceStrategy.NoCache -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-docker-build.json' -build_name="$(oc start-build -o=name test)" -os::cmd::expect_success_and_not_text "oc describe ${build_name}" 'No Cache' -build_name="$(oc start-build -o=name --no-cache test)" -os::cmd::expect_success_and_text "oc describe ${build_name}" 'No Cache' -os::cmd::expect_success "oc patch bc/test -p '{\"spec\":{\"strategy\":{\"dockerStrategy\":{\"noCache\": true}}}}'" -build_name="$(oc start-build -o=name test)" -os::cmd::expect_success_and_text "oc describe ${build_name}" 'No Cache' -build_name="$(oc start-build -o=name --no-cache=false test)" -os::cmd::expect_success_and_not_text "oc describe ${build_name}" 'No Cache' -os::cmd::expect_success "oc patch bc/test -p '{\"spec\":{\"strategy\":{\"dockerStrategy\":{\"noCache\": false}}}}'" -build_name="$(oc start-build -o=name test)" -os::cmd::expect_success_and_not_text "oc describe ${build_name}" 'No Cache' -build_name="$(oc start-build -o=name --no-cache test)" -os::cmd::expect_success_and_text "oc describe ${build_name}" 'No Cache' -os::cmd::expect_failure_and_text "oc start-build test --incremental" 'Cannot specify Source build specific options' -# ensure a specific version can be specified for buildconfigs -os::cmd::expect_failure_and_not_text "oc logs bc/test --version=1" "cannot specify a version and a build" -os::cmd::expect_success 'oc delete all --selector="name=test"' -echo "start-build: ok" -os::test::junit::declare_suite_end +# os::util::trap::init_exit initializes the privileged handler for the EXIT signal if it hasn't +# been registered already. This will overwrite any other handlers registered on the signal. +# +# Globals: +# None +# Arguments: +# None +# Returns: +# None +function os::util::trap::init_exit() { + if ! trap -p EXIT | grep -q 'os::util::trap::exit_handler'; then + trap 'os::util::trap::exit_handler;' EXIT + fi +} +readonly -f os::util::trap::init_exit -os::test::junit::declare_suite_start "cmd/builds/cancel-build" -os::cmd::expect_success_and_text "oc cancel-build ${started} --dump-logs --restart" "build.build.openshift.io/${started} restarted" -os::cmd::expect_success 'oc delete all --all' -os::cmd::expect_success 'oc delete secret dbsecret' -os::cmd::expect_success 'oc process -f ${TEST_DATA}/application-template-dockerbuild.json -l build=docker | oc create -f -' -os::cmd::try_until_success 'oc get build/ruby-sample-build-1' -# Uses type/name resource syntax to cancel the build and check for proper message -os::cmd::expect_success_and_text 'oc cancel-build build/ruby-sample-build-1' 'build.build.openshift.io/ruby-sample-build-1 cancelled' -# Make sure canceling already cancelled build returns proper message -os::cmd::expect_success 'oc cancel-build build/ruby-sample-build-1' -# Cancel all builds from a build configuration -os::cmd::expect_success "oc start-build bc/ruby-sample-build" -os::cmd::expect_success "oc start-build bc/ruby-sample-build" -lastbuild="$(basename $(oc start-build -o=name bc/ruby-sample-build))" -os::cmd::expect_success_and_text 'oc cancel-build bc/ruby-sample-build' "build.build.openshift.io/${lastbuild} cancelled" -os::cmd::expect_success_and_text "oc get build ${lastbuild} -o template --template '{{.status.phase}}'" 'Cancelled' -builds=$(oc get builds -o template --template '{{range .items}}{{ .status.phase }} {{end}}') -for state in $builds; do - os::cmd::expect_success "[ \"${state}\" == \"Cancelled\" ]" -done -# Running this command again when all builds are cancelled should be no-op. -os::cmd::expect_success 'oc cancel-build bc/ruby-sample-build' -os::cmd::expect_success 'oc delete all --all' -os::cmd::expect_success 'oc delete secret dbsecret' -echo "cancel-build: ok" -os::test::junit::declare_suite_end +# os::util::trap::err_handler is the handler for the ERR signal. +# +# Globals: +# - OS_TRAP_DEBUG +# - OS_USE_STACKTRACE +# Arguments: +# None +# Returns: +# - returns original return code, allows privileged handler to exit if necessary +function os::util::trap::err_handler() { + local -r return_code=$? + local -r last_command="${BASH_COMMAND}" -os::test::junit::declare_suite_end -`) + if set +o | grep -q '\-o errexit'; then + local -r errexit_set=true + fi -func testExtendedTestdataCmdTestCmdBuildsShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdBuildsSh, nil -} + if [[ "${OS_TRAP_DEBUG:-}" = "true" ]]; then + echo "[DEBUG] Error handler executing with return code \` + "`" + `${return_code}\` + "`" + `, last command \` + "`" + `${last_command}\` + "`" + `, and errexit set \` + "`" + `${errexit_set:-}\` + "`" + `" + fi -func testExtendedTestdataCmdTestCmdBuildsSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdBuildsShBytes() - if err != nil { - return nil, err - } + if [[ "${OS_USE_STACKTRACE:-}" = "true" ]]; then + # the OpenShift stacktrace function is treated as a privileged handler for this signal + # and is therefore allowed to run outside of a subshell in order to allow it to ` + "`" + `exit` + "`" + ` + # if necessary + os::log::stacktrace::print "${return_code}" "${last_command}" "${errexit_set:-}" + fi - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/builds.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil + return "${return_code}" } +readonly -f os::util::trap::err_handler -var _testExtendedTestdataCmdTestCmdCompletionsSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT +# os::util::trap::exit_handler is the handler for the EXIT signal. +# +# Globals: +# - OS_TRAP_DEBUG +# - OS_DESCRIBE_RETURN_CODE +# Arguments: +# None +# Returns: +# - original exit code of the script that exited +function os::util::trap::exit_handler() { + local -r return_code=$? -os::test::junit::declare_suite_start "cmd/completions" -# This test validates basic resource retrieval and command interaction + # we do not want these traps to be able to trigger more errors, we can let them fail silently + set +o errexit -# test completion command help -os::cmd::expect_success_and_text "oc completion -h" "interactive completion of oc commands" -# test completion command output -os::cmd::expect_failure_and_text "oc completion" "Shell not specified." -os::cmd::expect_success "oc completion bash" -os::cmd::expect_success "oc completion zsh" -os::cmd::expect_failure_and_text "oc completion test_shell" 'Unsupported shell type "test_shell"' -echo "oc completion: ok" + if [[ "${OS_TRAP_DEBUG:-}" = "true" ]]; then + echo "[DEBUG] Exit handler executing with return code \` + "`" + `${return_code}\` + "`" + `" + fi -os::test::junit::declare_suite_end + # the following envars selectively enable optional exit traps, all of which are run inside of + # a subshell in order to sandbox them and not allow them to influence how this script will exit + if [[ "${OS_DESCRIBE_RETURN_CODE:-}" = "true" ]]; then + ( os::util::describe_return_code "${return_code}" ) + fi + + exit "${return_code}" +} +readonly -f os::util::trap::exit_handler `) -func testExtendedTestdataCmdTestCmdCompletionsShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdCompletionsSh, nil +func testExtendedTestdataCmdHackLibUtilTrapShBytes() ([]byte, error) { + return _testExtendedTestdataCmdHackLibUtilTrapSh, nil } -func testExtendedTestdataCmdTestCmdCompletionsSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdCompletionsShBytes() +func testExtendedTestdataCmdHackLibUtilTrapSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdHackLibUtilTrapShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/completions.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/hack/lib/util/trap.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdConfigSh = []byte(`#!/bin/bash - -set -o errexit -set -o nounset -set -o pipefail - -OS_ROOT=$(dirname "${BASH_SOURCE}")/../.. -source "${OS_ROOT}/hack/lib/init.sh" -os::log::stacktrace::install +var _testExtendedTestdataCmdTestCmdAdminSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT # Cleanup cluster resources created by this test ( set +e - oc delete all,templates,secrets --all + oc delete project/example project/ui-test-project project/recreated-project &>/dev/null || true + oc delete groups/shortoutputgroup &>/dev/null || true + oc delete groups/group1 &>/dev/null || true + oc delete groups/cascaded-group &>/dev/null || true + oc delete groups/orphaned-group &>/dev/null || true + oc delete users/cascaded-user &>/dev/null || true + oc delete users/orphaned-user &>/dev/null || true + oc delete identities/alwaysallow:orphaned-user &>/dev/null || true + oc delete identities/alwaysallow:cascaded-user &>/dev/null || true + oc delete clusterroles/basic-users2 &>/dev/null || true + oc delete clusterroles/basic-user2 &>/dev/null || true + oc delete clusterrolebindings/basic-users2 &>/dev/null || true + oc delete clusterrolebindings/basic-user2 &>/dev/null || true + oc delete user/test-cmd-user &>/dev/null || true + oc delete namespace example &>/dev/null || true + oc delete identities.user.openshift.io/test-idp:test-uid &>/dev/null || true + oc delete images.image.openshift.io/sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6 &>/dev/null || true + oc delete -n default imagestreams.image.openshift.io/busybox &>/dev/null || true + oc wait --for=delete namespace/example --timeout=60s || true +# oc auth reconcile --remove-extra-permissions --remove-extra-subjects -f "${BASE_RBAC_DATA}" exit 0 ) &>/dev/null -# check to make sure that "get"ting a resource with no config file present -# still returns error indicating that no config-file is set -os::test::junit::declare_suite_start "cmd/configuration" -os::cmd::expect_success_and_not_text 'oc get bc' 'does not exist' -( - export HOME=/tmp - unset KUBECONFIG - unset KUBERNETES_MASTER +project="$( oc project -q )" - os::cmd::expect_failure_and_text 'env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --user=""' 'Missing or incomplete configuration info' - os::cmd::expect_failure_and_text 'env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --context=""' 'Missing or incomplete configuration info' - os::cmd::expect_failure_and_text 'env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --cluster=""' 'Missing or incomplete configuration info' +defaultimage="openshift/origin-\${component}:latest" +USE_IMAGES=${USE_IMAGES:-$defaultimage} - os::cmd::expect_failure_and_text 'env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --context="test"' 'context was not found for specified context: test' - os::cmd::expect_failure_and_text 'env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --cluster="test"' 'no server found for cluster "test"' - # need some level of default (both upstream and here) to get the pretty auth message because you fail on namespace first. - os::cmd::expect_failure_and_text 'KUBERNETES_MASTER=anything env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --user="test"' 'auth info "test" does not exist' +os::test::junit::declare_suite_start "cmd/admin" +# This test validates admin level commands including system policy - os::cmd::expect_failure_and_text 'oc get bc --config=missing' 'missing: no such file or directory' +os::test::junit::declare_suite_start "cmd/admin/start" +# Check failure modes of various system commands - # define temp location for new config - NEW_CONFIG_LOC="${BASETMPDIR}/new-config.yaml" +os::test::junit::declare_suite_start "cmd/admin/certs" +# check encrypt/decrypt of plain text +os::cmd::expect_success "echo -n 'secret data 1' | oc adm ca encrypt --genkey='${ARTIFACT_DIR}/secret.key' --out='${ARTIFACT_DIR}/secret.encrypted'" +os::cmd::expect_success_and_text "oc adm ca decrypt --in='${ARTIFACT_DIR}/secret.encrypted' --key='${ARTIFACT_DIR}/secret.key'" 'secret data 1' +# create a file with trailing whitespace +echo "data with newline" > "${ARTIFACT_DIR}/secret.whitespace.data" +os::cmd::expect_success_and_text "oc adm ca encrypt --key='${ARTIFACT_DIR}/secret.key' --in='${ARTIFACT_DIR}/secret.whitespace.data' --out='${ARTIFACT_DIR}/secret.whitespace.encrypted'" 'Warning.*whitespace' +os::cmd::expect_success "oc adm ca decrypt --key='${ARTIFACT_DIR}/secret.key' --in='${ARTIFACT_DIR}/secret.whitespace.encrypted' --out='${ARTIFACT_DIR}/secret.whitespace.decrypted'" +os::cmd::expect_success "diff '${ARTIFACT_DIR}/secret.whitespace.data' '${ARTIFACT_DIR}/secret.whitespace.decrypted'" +# create a binary file +echo "hello" | gzip > "${ARTIFACT_DIR}/secret.data" +# encrypt using file and pipe input/output +os::cmd::expect_success "oc adm ca encrypt --key='${ARTIFACT_DIR}/secret.key' --in='${ARTIFACT_DIR}/secret.data' --out='${ARTIFACT_DIR}/secret.file-in-file-out.encrypted'" +os::cmd::expect_success "oc adm ca encrypt --key='${ARTIFACT_DIR}/secret.key' --in='${ARTIFACT_DIR}/secret.data' > '${ARTIFACT_DIR}/secret.file-in-pipe-out.encrypted'" +os::cmd::expect_success "oc adm ca encrypt --key='${ARTIFACT_DIR}/secret.key' < '${ARTIFACT_DIR}/secret.data' > '${ARTIFACT_DIR}/secret.pipe-in-pipe-out.encrypted'" +# decrypt using all three methods +os::cmd::expect_success "oc adm ca decrypt --key='${ARTIFACT_DIR}/secret.key' --in='${ARTIFACT_DIR}/secret.file-in-file-out.encrypted' --out='${ARTIFACT_DIR}/secret.file-in-file-out.decrypted'" +os::cmd::expect_success "oc adm ca decrypt --key='${ARTIFACT_DIR}/secret.key' --in='${ARTIFACT_DIR}/secret.file-in-pipe-out.encrypted' > '${ARTIFACT_DIR}/secret.file-in-pipe-out.decrypted'" +os::cmd::expect_success "oc adm ca decrypt --key='${ARTIFACT_DIR}/secret.key' < '${ARTIFACT_DIR}/secret.pipe-in-pipe-out.encrypted' > '${ARTIFACT_DIR}/secret.pipe-in-pipe-out.decrypted'" +# verify lossless roundtrip +os::cmd::expect_success "diff '${ARTIFACT_DIR}/secret.data' '${ARTIFACT_DIR}/secret.file-in-file-out.decrypted'" +os::cmd::expect_success "diff '${ARTIFACT_DIR}/secret.data' '${ARTIFACT_DIR}/secret.file-in-pipe-out.decrypted'" +os::cmd::expect_success "diff '${ARTIFACT_DIR}/secret.data' '${ARTIFACT_DIR}/secret.pipe-in-pipe-out.decrypted'" +echo "certs: ok" +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_start "cmd/admin/groups" +os::cmd::expect_success_and_text 'oc adm groups new shortoutputgroup -o name' 'group.user.openshift.io/shortoutputgroup' +# test --dry-run flag for this command +os::cmd::expect_success_and_text 'oc adm groups new mygroup --dry-run' 'group.user.openshift.io/mygroup created \(dry run\)' +os::cmd::expect_success_and_text 'oc adm groups new mygroup --dry-run -o name' 'group.user.openshift.io/mygroup' +# ensure group was not actually created +os::cmd::expect_failure_and_text 'oc get groups mygroup' 'groups.user.openshift.io "mygroup" not found' +os::cmd::expect_success_and_text 'oc adm groups new shortoutputgroup -o name --dry-run' 'group.user.openshift.io/shortoutputgroup' +os::cmd::expect_failure_and_text 'oc adm groups new shortoutputgroup' 'groups.user.openshift.io "shortoutputgroup" already exists' +os::cmd::expect_failure_and_text 'oc adm groups new errorgroup -o blah' 'unable to match a printer suitable for the output format "blah"' +os::cmd::expect_failure_and_text 'oc get groups/errorgroup' 'groups.user.openshift.io "errorgroup" not found' +# update cmd to use --template once it is wired across all Origin commands. +# see +os::cmd::expect_success_and_text 'oc adm groups new group1 foo bar -o yaml' '\- foo' +os::cmd::expect_success_and_text 'oc get groups/group1 --no-headers' 'foo, bar' +os::cmd::expect_success 'oc adm groups add-users group1 baz' +os::cmd::expect_success_and_text 'oc get groups/group1 --no-headers' 'baz' +os::cmd::expect_success 'oc adm groups remove-users group1 bar' +os::cmd::expect_success_and_not_text 'oc get groups/group1 --no-headers' 'bar' +os::cmd::expect_success_and_text 'oc adm prune auth users/baz' 'group.user.openshift.io/group1 updated' +echo "groups: ok" +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_start "cmd/admin/admin-scc" +os::cmd::expect_success 'oc adm policy who-can get pods' +os::cmd::expect_success 'oc adm policy who-can get pods -n default' +os::cmd::expect_success 'oc adm policy who-can get pods --all-namespaces' +# check to make sure that the resource arg conforms to resource rules +os::cmd::expect_success_and_text 'oc adm policy who-can get Pod' "Resource: pods" +os::cmd::expect_success_and_text 'oc adm policy who-can get PodASDF' "Resource: PodASDF" +os::cmd::expect_success_and_text 'oc adm policy who-can get hpa.autoscaling -n default' "Resource: horizontalpodautoscalers.autoscaling" +os::cmd::expect_success_and_text 'oc adm policy who-can get hpa.v1.autoscaling -n default' "Resource: horizontalpodautoscalers.autoscaling" +os::cmd::expect_success_and_text 'oc adm policy who-can get hpa -n default' "Resource: horizontalpodautoscalers.autoscaling" + +os::cmd::expect_success 'oc adm policy add-role-to-group --rolebinding-name=cluster-admin cluster-admin system:unauthenticated' +os::cmd::expect_success 'oc adm policy add-role-to-user --rolebinding-name=cluster-admin cluster-admin system:no-user' +os::cmd::expect_success 'oc adm policy add-role-to-user --rolebinding-name=admin admin -z fake-sa' +os::cmd::expect_success_and_text 'oc get rolebinding/admin -o jsonpath={.subjects}' 'fake-sa' +os::cmd::expect_success 'oc adm policy remove-role-from-user admin -z fake-sa' +os::cmd::expect_success_and_not_text 'oc get rolebinding/admin -o jsonpath={.subjects}' 'fake-sa' +os::cmd::expect_success 'oc adm policy add-role-to-user --rolebinding-name=admin admin -z fake-sa' +os::cmd::expect_success_and_text 'oc get rolebinding/admin -o jsonpath={.subjects}' 'fake-sa' +os::cmd::expect_success "oc adm policy remove-role-from-user admin system:serviceaccount:$(oc project -q):fake-sa" +os::cmd::expect_success_and_not_text 'oc get rolebinding/admin -o jsonpath={.subjects}' 'fake-sa' +os::cmd::expect_success 'oc adm policy remove-role-from-group cluster-admin system:unauthenticated' +os::cmd::expect_success 'oc adm policy remove-role-from-user cluster-admin system:no-user' +os::cmd::expect_failure_and_text 'oc adm policy remove-role-from-user admin ghost' 'error: unable to find target \[ghost\]' +os::cmd::expect_failure_and_text 'oc adm policy remove-role-from-user admin -z ghost' 'error: unable to find target \[ghost\]' +os::cmd::expect_success 'oc adm policy remove-group system:unauthenticated' +os::cmd::expect_success 'oc adm policy remove-user system:no-user' +os::cmd::expect_success 'oc adm policy add-cluster-role-to-group cluster-admin system:unauthenticated' +os::cmd::expect_success 'oc adm policy remove-cluster-role-from-group cluster-admin system:unauthenticated' +os::cmd::expect_success 'oc adm policy add-cluster-role-to-user cluster-admin system:no-user' +os::cmd::expect_success 'oc adm policy remove-cluster-role-from-user cluster-admin system:no-user' +os::cmd::expect_success 'oc adm policy add-role-to-user view foo' +os::cmd::expect_success 'oc adm policy add-role-to-user view bar --rolebinding-name=custom' +os::cmd::expect_success 'oc adm policy add-role-to-user view baz --rolebinding-name=custom' +#os::cmd::expect_success_and_text 'oc get rolebinding/view -o jsonpath="{.metadata.name},{.roleRef.name},{.userNames[*]}"' '^view,view,foo$' +#os::cmd::expect_success_and_text 'oc get rolebinding/custom -o jsonpath="{.metadata.name},{.roleRef.name},{.userNames[*]}"' '^custom,view,bar baz$' +os::cmd::expect_failure_and_text 'oc adm policy add-role-to-user other fuz --rolebinding-name=custom' '^error: rolebinding custom found for role view, not other$' +#os::cmd::expect_success_and_text 'oc adm policy remove-cluster-role-from-group self-provisioner system:authenticated:oauth' "Warning: Your changes may get lost whenever a master is restarted, unless you prevent reconciliation of this rolebinding using the following command: oc annotate clusterrolebinding.rbac self-provisioners 'rbac.authorization.kubernetes.io/autoupdate=false' --overwrite" +os::cmd::expect_success 'oc adm policy add-cluster-role-to-group --rolebinding-name=self-provisioners self-provisioner system:authenticated:oauth' +#os::cmd::expect_success 'oc annotate clusterrolebinding.rbac self-provisioners "rbac.authorization.kubernetes.io/autoupdate=false" --overwrite' +#os::cmd::expect_success_and_not_text 'oc adm policy remove-cluster-role-from-group self-provisioner system:authenticated:oauth' "Warning" +#os::cmd::expect_success 'oc adm policy add-cluster-role-to-group --rolebinding-name=self-provisioners self-provisioner system:authenticated:oauth' + +# os::cmd::expect_success 'oc adm policy add-scc-to-user privileged fake-user' +# os::cmd::expect_success_and_text 'oc get scc/privileged -o yaml' 'fake-user' +# os::cmd::expect_success 'oc adm policy add-scc-to-user privileged -z fake-sa' +# os::cmd::expect_success_and_text 'oc get scc/privileged -o yaml' "system:serviceaccount:$(oc project -q):fake-sa" +# os::cmd::expect_success 'oc adm policy add-scc-to-group privileged fake-group' +# os::cmd::expect_success_and_text 'oc get scc/privileged -o yaml' 'fake-group' +# os::cmd::expect_success 'oc adm policy remove-scc-from-user privileged fake-user' +# os::cmd::expect_success_and_not_text 'oc get scc/privileged -o yaml' 'fake-user' +# os::cmd::expect_success 'oc adm policy remove-scc-from-user privileged -z fake-sa' +# os::cmd::expect_success_and_not_text 'oc get scc/privileged -o yaml' "system:serviceaccount:$(oc project -q):fake-sa" +# os::cmd::expect_success 'oc adm policy remove-scc-from-group privileged fake-group' +# os::cmd::expect_success_and_not_text 'oc get scc/privileged -o yaml' 'fake-group' + +# check pruning +os::cmd::expect_success 'oc adm policy add-scc-to-user privileged fake-user' +os::cmd::expect_success_and_text 'oc adm prune auth users/fake-user' 'privileged updated' +os::cmd::expect_success 'oc adm policy add-scc-to-group privileged fake-group' +os::cmd::expect_success_and_text 'oc adm prune auth groups/fake-group' 'privileged updated' +echo "admin-scc: ok" +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_start "cmd/admin/role-reapers" +#os::cmd::expect_success "oc process -f ${TEST_DATA}/roles/policy-roles.yaml -p NAMESPACE='${project}' | oc create -f -" +#os::cmd::expect_success "oc get rolebinding/basic-users" +#os::cmd::expect_success "oc adm prune auth role/basic-user" +#os::cmd::try_until_failure "oc get rolebinding/basic-users" +#os::cmd::expect_success "oc delete role/basic-user" +#os::cmd::expect_success "oc create -f ${TEST_DATA}/roles/policy-clusterroles.yaml" +#os::cmd::expect_success "oc get clusterrolebinding/basic-users2" +#os::cmd::expect_success "oc adm prune auth clusterrole/basic-user2" +#os::cmd::try_until_failure "oc get clusterrolebinding/basic-users2" +#os::cmd::expect_success "oc delete clusterrole/basic-user2" +#os::cmd::expect_success "oc policy add-role-to-user edit foo" +#os::cmd::expect_success "oc get rolebinding/edit" +#os::cmd::expect_success "oc adm prune auth clusterrole/edit" +#os::cmd::try_until_failure "oc get rolebinding/edit" +#os::cmd::expect_success "oc delete clusterrole/edit" +#os::cmd::expect_success 'oc auth reconcile --remove-extra-permissions --remove-extra-subjects -f "${BASE_RBAC_DATA}"' +# +#os::cmd::expect_success "oc process -f ${TEST_DATA}/roles/policy-roles.yaml -p NAMESPACE='${project}' | oc create -f -" +#os::cmd::expect_success "oc get rolebinding/basic-users" +#os::cmd::expect_success_and_text "oc adm prune auth role/basic-user" "rolebinding.rbac.authorization.k8s.io/basic-users deleted" +#os::cmd::expect_success "oc get role/basic-user" +#os::cmd::expect_success "oc delete role/basic-user" +# +#os::cmd::expect_success "oc create -f ${TEST_DATA}/roles/policy-clusterroles.yaml" +#os::cmd::expect_success "oc get clusterrolebinding/basic-users2" +#os::cmd::expect_success_and_text "oc adm prune auth clusterrole/basic-user2" "clusterrolebinding.rbac.authorization.k8s.io/basic-users2 deleted" +#os::cmd::expect_success "oc get clusterrole/basic-user2" +#os::cmd::expect_success "oc delete clusterrole/basic-user2" +echo "admin-role-reapers: ok" +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_start "cmd/admin/role-selectors" +os::cmd::expect_success "oc create -f ${TEST_DATA}/roles/policy-clusterroles.yaml" +os::cmd::expect_success "oc get clusterrole/basic-user2" +os::cmd::expect_success "oc label clusterrole/basic-user2 foo=bar" +os::cmd::expect_success_and_not_text "oc get clusterroles --selector=foo=bar" "No resources found" +os::cmd::expect_success_and_text "oc get clusterroles --selector=foo=unknown" "No resources found" +os::cmd::expect_success "oc get clusterrolebinding/basic-users2" +os::cmd::expect_success "oc label clusterrolebinding/basic-users2 foo=bar" +os::cmd::expect_success_and_not_text "oc get clusterrolebindings --selector=foo=bar" "No resources found" +os::cmd::expect_success_and_text "oc get clusterroles --selector=foo=unknown" "No resources found" +os::cmd::expect_success "oc delete clusterrole/basic-user2" +os::test::junit::declare_suite_end +echo "admin-role-selectors: ok" + +os::test::junit::declare_suite_start "cmd/admin/ui-project-commands" +# Test the commands the UI projects page tells users to run +# These should match what is described in projects.html +os::cmd::expect_success 'oc adm new-project ui-test-project --admin="createuser"' +os::cmd::expect_success 'oc adm policy add-role-to-user --rolebinding-name=admin admin adduser -n ui-test-project' +# Make sure project can be listed by oc (after auth cache syncs) +os::cmd::try_until_text 'oc get projects' 'ui\-test\-project' +# Make sure users got added +os::cmd::expect_success_and_text "oc get rolebinding admin -n ui-test-project -o jsonpath='{.subjects[*].name}'" '^createuser adduser$' +echo "ui-project-commands: ok" +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_start "cmd/admin/new-project" +# Test deleting and recreating a project +os::cmd::expect_success 'oc adm new-project recreated-project --admin="createuser1"' +os::cmd::expect_success 'oc delete project recreated-project' +os::cmd::try_until_failure 'oc get project recreated-project' +os::cmd::expect_success 'oc adm new-project recreated-project --admin="createuser2"' +os::cmd::expect_success_and_text "oc get rolebinding admin -n recreated-project -o jsonpath='{.subjects[*].name}'" '^createuser2$' +echo "new-project: ok" +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_start "cmd/admin/build-chain" +# Test building a dependency tree +os::cmd::expect_success 'oc process -f ${TEST_DATA}/application-template-stibuild.json -l build=sti | oc create -f -' +# Test both the type/name resource syntax and the fact that istag/origin-ruby-sample:latest is still +# not created but due to a buildConfig pointing to it, we get back its graph of deps. +os::cmd::expect_success_and_text 'oc adm build-chain istag/origin-ruby-sample' 'istag/origin-ruby-sample:latest' +os::cmd::expect_success_and_text 'oc adm build-chain ruby-27-centos7 -o dot' 'digraph "ruby-27-centos7:latest"' +os::cmd::expect_success 'oc delete all -l build=sti' +echo "ex build-chain: ok" +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_start "cmd/admin/complex-scenarios" +# Make sure no one commits data with allocated values that could flake +os::cmd::expect_failure 'grep -r "clusterIP.*172" ${TEST_DATA}/app-scenarios' +os::cmd::expect_success 'oc adm new-project example --admin="createuser"' +os::cmd::expect_success 'oc project example' +os::cmd::try_until_success 'oc get serviceaccount default' +#os::cmd::expect_success 'oc create -f ${TEST_DATA}/app-scenarios' +os::cmd::expect_success 'oc status' +os::cmd::expect_success_and_text 'oc status -o dot' '"example"' +echo "complex-scenarios: ok" +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_start "cmd/admin/rolebinding-allowed" +# Admin can bind local roles without cluster-admin permissions +#os::cmd::expect_success "oc create -f ${TEST_DATA}/roles/empty-role.yaml -n '${project}'" +#os::cmd::expect_success 'oc adm policy add-role-to-user admin local-admin -n '${project}'' +#os::cmd::expect_success 'oc login -u local-admin -p pw' +#os::cmd::expect_success 'oc policy add-role-to-user empty-role other --role-namespace='${project}' -n '${project}'' +#os::cmd::expect_success 'oc login -u system:admin' +#os::cmd::expect_success "oc delete role/empty-role -n '${project}'" +echo "cmd/admin/rolebinding-allowed: ok" +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_start "cmd/admin/rolebinding-local-only" +# Admin cannot bind local roles from different namespace +otherproject='someotherproject' +#os::cmd::expect_success "oc new-project '${otherproject}'" +#os::cmd::expect_success "oc create -f ${TEST_DATA}/roles/empty-role.yaml -n '${project}'" +#os::cmd::expect_success 'oc adm policy add-role-to-user admin local-admin -n '${otherproject}'' +#os::cmd::expect_success 'oc login -u local-admin -p pw' +#os::cmd::expect_failure_and_text 'oc policy add-role-to-user empty-role other --role-namespace='${project}' -n '${otherproject}'' "role binding in namespace \"${otherproject}\" can't reference role in different namespace \"${project}\"" +#os::cmd::expect_success 'oc login -u system:admin' +#os::cmd::expect_success "oc delete role/empty-role -n '${project}'" +echo "rolebinding-local-only: ok" +os::test::junit::declare_suite_end + +#os::test::junit::declare_suite_start "cmd/admin/user-group-cascade" +## Create test users/identities and groups +#os::cmd::expect_success 'oc login -u cascaded-user -p pw' +#os::cmd::expect_success 'oc login -u orphaned-user -p pw' +#os::cmd::expect_success 'oc login -u system:admin' +## switch to using --template once template printing is available to all cmds through the genericclioptions printer +#os::cmd::expect_success_and_text 'oc adm groups new cascaded-group cascaded-user orphaned-user -o yaml' '\- cascaded\-user' +## switch to using --template once template printing is available to all cmds through the genericclioptions printer +#os::cmd::expect_success_and_text 'oc adm groups new orphaned-group cascaded-user orphaned-user -o yaml' '\- orphaned\-user' +## Add roles, sccs to users/groups +#os::cmd::expect_success 'oc adm policy add-scc-to-user restricted cascaded-user orphaned-user' +#os::cmd::expect_success 'oc adm policy add-scc-to-group restricted cascaded-group orphaned-group' +#os::cmd::expect_success 'oc adm policy add-role-to-user --rolebinding-name=cluster-admin cluster-admin cascaded-user orphaned-user -n default' +#os::cmd::expect_success 'oc adm policy add-role-to-group --rolebinding-name=cluster-admin cluster-admin cascaded-group orphaned-group -n default' +#os::cmd::expect_success 'oc adm policy add-cluster-role-to-user --rolebinding-name=cluster-admin cluster-admin cascaded-user orphaned-user' +#os::cmd::expect_success 'oc adm policy add-cluster-role-to-group --rolebinding-name=cluster-admin cluster-admin cascaded-group orphaned-group' +# +## Delete users +#os::cmd::expect_success 'oc adm prune auth user/cascaded-user' +#os::cmd::expect_success 'oc delete user cascaded-user' +#os::cmd::expect_success 'oc delete user orphaned-user --cascade=false' +## Verify all identities remain +#os::cmd::expect_success 'oc get identities/alwaysallow:cascaded-user' +#os::cmd::expect_success 'oc get identities/alwaysallow:orphaned-user' +## Verify orphaned user references are left +#os::cmd::expect_success_and_text "oc get clusterrolebindings/cluster-admins clusterrolebindings/cluster-admin -o jsonpath='{ .items[*].subjects }'" 'orphaned-user' +#os::cmd::expect_success_and_text "oc get rolebindings/cluster-admin --template='{{.subjects}}' -n default" 'orphaned-user' +#os::cmd::expect_success_and_text "oc get scc/restricted --template='{{.users}}'" 'orphaned-user' +#os::cmd::expect_success_and_text "oc get group/cascaded-group --template='{{.users}}'" 'orphaned-user' +## Verify cascaded user references are removed +#os::cmd::expect_success_and_not_text "oc get clusterrolebindings/cluster-admins clusterrolebindings/cluster-admin -o jsonpath='{ .items[*].subjects }'" 'cascaded-user' +#os::cmd::expect_success_and_not_text "oc get rolebindings/cluster-admin --template='{{.subjects}}' -n default" 'cascaded-user' +#os::cmd::expect_success_and_not_text "oc get scc/restricted --template='{{.users}}'" 'cascaded-user' +#os::cmd::expect_success_and_not_text "oc get group/cascaded-group --template='{{.users}}'" 'cascaded-user' +# +## Delete groups +#os::cmd::expect_success "oc adm prune auth group/cascaded-group" +#os::cmd::expect_success 'oc delete group cascaded-group' +#os::cmd::expect_success 'oc delete group orphaned-group --cascade=false' +## Verify orphaned group references are left +#os::cmd::expect_success_and_text "oc get clusterrolebindings/cluster-admins clusterrolebindings/cluster-admin -o jsonpath='{ .items[*].subjects }'" 'orphaned-group' +#os::cmd::expect_success_and_text "oc get rolebindings/cluster-admin --template='{{.subjects}}' -n default" 'orphaned-group' +#os::cmd::expect_success_and_text "oc get scc/restricted --template='{{.groups}}'" 'orphaned-group' +## Verify cascaded group references are removed +#os::cmd::expect_success_and_not_text "oc get clusterrolebindings/cluster-admins clusterrolebindings/cluster-admin -o jsonpath='{ .items[*].subjects }'" 'cascaded-group' +#os::cmd::expect_success_and_not_text "oc get rolebindings/cluster-admin --template='{{.subjects}}' -n default" 'cascaded-group' +#os::cmd::expect_success_and_not_text "oc get scc/restricted --template='{{.groups}}'" 'cascaded-group' +#echo "user-group-cascade: ok" +#os::test::junit::declare_suite_end + +os::test::junit::declare_suite_start "cmd/admin/serviceaccounts" +# create a new service account +os::cmd::expect_success_and_text 'oc create serviceaccount my-sa-name' 'serviceaccount/my-sa-name created' +os::cmd::expect_success 'oc get sa my-sa-name' + +# extract token and ensure it links us back to the service account +os::cmd::try_until_success 'oc sa get-token my-sa-name' +# TODO re-enable once we can use tokens instead of certs +#os::cmd::expect_success_and_text 'oc get user/~ --token="$( oc sa get-token my-sa-name )"' 'system:serviceaccount:.+:my-sa-name' + +# add a new token and ensure it links us back to the service account +# TODO re-enable once we can use tokens instead of certs +#os::cmd::expect_success_and_text 'oc get user/~ --token="$( oc sa new-token my-sa-name )"' 'system:serviceaccount:.+:my-sa-name' + +# add a new labeled token and ensure the label stuck +os::cmd::expect_success 'oc sa new-token my-sa-name --labels="mykey=myvalue,myotherkey=myothervalue"' +os::cmd::expect_success_and_text 'oc get secrets --selector="mykey=myvalue"' 'my-sa-name' +os::cmd::expect_success_and_text 'oc get secrets --selector="myotherkey=myothervalue"' 'my-sa-name' +os::cmd::expect_success_and_text 'oc get secrets --selector="mykey=myvalue,myotherkey=myothervalue"' 'my-sa-name' +echo "serviceacounts: ok" +os::test::junit::declare_suite_end + +# user creation +os::test::junit::declare_suite_start "cmd/admin/user-creation" +os::cmd::expect_success 'oc create user test-cmd-user' +os::cmd::expect_success 'oc create identity test-idp:test-uid' +os::cmd::expect_success 'oc create useridentitymapping test-idp:test-uid test-cmd-user' +os::cmd::expect_success_and_text 'oc describe identity test-idp:test-uid' 'test-cmd-user' +os::cmd::expect_success_and_text 'oc describe user test-cmd-user' 'test-idp:test-uid' +os::test::junit::declare_suite_end + +# images +os::test::junit::declare_suite_start "cmd/admin/images" + +# import image and check its information +os::cmd::expect_success "oc create -f ${TEST_DATA}/stable-busybox.yaml" +os::cmd::expect_success_and_text "oc adm top images" "sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6\W+default/busybox \(latest\)\W+\W+\W+yes\W+653\.4KiB" +os::cmd::expect_success_and_text "oc adm top imagestreams" "default/busybox\W+653\.4KiB\W+1\W+1" +os::cmd::expect_success "oc delete is/busybox -n default" + +# log in as an image-pruner and test that oc adm prune images works against the atomic binary +#os::cmd::expect_success "oc adm policy add-cluster-role-to-user system:image-pruner pruner --config='${MASTER_CONFIG_DIR}/admin.kubeconfig'" +#os::cmd::expect_success "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${MASTER_CONFIG_DIR}/server-ca.crt' -u pruner -p anything" +#os::cmd::expect_success_and_text "oc adm prune images" "Dry run enabled - no modifications will be made. Add --confirm to remove images" + +echo "images: ok" +os::test::junit::declare_suite_end + +# oc adm must-gather +os::test::junit::declare_suite_start "cmd/admin/must-gather" +os::cmd::expect_success "oc adm must-gather --help" +os::test::junit::declare_suite_end - # make sure non-existing --cluster and --user can still be set - os::cmd::expect_success_and_text "oc config set-context new-context-name --cluster=missing-cluster --user=missing-user --namespace=default --config='${NEW_CONFIG_LOC}'" 'Context "new-context-name" ' - os::cmd::expect_failure_and_text "env -u KUBERNETES_SERVICE_HOST -u KUBECONFIG -u KUBERNETES_MASTER oc get buildconfigs --config='${NEW_CONFIG_LOC}'" 'Missing or incomplete configuration info' - os::cmd::expect_failure_and_text "env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --config='${NEW_CONFIG_LOC}'" 'Missing or incomplete configuration info' -) -echo "config error handling: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdConfigShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdConfigSh, nil +func testExtendedTestdataCmdTestCmdAdminShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdAdminSh, nil } -func testExtendedTestdataCmdTestCmdConfigSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdConfigShBytes() +func testExtendedTestdataCmdTestCmdAdminSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdAdminShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/config.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/admin.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdConvertSh = []byte(`#!/bin/bash - -set -o errexit -set -o nounset -set -o pipefail - -OS_ROOT=$(dirname "${BASH_SOURCE}")/../.. -source "${OS_ROOT}/hack/lib/init.sh" -os::log::stacktrace::install +var _testExtendedTestdataCmdTestCmdAnnotationsSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT # Cleanup cluster resources created by this test ( set +e - oc delete all --all + oc delete all,templates --all exit 0 ) &>/dev/null -os::test::junit::declare_suite_start "cmd/convert" -# This test validates the convert command -os::cmd::expect_success "oc convert -f ${TEST_DATA}/convert/job-v1.yaml | grep 'apiVersion: batch/v1'" -os::cmd::expect_success "oc convert -f ${TEST_DATA}/convert/job-v2.json | grep 'apiVersion: batch/v1beta1'" +os::test::junit::declare_suite_start "cmd/annotate" +# This test validates empty values in key-value pairs set by the annotate command +os::cmd::expect_success_and_text 'oc create -f ${TEST_DATA}/hello-openshift/hello-pod.json' 'pod/hello-openshift created' +os::cmd::expect_success_and_text 'oc annotate pod hello-openshift node-selector=""' 'pod/hello-openshift annotated' +os::cmd::expect_success_and_not_text 'oc get pod hello-openshift --template="{{index .metadata.annotations \"node-selector\"}}"' '.' + +echo "annotate: ok" +os::test::junit::declare_suite_end -os::cmd::expect_success_and_text "oc convert -f ${TEST_DATA}/convert | oc create --dry-run -f -" 'job.batch/pi created' -os::cmd::expect_success_and_text "oc convert -f ${TEST_DATA}/convert | oc create --dry-run -f -" 'cronjob.batch/hello created' +os::test::junit::declare_suite_start "cmd/label" +# This test validates empty values in key-value pairs set by the label command +os::cmd::expect_success_and_text 'oc label pod hello-openshift label2=""' 'pod/hello-openshift labeled' +os::cmd::expect_success_and_not_text 'oc get pod hello-openshift --template="{{.metadata.labels.label2}}"' '.' -echo "convert: ok" +echo "label: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdConvertShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdConvertSh, nil +func testExtendedTestdataCmdTestCmdAnnotationsShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdAnnotationsSh, nil } -func testExtendedTestdataCmdTestCmdConvertSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdConvertShBytes() +func testExtendedTestdataCmdTestCmdAnnotationsSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdAnnotationsShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/convert.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/annotations.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdCreateSh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdApiresourcesSh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT -# Cleanup cluster resources created by this test -( - set +e - oc delete all,templates --all - exit 0 -) &>/dev/null +os::test::junit::declare_suite_start "cmd/apiresources" +os::cmd::expect_success_and_text 'oc api-resources' 'imagestreamtags' +os::cmd::expect_success_and_text 'oc api-resources --api-group=build.openshift.io' 'BuildConfig' +os::cmd::expect_success_and_text 'oc api-resources --namespaced=false' 'Image' +os::cmd::expect_success_and_text 'oc api-resources --verbs=get' 'project.openshift.io' -os::test::junit::declare_suite_start "cmd/create" -# validate --dry-run outputs correct success message -os::cmd::expect_success_and_text 'oc create quota quota --dry-run' 'resourcequota/quota created \(dry run\)' -# validate -- works in create -os::cmd::expect_success_and_text 'oc create deploymentconfig sleep --image=busybox -- /bin/sleep infinity' 'deploymentconfig.apps.openshift.io/sleep created' +os::cmd::expect_success_and_text 'oc api-versions' 'route.openshift.io/v1' -echo "oc create: ok" +echo "apiresources: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdCreateShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdCreateSh, nil +func testExtendedTestdataCmdTestCmdApiresourcesShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdApiresourcesSh, nil } -func testExtendedTestdataCmdTestCmdCreateSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdCreateShBytes() +func testExtendedTestdataCmdTestCmdApiresourcesSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdApiresourcesShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/create.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/apiresources.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdDebugSh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdAuthenticationSh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT +project="$( oc project -q )" +if [[ "${project}" == "default" ]]; then + echo "Test must be run from a non-default namespace" + exit 1 +fi + # Cleanup cluster resources created by this test ( set +e - oc delete all,templates --all + oc delete oauthaccesstokens --all + oc adm policy remove-cluster-role-from-user cluster-debugger user3 exit 0 ) &>/dev/null -os::test::junit::declare_suite_start "cmd/debug" -# This test validates the debug command -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-deployment-config.yaml' -os::cmd::expect_success_and_text "oc debug dc/test-deployment-config -o yaml" '\- /bin/sh' -os::cmd::expect_success_and_text "oc debug dc/test-deployment-config --keep-annotations -o yaml" 'annotations:' -os::cmd::expect_success_and_text "oc debug dc/test-deployment-config --as-root -o yaml" 'runAsUser: 0' -os::cmd::expect_success_and_text "oc debug dc/test-deployment-config --as-root=false -o yaml" 'runAsNonRoot: true' -os::cmd::expect_success_and_text "oc debug dc/test-deployment-config --as-user=1 -o yaml" 'runAsUser: 1' -os::cmd::expect_success_and_text "oc debug dc/test-deployment-config --keep-liveness --keep-readiness -o yaml" '' -os::cmd::expect_success_and_text "oc debug dc/test-deployment-config -o yaml -- /bin/env" '\- /bin/env' -os::cmd::expect_success_and_text "oc debug -t dc/test-deployment-config -o yaml" 'stdinOnce' -os::cmd::expect_success_and_text "oc debug -t dc/test-deployment-config -o yaml" 'tty' -os::cmd::expect_success_and_text "oc debug --v=8 -t dc/test-deployment-config -o yaml" "Response Headers" -os::cmd::expect_success_and_not_text "oc debug --tty=false dc/test-deployment-config -o yaml" 'tty' -os::cmd::expect_success_and_not_text "oc debug dc/test-deployment-config -o yaml -- /bin/env" 'stdin' -os::cmd::expect_success_and_not_text "oc debug dc/test-deployment-config -o yaml -- /bin/env" 'tty' -os::cmd::expect_failure_and_text "oc debug dc/test-deployment-config --node-name=invalid -- /bin/env" 'on node "invalid"' -# Does not require a real resource on the server -os::cmd::expect_success_and_not_text "oc debug -T -f ${TEST_DATA}/hello-openshift/hello-pod.json -o yaml" 'tty' -os::cmd::expect_success_and_text "oc debug -f ${TEST_DATA}/hello-openshift/hello-pod.json --keep-liveness --keep-readiness -o yaml" '' -os::cmd::expect_success_and_text "oc debug -f ${TEST_DATA}/hello-openshift/hello-pod.json -o yaml -- /bin/env" '\- /bin/env' -os::cmd::expect_success_and_not_text "oc debug -f ${TEST_DATA}/hello-openshift/hello-pod.json -o yaml -- /bin/env" 'stdin' -os::cmd::expect_success_and_not_text "oc debug -f ${TEST_DATA}/hello-openshift/hello-pod.json -o yaml -- /bin/env" 'tty' -# TODO: write a test that emulates a TTY to verify the correct defaulting of what the pod is created - -# Ensure debug does not depend on a container actually existing for the selected resource. -# The command should not hang waiting for an attachable pod. Timeout each cmd after 10s. -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-replication-controller.yaml' -os::cmd::expect_success 'oc scale --replicas=0 rc/test-replication-controller' -os::cmd::expect_success_and_text "oc debug --request-timeout=10s -c ruby-helloworld --one-container rc/test-replication-controller -o jsonpath='{.metadata.name}'" 'test-replication-controller-debug' - -os::cmd::expect_success 'oc scale --replicas=0 dc/test-deployment-config' -os::cmd::expect_success_and_text "oc debug --request-timeout=10s -c ruby-helloworld --one-container dc/test-deployment-config -o jsonpath='{.metadata.name}'" 'test-deployment-config' +os::test::junit::declare_suite_start "cmd/authentication" -tmp_deploy="$(mktemp)" -os::cmd::expect_success 'oc create -f - >> $tmp_deploy << __EOF__ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: test-deployment - labels: - deployment: test-deployment -spec: - replicas: 0 - selector: - matchLabels: - deployment: test-deployment - template: - metadata: - labels: - deployment: test-deployment - name: test-deployment - spec: - containers: - - name: ruby-helloworld - image: openshift/origin-pod - imagePullPolicy: IfNotPresent - resources: {} -status: {} -__EOF__' -os::cmd::expect_success_and_text "oc debug --request-timeout=10s -c ruby-helloworld --one-container deploy/test-deployment -o jsonpath='{.metadata.name}'" 'test-deployment-debug' +## Logging in prints useful messages +#os::test::junit::declare_suite_start "cmd/authentication/existing-credentials" +#os::cmd::expect_success_and_text 'oc login -u user1 -p pw' 'Login successful' +#os::cmd::expect_success_and_text 'oc login -u user2 -p pw' 'Login successful' +## Switching to another user using existing credentials informs you +#os::cmd::expect_success_and_text 'oc login -u user1' 'Logged into ".*" as "user1" using existing credentials' +## Completing a login as the same user using existing credentials informs you +#os::cmd::expect_success_and_text 'oc login -u user1' 'Logged into ".*" as "user1" using existing credentials' +## Return to the system:admin user +#os::cmd::expect_success "oc login -u system:admin -n '${project}'" +#os::test::junit::declare_suite_end +# +#os::test::junit::declare_suite_start "cmd/authentication/scopedtokens" +#os::cmd::expect_success 'oc adm policy add-role-to-user admin scoped-user' +# +## initialize the user object +#os::cmd::expect_success 'oc login -u scoped-user -p asdf' +#os::cmd::expect_success 'oc login -u system:admin' +#username="$(oc get user/scoped-user -o jsonpath='{.metadata.name}')" +#useruid="$(oc get user/scoped-user -o jsonpath='{.metadata.uid}')" +#os::cmd::expect_success_and_text "oc policy can-i --list -n '${project}' --as=scoped-user" 'get.*pods' +#os::cmd::expect_success "oc policy can-i --list --output=yaml" +#os::cmd::expect_success "oc policy can-i --list --output=json" +#os::cmd::expect_success "oc policy can-i --list" +# +#whoamitoken="$(oc process -f "${OS_ROOT}/test/testdata/authentication/scoped-token-template.yaml" TOKEN_PREFIX=whoami SCOPE=user:info USER_NAME="${username}" USER_UID="${useruid}" | oc create -f - -o name | awk -F/ '{print $2}')" +#os::cmd::expect_success_and_text "oc get user/~ --token='${whoamitoken}'" "${username}" +#os::cmd::expect_success_and_text "oc whoami --token='${whoamitoken}'" "${username}" +#os::cmd::expect_failure_and_text "oc get pods --token='${whoamitoken}' -n '${project}'" "pods is forbidden: User \"scoped-user\" cannot list resource \"pods\" in API group \"\" in the namespace \"${project}\"" +# +#listprojecttoken="$(oc process -f "${OS_ROOT}/test/testdata/authentication/scoped-token-template.yaml" TOKEN_PREFIX=listproject SCOPE=user:list-scoped-projects USER_NAME="${username}" USER_UID="${useruid}" | oc create -f - -o name | awk -F/ '{print $2}')" +## this token doesn't have rights to see any projects even though it can hit the list endpoint, so an empty list is correct +## we'll add another scope that allows listing all known projects even if this token has no other powers in them. +#os::cmd::expect_success_and_not_text "oc get projects --token='${listprojecttoken}'" "${project}" +#os::cmd::expect_failure_and_text "oc get user/~ --token='${listprojecttoken}'" 'User "scoped-user" cannot get resource "users" in API group "user.openshift.io" at the cluster scope' +#os::cmd::expect_failure_and_text "oc get pods --token='${listprojecttoken}' -n '${project}'" "User \"scoped-user\" cannot list resource \"pods\" in API group \"\" in the namespace \"${project}\"" +# +#listprojecttoken="$(oc process -f "${OS_ROOT}/test/testdata/authentication/scoped-token-template.yaml" TOKEN_PREFIX=listallprojects SCOPE=user:list-projects USER_NAME="${username}" USER_UID="${useruid}" | oc create -f - -o name | awk -F/ '{print $2}')" +#os::cmd::expect_success_and_text "oc get projects --token='${listprojecttoken}'" "${project}" +# +#adminnonescalatingpowerstoken="$(oc process -f "${OS_ROOT}/test/testdata/authentication/scoped-token-template.yaml" TOKEN_PREFIX=admin SCOPE=role:admin:* USER_NAME="${username}" USER_UID="${useruid}" | oc create -f - -o name | awk -F/ '{print $2}')" +#os::cmd::expect_failure_and_text "oc get user/~ --token='${adminnonescalatingpowerstoken}'" 'User "scoped-user" cannot get resource "users" in API group "user.openshift.io" at the cluster scope' +#os::cmd::expect_failure_and_text "oc get secrets --token='${adminnonescalatingpowerstoken}' -n '${project}'" "User \"scoped-user\" cannot list resource \"secrets\" in API group \"\" in the namespace \"${project}\"" +#os::cmd::expect_success_and_text "oc get 'projects/${project}' --token='${adminnonescalatingpowerstoken}' -n '${project}'" "${project}" +# +#allescalatingpowerstoken="$(oc process -f "${OS_ROOT}/test/testdata/authentication/scoped-token-template.yaml" TOKEN_PREFIX=clusteradmin SCOPE='role:cluster-admin:*:!' USER_NAME="${username}" USER_UID="${useruid}" | oc create -f - -o name | awk -F/ '{print $2}')" +#os::cmd::expect_success_and_text "oc get user/~ --token='${allescalatingpowerstoken}'" "${username}" +#os::cmd::expect_success "oc get secrets --token='${allescalatingpowerstoken}' -n '${project}'" +## scopes allow it, but authorization doesn't +#os::cmd::try_until_failure "oc get secrets --token='${allescalatingpowerstoken}' -n default" +#os::cmd::expect_failure_and_text "oc get secrets --token='${allescalatingpowerstoken}' -n default" 'cannot list resource "secrets" in API group "" in the namespace' +#os::cmd::expect_success_and_text "oc get projects --token='${allescalatingpowerstoken}'" "${project}" +#os::cmd::expect_success_and_text "oc policy can-i --list --token='${allescalatingpowerstoken}' -n '${project}'" 'get.*pods' +# +#accesstoken="$(oc process -f "${OS_ROOT}/test/testdata/authentication/scoped-token-template.yaml" TOKEN_PREFIX=access SCOPE=user:check-access USER_NAME="${username}" USER_UID="${useruid}" | oc create -f - -o name | awk -F/ '{print $2}')" +#os::cmd::expect_success_and_text "curl -k -XPOST -H 'Content-Type: application/json' -H 'Authorization: Bearer ${accesstoken}' '${API_SCHEME}://${API_HOST}:${API_PORT}/apis/authorization.openshift.io/v1/namespaces/${project}/localsubjectaccessreviews' -d '{\"kind\":\"LocalSubjectAccessReview\",\"apiVersion\":\"authorization.openshift.io/v1\",\"namespace\":\"${project}\",\"verb\":\"create\",\"resource\":\"pods\"}'" '"kind": "SubjectAccessReviewResponse"' +## verify group and kind defaulting works correctly +#os::cmd::expect_success_and_text "curl -k -XPOST -H 'Content-Type: application/json' -H 'Authorization: Bearer ${accesstoken}' '${API_SCHEME}://${API_HOST}:${API_PORT}/apis/authorization.openshift.io/v1/subjectaccessreviews' -d '{\"namespace\":\"${project}\",\"verb\":\"create\",\"resource\":\"pods\"}'" '"kind": "SubjectAccessReviewResponse"' +#os::cmd::expect_success_and_text "oc policy can-i create pods --token='${accesstoken}' -n '${project}' --ignore-scopes" 'yes' +#os::cmd::expect_success_and_text "oc policy can-i create pods --token='${accesstoken}' -n '${project}'" 'no' +#os::cmd::expect_success_and_text "oc policy can-i create subjectaccessreviews.authorization.openshift.io --token='${accesstoken}' -n '${project}'" 'no' +#os::cmd::expect_success_and_text "oc policy can-i create subjectaccessreviews.authorization.openshift.io --token='${accesstoken}' -n '${project}' --ignore-scopes" 'yes' +#os::cmd::expect_success_and_text "oc policy can-i create pods --token='${accesstoken}' -n '${project}' --scopes='role:admin:*'" 'yes' +#os::cmd::expect_success_and_text "oc policy can-i --list --token='${accesstoken}' -n '${project}' --scopes='role:admin:*'" 'get.*pods' +#os::cmd::expect_success_and_not_text "oc policy can-i --list --token='${accesstoken}' -n '${project}'" 'get.*pods' +# +#os::test::junit::declare_suite_end +# +#os::test::junit::declare_suite_start "cmd/authentication/debugging" +#os::cmd::expect_success_and_text 'oc login -u user3 -p pw' 'Login successful' +#os::cmd::expect_success 'oc login -u system:admin' +#os::cmd::expect_failure_and_text 'oc get --raw /debug/pprof/ --as=user3' 'Forbidden' +#os::cmd::expect_failure_and_text 'oc get --raw /metrics --as=user3' 'Forbidden' +#os::cmd::expect_success_and_text 'oc get --raw /healthz --as=user3' 'ok' +#os::cmd::expect_success 'oc adm policy add-cluster-role-to-user cluster-debugger user3' +#os::cmd::try_until_text 'oc get --raw /debug/pprof/ --as=user3' 'full goroutine stack dump' +#os::cmd::expect_success_and_text 'oc get --raw /debug/pprof/ --as=user3' 'full goroutine stack dump' +#os::cmd::expect_success_and_text 'oc get --raw /metrics --as=user3' 'apiserver_request_latencies' +#os::cmd::expect_success_and_text 'oc get --raw /healthz --as=user3' 'ok' +## TODO validate controller +#os::test::junit::declare_suite_end -# re-scale existing resources -os::cmd::expect_success 'oc scale --replicas=1 dc/test-deployment-config' +os::test::junit::declare_suite_start "cmd/authentication/scopedtokens" -os::cmd::expect_success 'oc create -f ${TEST_DATA}/image-streams/image-streams-centos7.json' -os::cmd::try_until_success 'oc get imagestreamtags wildfly:latest' -os::cmd::expect_success_and_text "oc debug istag/wildfly:latest -o yaml" 'image:.*cmd-debug/wildfly.*@' -sha="$( oc get istag/wildfly:latest --template '{{ .image.metadata.name }}' )" -os::cmd::expect_success_and_text "oc debug isimage/wildfly@${sha} -o yaml" 'image: docker.io/openshift/wildfly-150-centos7' -echo "debug: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdDebugShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdDebugSh, nil +func testExtendedTestdataCmdTestCmdAuthenticationShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdAuthenticationSh, nil } -func testExtendedTestdataCmdTestCmdDebugSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdDebugShBytes() +func testExtendedTestdataCmdTestCmdAuthenticationSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdAuthenticationShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/debug.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/authentication.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdDeploymentsSh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdBasicresourcesSh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT # Cleanup cluster resources created by this test ( set +e - oc delete all,templates --all + oc delete all,templates,secrets,pods,jobs --all + oc delete image v1-image + oc delete group patch-group + oc delete project test-project-admin + oc delete oauthaccesstokens.oauth.openshift.io/DYGZDLucARCPIfUeKPhsgPfn0WBLR_9KdeREH0c9iod + oc delete -f ${TEST_DATA}/multiport-service.yaml exit 0 ) &>/dev/null +function escape_regex() { + sed 's/[]\.|$(){}?+*^]/\\&/g' <<< "$*" +} -os::test::junit::declare_suite_start "cmd/deployments" -# This test validates deployments and the env command +project="$( oc project -q )" -os::cmd::expect_success 'oc get deploymentConfigs' -os::cmd::expect_success 'oc get dc' -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-deployment-config.yaml' -os::cmd::expect_success 'oc describe deploymentConfigs test-deployment-config' -os::cmd::expect_success_and_text 'oc get dc -o name' 'deploymentconfig.apps.openshift.io/test-deployment-config' -os::cmd::try_until_success 'oc get rc/test-deployment-config-1' -os::cmd::expect_success_and_text 'oc describe dc test-deployment-config' 'deploymentconfig=test-deployment-config' -os::cmd::expect_success_and_text 'oc status' 'dc/test-deployment-config deploys docker.io/openshift/origin-pod:latest' -os::cmd::expect_success 'oc create -f ${TEST_DATA}/hello-openshift/hello-pod.json' -os::cmd::try_until_text 'oc status' 'pod/hello-openshift runs openshift/hello-openshift' +os::test::junit::declare_suite_start "cmd/basicresources" +# This test validates basic resource retrieval and command interaction -os::test::junit::declare_suite_start "cmd/deployments/env" -# Patch a nil list -os::cmd::expect_success 'oc set env dc/test-deployment-config TEST=value' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'TEST=value' -# Remove only env in the list -os::cmd::expect_success 'oc set env dc/test-deployment-config TEST-' -os::cmd::expect_success_and_not_text 'oc set env dc/test-deployment-config --list' 'TEST=value' -# Add back to empty list -os::cmd::expect_success 'oc set env dc/test-deployment-config TEST=value' -os::cmd::expect_success_and_not_text 'oc set env dc/test-deployment-config TEST=foo --list' 'TEST=value' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config TEST=foo --list' 'TEST=foo' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config OTHER=foo --list' 'TEST=value' -os::cmd::expect_success_and_not_text 'oc set env dc/test-deployment-config OTHER=foo -c ruby --list' 'OTHER=foo' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config OTHER=foo -c ruby* --list' 'OTHER=foo' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config OTHER=foo -c *hello* --list' 'OTHER=foo' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config OTHER=foo -c *world --list' 'OTHER=foo' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config OTHER=foo --list' 'OTHER=foo' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config OTHER=foo -o yaml' 'name: OTHER' -os::cmd::expect_success_and_text 'echo OTHER=foo | oc set env dc/test-deployment-config -e - --list' 'OTHER=foo' -os::cmd::expect_success_and_not_text 'echo #OTHER=foo | oc set env dc/test-deployment-config -e - --list' 'OTHER=foo' -os::cmd::expect_success 'oc set env dc/test-deployment-config TEST=bar OTHER=baz BAR-' -os::cmd::expect_success_and_text 'oc set env -f ${TEST_DATA}/test-deployment-config.yaml TEST=VERSION -o yaml' 'v1' -os::cmd::expect_success 'oc set env dc/test-deployment-config A=a B=b C=c D=d E=e F=f G=g' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'A=a' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'B=b' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'C=c' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'D=d' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'E=e' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'F=f' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'G=g' -os::cmd::expect_success 'oc set env dc/test-deployment-config H=h G- E=updated C- A-' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'B=b' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'D=d' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'E=updated' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'F=f' -os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'H=h' -os::cmd::expect_success_and_not_text 'oc set env dc/test-deployment-config --list' 'A=a' -os::cmd::expect_success_and_not_text 'oc set env dc/test-deployment-config --list' 'C=c' -os::cmd::expect_success_and_not_text 'oc set env dc/test-deployment-config --list' 'G=g' -echo "env: ok" +os::test::junit::declare_suite_start "cmd/basicresources/versionreporting" +# Test to make sure that we're reporting the correct version information from endpoints and the correct +# User-Agent information from our clients regardless of which resources they're trying to access +#os::build::version::get_vars +#os_git_regex="$( escape_regex "${OS_GIT_VERSION%%-*}" )" +#kube_git_regex="$( escape_regex "${KUBE_GIT_VERSION%%-*}" )" +#etcd_version="$(echo "${ETCD_GIT_VERSION}" | sed -E "s/\-.*//g" | sed -E "s/v//")" +#etcd_git_regex="$( escape_regex "${etcd_version%%-*}" )" +#os::cmd::expect_success_and_text 'oc version' "Client Version: .*GitVersion:\"${os_git_regex}" +#os::cmd::expect_success_and_text 'oc version' "Server Version: .*GitVersion:\"${kube_git_regex}" +#os::cmd::expect_success_and_text "curl -k '${API_SCHEME}://${API_HOST}:${API_PORT}/version'" "${kube_git_regex}" +#os::cmd::expect_success_and_text "curl -k '${API_SCHEME}://${API_HOST}:${API_PORT}/version'" "${OS_GIT_COMMIT}" + +# variants I know I have to worry about +# 1. oc (kube and openshift resources) +# 2. oc adm (kube and openshift resources) + +# example User-Agent: oc/v1.2.0 (linux/amd64) kubernetes/bc4550d +#os::cmd::expect_success_and_text 'oc get pods --loglevel=7 2>&1 | grep -A4 "pods" | grep User-Agent' "oc/${kube_git_regex} .* kubernetes/" +## example User-Agent: oc/v1.2.0 (linux/amd64) kubernetes/bc4550d +#os::cmd::expect_success_and_text 'oc get dc --loglevel=7 2>&1 | grep -A4 "deploymentconfig" | grep User-Agent' "oc/${kube_git_regex} .* kubernetes/" +## example User-Agent: oc/v1.1.3 (linux/amd64) openshift/b348c2f +#os::cmd::expect_success_and_text 'oc adm policy who-can get pods --loglevel=7 2>&1 | grep -A4 "localresourceaccessreviews" | grep User-Agent' "oc/${kube_git_regex} .* kubernetes/" +#echo "version reporting: ok" os::test::junit::declare_suite_end -os::test::junit::declare_suite_start "cmd/deployments/config" -#os::cmd::expect_failure_and_text 'oc rollout latest test-deployment-config' 'already in progress' -#os::cmd::expect_failure_and_text 'oc rollout latest dc/test-deployment-config' 'already in progress' -## ensure that a cancelled deployment can be retried successfully -#os::cmd::expect_success 'oc rollout cancel dc/test-deployment-config' -#os::cmd::expect_success_and_text 'oc rollout retry dc/test-deployment-config' 'deploymentconfig.apps.openshift.io/test-deployment-config retried rollout' -#os::cmd::expect_success 'oc delete deploymentConfigs test-deployment-config' -echo "deploymentConfigs: ok" +os::test::junit::declare_suite_start "cmd/basicresources/status" +os::cmd::expect_success_and_text 'oc status -h' 'oc describe buildconfig' +os::cmd::expect_success_and_text 'oc status' 'oc new-app' +echo "status help output: ok" os::test::junit::declare_suite_end -os::cmd::expect_success 'oc delete all --all' -# TODO: remove, flake caused by deployment controller updating the following dc -sleep 1 -os::cmd::expect_success 'oc delete all --all' +os::test::junit::declare_suite_start "cmd/basicresources/explain" +os::cmd::expect_failure_and_text 'oc get' 'oc api-resources' +os::cmd::expect_success_and_text 'oc get all --loglevel=6' 'buildconfigs' +os::cmd::expect_success_and_text 'oc explain pods' 'Pod is a collection of containers that can run on a host' +os::cmd::expect_success_and_text 'oc explain pods.spec' 'SecurityContext holds pod-level security attributes' +# TODO unbreak explain +#os::cmd::expect_success_and_text 'oc explain deploymentconfig' 'a desired deployment state' +#os::cmd::expect_success_and_text 'oc explain deploymentconfig.spec' 'ensures that this deployment config will have zero replicas' +echo "explain: ok" +os::test::junit::declare_suite_end -os::cmd::expect_success 'oc process -f ${TEST_DATA}/application-template-dockerbuild.json -l app=dockerbuild | oc create -f -' -os::cmd::try_until_success 'oc get rc/database-1' +os::test::junit::declare_suite_start "cmd/basicresources/resource-builder" +# Test resource builder filtering of files with expected extensions inside directories, and individual files without expected extensions +os::cmd::expect_success 'oc create -f ${TEST_DATA}/resource-builder/directory -f ${TEST_DATA}/resource-builder/json-no-extension -f ${TEST_DATA}/resource-builder/yml-no-extension' +# Explicitly specified extensionless files +os::cmd::expect_success 'oc get secret json-no-extension yml-no-extension' +# Scanned files with extensions inside directories +os::cmd::expect_success 'oc get secret json-with-extension yml-with-extension' +# Ensure extensionless files inside directories are not processed by resource-builder +os::cmd::expect_failure_and_text 'oc get secret json-no-extension-in-directory' 'not found' +echo "resource-builder: ok" +os::test::junit::declare_suite_end -os::test::junit::declare_suite_start "cmd/deployments/get" -os::cmd::expect_success_and_text "oc get dc --show-labels" "app=dockerbuild,template=application-template-dockerbuild" -os::cmd::expect_success_and_text "oc get dc frontend --show-labels" "app=dockerbuild,template=application-template-dockerbuild" -os::cmd::expect_success_and_not_text "oc get dc" "app=dockerbuild,template=application-template-dockerbuild" -os::cmd::expect_success_and_not_text "oc get dc frontend" "app=dockerbuild,template=application-template-dockerbuild" -os::cmd::expect_success "oc process -f ${TEST_DATA}/old-template.json | oc create -f -" -os::cmd::expect_success_and_text "oc get dc/eap-app -o yaml" ":latest" -echo "get: ok" +os::test::junit::declare_suite_start "cmd/basicresources/pods" +os::cmd::expect_success 'oc get pods' +os::cmd::expect_success_and_text 'oc create -f ${TEST_DATA}/hello-openshift/hello-pod.json' 'pod/hello-openshift created' +os::cmd::expect_success 'oc describe pod hello-openshift' +os::cmd::expect_success 'oc delete pods hello-openshift --grace-period=0 --force' +echo "pods: ok" os::test::junit::declare_suite_end -os::test::junit::declare_suite_start "cmd/deployments/rollout" -os::cmd::try_until_success 'oc rollout pause dc/database' -os::cmd::try_until_text "oc get dc/database --template='{{.spec.paused}}'" "true" -os::cmd::try_until_success 'oc rollout resume dc/database' -os::cmd::try_until_text "oc get dc/database --template='{{.spec.paused}}'" "" -# create a replication controller and attempt to perform ` + "`" + `oc rollout cancel` + "`" + ` on it. -# expect an error about the resource type, rather than a panic or a success. -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-replication-controller.yaml' -os::cmd::expect_failure_and_text 'oc rollout cancel rc/test-replication-controller' 'expected deployment configuration, got replicationcontrollers' +os::test::junit::declare_suite_start "cmd/basicresources/label" +os::cmd::expect_success_and_text 'oc create -f ${TEST_DATA}/hello-openshift/hello-pod.json -o name' 'pod/hello-openshift' +os::cmd::try_until_success 'oc label pod/hello-openshift acustom=label' # can race against scheduling and status updates +os::cmd::expect_success_and_text 'oc describe pod/hello-openshift' 'acustom=label' +os::cmd::try_until_success 'oc annotate pod/hello-openshift foo=bar' # can race against scheduling and status updates +os::cmd::expect_success_and_text 'oc get -o yaml pod/hello-openshift' 'foo: bar' +os::cmd::expect_failure_and_not_text 'oc annotate pod hello-openshift description="test" --resource-version=123' 'may only be used with a single resource' +os::cmd::expect_failure_and_text 'oc annotate pod hello-openshift hello-openshift description="test" --resource-version=123' 'may only be used with a single resource' +os::cmd::expect_success 'oc delete pods -l acustom=label --grace-period=0 --force' +os::cmd::expect_failure 'oc get pod/hello-openshift' -echo "rollout: ok" +# show-labels should work for projects +os::cmd::expect_success "oc label namespace '${project}' foo=bar" +os::cmd::expect_success_and_text "oc get project '${project}' --show-labels" "foo=bar" + +echo "label: ok" os::test::junit::declare_suite_end -os::test::junit::declare_suite_start "cmd/deployments/rollback" -# should fail because there's no previous deployment -os::cmd::expect_failure 'oc rollback database --to-version=1 -o=yaml' -os::cmd::expect_failure 'oc rollback dc/database --to-version=1 -o=yaml' -os::cmd::expect_failure 'oc rollback dc/database --to-version=1 --dry-run' -os::cmd::expect_failure 'oc rollback database-1 -o=yaml' -os::cmd::expect_failure 'oc rollback rc/database-1 -o=yaml' -os::cmd::expect_failure 'oc rollback database -o yaml' -# trigger a new deployment with 'foo' image -os::cmd::expect_success 'oc set image dc/database ruby-helloworld-database=foo --source=docker' -# wait for the new deployment -os::cmd::try_until_success 'oc rollout history dc/database --revision=2' -# rolling back to the same revision should fail -os::cmd::expect_failure 'oc rollback dc/database --to-version=2' -# undo --dry-run should report the original image -os::cmd::expect_success_and_text 'oc rollout undo dc/database --dry-run' 'mysql-57-centos7' -echo "rollback: ok" +os::test::junit::declare_suite_start "cmd/basicresources/services" +os::cmd::expect_success 'oc get services' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-service.json' +os::cmd::expect_success 'oc delete services frontend' +echo "services: ok" os::test::junit::declare_suite_end -os::test::junit::declare_suite_start "cmd/deployments/stop" -os::cmd::expect_success 'oc get dc/database' -os::cmd::expect_success 'oc expose dc/database --name=fromdc' -# should be a service -os::cmd::expect_success 'oc get svc/fromdc' -os::cmd::expect_success 'oc delete svc/fromdc' -os::cmd::expect_success 'oc delete dc/database' -os::cmd::expect_failure 'oc get dc/database' -os::cmd::try_until_failure 'oc get rc/database-1' -echo "stop: ok" +# TODO rewrite the yaml for this test to actually work +os::test::junit::declare_suite_start "cmd/basicresources/list-version-conversion" +os::cmd::expect_success 'oc create -f ${TEST_DATA}/mixed-api-versions.yaml' +os::cmd::expect_success 'oc get -f ${TEST_DATA}/mixed-api-versions.yaml -o yaml' +os::cmd::expect_success 'oc label -f ${TEST_DATA}/mixed-api-versions.yaml mylabel=a' +os::cmd::expect_success 'oc annotate -f ${TEST_DATA}/mixed-api-versions.yaml myannotation=b' +# Make sure all six resources, with different API versions, got labeled and annotated +os::cmd::expect_success_and_text 'oc get -f ${TEST_DATA}/mixed-api-versions.yaml --output=jsonpath="{..metadata.labels.mylabel}"' 'a a a a' +os::cmd::expect_success_and_text 'oc get -f ${TEST_DATA}/mixed-api-versions.yaml --output=jsonpath="{..metadata.annotations.myannotation}"' 'b b b b' +os::cmd::expect_success 'oc delete -f ${TEST_DATA}/mixed-api-versions.yaml' +echo "list version conversion: ok" os::test::junit::declare_suite_end -os::test::junit::declare_suite_start "cmd/deployments/autoscale" -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-deployment-config.yaml' -os::cmd::expect_success 'oc autoscale dc/test-deployment-config --max 5' -os::cmd::expect_success_and_text "oc get hpa/test-deployment-config --template='{{.spec.maxReplicas}}'" "5" -os::cmd::expect_success_and_text "oc get hpa/test-deployment-config -o jsonpath='{.spec.scaleTargetRef.apiVersion}'" "apps.openshift.io/v1" -os::cmd::expect_success 'oc delete dc/test-deployment-config' -os::cmd::expect_success 'oc delete hpa/test-deployment-config' -echo "autoscale: ok" +os::test::junit::declare_suite_start "cmd/basicresources/nodes" +os::cmd::expect_success 'oc get nodes' +( + # subshell so we can unset kubeconfig + cfg="${KUBECONFIG}" + unset KUBECONFIG + os::cmd::expect_success "kubectl get nodes --kubeconfig='${cfg}'" +) +echo "nodes: ok" os::test::junit::declare_suite_end -os::test::junit::declare_suite_start "cmd/deployments/setimage" -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-deployment-config.yaml' -os::cmd::expect_success 'oc set image dc/test-deployment-config ruby-helloworld=myshinynewimage --source=docker' -os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o jsonpath='{.spec.template.spec.containers[0].image}'" "myshinynewimage" -os::cmd::expect_success 'oc delete dc/test-deployment-config' -echo "set image: ok" + +os::test::junit::declare_suite_start "cmd/basicresources/create" +os::cmd::expect_success 'oc create dc my-nginx --image=nginx' +os::cmd::expect_success 'oc delete dc my-nginx' +os::cmd::expect_success 'oc create clusterquota limit-bob --project-label-selector=openshift.io/requester=user-bob --hard=pods=10' +os::cmd::expect_success 'oc delete clusterquota/limit-bob' +echo "create subcommands: ok" os::test::junit::declare_suite_end -os::test::junit::declare_suite_start "cmd/deployments/setdeploymenthook" -# Validate the set deployment-hook command -arg="-f ${TEST_DATA}/test-deployment-config.yaml" -os::cmd::expect_failure_and_text "oc set deployment-hook" "error: one or more deployment configs" -os::cmd::expect_failure_and_text "oc set deployment-hook ${arg}" "error: you must specify one of --pre, --mid, or --post" -os::cmd::expect_failure_and_text "oc set deployment-hook ${arg} -o yaml --pre -- mycmd" 'deploymentconfigs.apps.openshift.io "test-deployment-config" not found' -os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local -o yaml --post -- mycmd" 'mycmd' -os::cmd::expect_success_and_not_text "oc set deployment-hook ${arg} --local -o yaml --post -- mycmd | oc set deployment-hook -f - --local -o yaml --post --remove" 'mycmd' -os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre -o yaml -- echo 'hello world'" 'pre:' -os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre -o yaml -- echo 'hello world'" 'execNewPod:' -os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre -o yaml -- echo 'hello world'" '\- echo' -os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre -o yaml -- echo 'hello world'" '\- hello world' -os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --post -o yaml -- echo 'hello world'" 'post:' -os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --mid -o yaml -- echo 'hello world'" 'mid:' -os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre --failure-policy=ignore -o yaml -- echo 'hello world'" 'failurePolicy: Ignore' -os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre --failure-policy=retry -o yaml -- echo 'hello world'" 'failurePolicy: Retry' -os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre --failure-policy=abort -o yaml -- echo 'hello world'" 'failurePolicy: Abort' -# Non-existent container -os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre --container=blah -o yaml -- echo 'hello world'" 'does not have a container named' -# Non-existent volume -os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre --volumes=blah -o yaml -- echo 'hello world'" 'does not have a volume named' -# Existing container -os::cmd::expect_success_and_not_text "oc set deployment-hook ${arg} --local --pre --container=ruby-helloworld -o yaml -- echo 'hello world'" 'does not have a container named' -os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre --container=ruby-helloworld -o yaml -- echo 'hello world'" 'containerName: ruby-helloworld' -# Existing volume -os::cmd::expect_success_and_not_text "oc set deployment-hook ${arg} --local --pre --volumes=vol1 -o yaml -- echo 'hello world'" 'does not have a volume named' -os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre --volumes=vol1 -o yaml -- echo 'hello world'" '\- vol1' -# Server object tests +os::test::junit::declare_suite_start "cmd/basicresources/statefulsets" +os::cmd::expect_success 'oc create -f ${TEST_DATA}/statefulset.yaml' +os::cmd::try_until_success 'oc get pods testapp-0' +os::cmd::expect_success_and_text 'oc describe statefulset testapp' 'app=testapp' +os::cmd::expect_success 'oc delete -f ${TEST_DATA}/statefulset.yaml' +echo "statefulsets: ok" +os::test::junit::declare_suite_end + + +os::test::junit::declare_suite_start "cmd/basicresources/setprobe" +# Validate the probe command +arg="-f ${TEST_DATA}/hello-openshift/hello-pod.json" +os::cmd::expect_failure_and_text "oc set probe" "error: one or more resources" +os::cmd::expect_failure_and_text "oc set probe ${arg}" "error: you must specify" +os::cmd::expect_failure_and_text "oc set probe ${arg} --local -o yaml --liveness --get-url=https://127.0.0.1/path" "port must be specified as part of a url" +os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness" 'livenessProbe: \{\}' +os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --initial-delay-seconds=10" "livenessProbe:" +os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --initial-delay-seconds=10" "initialDelaySeconds: 10" +os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness -- echo test" "livenessProbe:" +os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --readiness -- echo test" "readinessProbe:" +os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness -- echo test" "exec:" +os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness -- echo test" "\- echo" +os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness -- echo test" "\- test" +os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --open-tcp=3306" "tcpSocket:" +os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --open-tcp=3306" "port: 3306" +os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --open-tcp=port" "port: port" +os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --get-url=https://127.0.0.1:8080/path" "port: 8080" +os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --get-url=https://127.0.0.1:8080/path" "path: /path" +os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --get-url=https://127.0.0.1:8080/path" "scheme: HTTPS" +os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --get-url=http://127.0.0.1:8080/path" "scheme: HTTP" +os::cmd::expect_success_and_text "oc set probe ${arg} --local -o yaml --liveness --get-url=https://127.0.0.1:8080/path" "host: 127.0.0.1" os::cmd::expect_success "oc create -f ${TEST_DATA}/test-deployment-config.yaml" -os::cmd::expect_failure_and_text "oc set deployment-hook dc/test-deployment-config --pre" "you must specify a command" -os::cmd::expect_success_and_text "oc set deployment-hook test-deployment-config --pre -- echo 'hello world'" "updated" -os::cmd::expect_success_and_text "oc set deployment-hook dc/test-deployment-config --loglevel=1 --pre -- echo 'hello world'" "was not changed" -os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "pre:" -os::cmd::expect_success_and_text "oc set deployment-hook dc/test-deployment-config --pre --failure-policy=abort -- echo 'test'" "updated" -os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "failurePolicy: Abort" -os::cmd::expect_success_and_text "oc set deployment-hook --all --pre -- echo 'all dc'" "updated" -os::cmd::expect_success_and_text "oc get dc -o yaml" "all dc" -os::cmd::expect_success_and_text "oc set deployment-hook dc/test-deployment-config --pre --remove" "updated" -os::cmd::expect_success_and_not_text "oc get dc/test-deployment-config -o yaml" "pre:" -# Environment handling -os::cmd::expect_success_and_text "oc set deployment-hook dc/test-deployment-config --pre -o yaml --environment X=Y,Z=W -- echo 'test'" "value: Y,Z=W" -os::cmd::expect_success_and_text "oc set deployment-hook dc/test-deployment-config --pre -o yaml --environment X=Y,Z=W -- echo 'test'" "no longer accepts comma-separated list" -os::cmd::expect_success_and_not_text "oc set deployment-hook dc/test-deployment-config --pre -o yaml --environment X=Y -- echo 'test'" "no longer accepts comma-separated list" +os::cmd::expect_failure_and_text "oc set probe dc/test-deployment-config --liveness" "Required value: must specify a handler type" +os::cmd::expect_success_and_text "oc set probe dc test-deployment-config --liveness --open-tcp=8080" "updated" +os::cmd::expect_success_and_text "oc set probe dc/test-deployment-config --liveness --open-tcp=8080 --v=1" "was not changed" +os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "livenessProbe:" +os::cmd::expect_success_and_text "oc set probe dc/test-deployment-config --liveness --initial-delay-seconds=10" "updated" +os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "initialDelaySeconds: 10" +os::cmd::expect_success_and_text "oc set probe dc/test-deployment-config --liveness --initial-delay-seconds=20" "updated" +os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "initialDelaySeconds: 20" +os::cmd::expect_success_and_text "oc set probe dc/test-deployment-config --liveness --failure-threshold=2" "updated" +os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "initialDelaySeconds: 20" +os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "failureThreshold: 2" +os::cmd::expect_success_and_text "oc set probe dc/test-deployment-config --readiness --success-threshold=4 -- echo test" "updated" +os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "initialDelaySeconds: 20" +os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "successThreshold: 4" +os::cmd::expect_success_and_text "oc set probe dc test-deployment-config --liveness --period-seconds=5" "updated" +os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "periodSeconds: 5" +os::cmd::expect_success_and_text "oc set probe dc/test-deployment-config --liveness --timeout-seconds=6" "updated" +os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "timeoutSeconds: 6" +os::cmd::expect_success_and_text "oc set probe dc --all --liveness --timeout-seconds=7" "updated" +os::cmd::expect_success_and_text "oc get dc -o yaml" "timeoutSeconds: 7" +os::cmd::expect_success_and_text "oc set probe dc/test-deployment-config --liveness --remove" "updated" +os::cmd::expect_success_and_not_text "oc get dc/test-deployment-config -o yaml" "livenessProbe" +os::cmd::expect_success "oc delete dc/test-deployment-config" +echo "set probe: ok" +os::test::junit::declare_suite_end +os::test::junit::declare_suite_start "cmd/basicresources/setenv" +os::cmd::expect_success "oc create -f ${TEST_DATA}/test-deployment-config.yaml" +os::cmd::expect_success "oc create -f ${TEST_DATA}/test-buildcli.json" +os::cmd::expect_success_and_text "oc set env dc/test-deployment-config FOO=1st" "updated" +os::cmd::expect_success_and_text "oc set env dc/test-deployment-config FOO=2nd" "updated" +os::cmd::expect_success_and_text "oc set env dc/test-deployment-config FOO=bar --overwrite" "updated" +os::cmd::expect_failure_and_text "oc set env dc/test-deployment-config FOO=zee --overwrite=false" "already has a value" +os::cmd::expect_success_and_text "oc set env dc/test-deployment-config --list" "FOO=bar" +os::cmd::expect_success_and_text "oc set env dc/test-deployment-config FOO-" "updated" +os::cmd::expect_success_and_text "oc set env bc --all FOO=bar" "updated" +os::cmd::expect_success_and_text "oc set env bc --all --list" "FOO=bar" +os::cmd::expect_success_and_text "oc set env bc --all FOO-" "updated" +os::cmd::expect_success "oc create secret generic mysecret --from-literal='foo.bar=secret'" +os::cmd::expect_success_and_text "oc set env --from=secret/mysecret --prefix=PREFIX_ dc/test-deployment-config" "updated" +os::cmd::expect_success_and_text "oc set env dc/test-deployment-config --list" "PREFIX_FOO_BAR from secret mysecret, key foo.bar" +os::cmd::expect_success_and_text "oc set env dc/test-deployment-config --list --resolve" "PREFIX_FOO_BAR=secret" +os::cmd::expect_success "oc delete secret mysecret" +os::cmd::expect_failure_and_text "oc set env dc/test-deployment-config --list --resolve" "error retrieving reference for PREFIX_FOO_BAR" +# switch to view user to ensure view-only users can't get secrets through env var resolution +new="$(mktemp -d)/tempconfig" +os::cmd::expect_success "oc config view --raw > $new" +export KUBECONFIG=$new +project=$(oc project -q) +#os::cmd::expect_success 'oc policy add-role-to-user view view-user' +#os::cmd::expect_success 'oc login -u view-user -p anything' +#os::cmd::try_until_success 'oc project ${project}' +#os::cmd::expect_failure_and_text "oc set env dc/test-deployment-config --list --resolve" 'cannot get resource "secrets" in API group "" in the namespace' +#oc login -u system:admin +# clean up os::cmd::expect_success "oc delete dc/test-deployment-config" -echo "set deployment-hook: ok" +os::cmd::expect_success "oc delete bc/ruby-sample-build-validtag" +echo "set env: ok" os::test::junit::declare_suite_end +os::test::junit::declare_suite_start "cmd/basicresources/expose" +# Expose service as a route +os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-service.json' +os::cmd::expect_failure 'oc expose service frontend --create-external-load-balancer' +os::cmd::expect_failure 'oc expose service frontend --port=40 --type=NodePort' +os::cmd::expect_success 'oc expose service frontend --path=/test' +os::cmd::expect_success_and_text "oc get route.v1.route.openshift.io frontend --template='{{.spec.path}}'" "/test" +os::cmd::expect_success_and_text "oc get route.v1.route.openshift.io frontend --template='{{.spec.to.name}}'" "frontend" # routes to correct service +os::cmd::expect_success_and_text "oc get route.v1.route.openshift.io frontend --template='{{.spec.port.targetPort}}'" "" +os::cmd::expect_success 'oc delete svc,route -l name=frontend' +# Test that external services are exposable +os::cmd::expect_success 'oc create -f ${TEST_DATA}/external-service.yaml' +os::cmd::expect_success 'oc expose svc/external' +os::cmd::expect_success_and_text 'oc get route external' 'external' +os::cmd::expect_success 'oc delete route external' +os::cmd::expect_success 'oc delete svc external' +# Expose multiport service and verify we set a port in the route +os::cmd::expect_success 'oc create -f ${TEST_DATA}/multiport-service.yaml' +os::cmd::expect_success 'oc expose svc/frontend --name route-with-set-port' +os::cmd::expect_success_and_text "oc get route route-with-set-port --template='{{.spec.port.targetPort}}'" "web" +echo "expose: ok" os::test::junit::declare_suite_end -`) -func testExtendedTestdataCmdTestCmdDeploymentsShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdDeploymentsSh, nil -} +# Test OAuth access token describer +os::cmd::expect_success 'oc create -f ${TEST_DATA}/oauthaccesstoken.yaml' +os::cmd::expect_success_and_text "oc describe oauthaccesstoken DYGZDLucARCPIfUeKPhsgPfn0WBLR_9KdeREH0c9iod" "DYGZDLucARCPIfUeKPhsgPfn0WBLR_9KdeREH0c9iod" +echo "OAuth descriptor: ok" -func testExtendedTestdataCmdTestCmdDeploymentsSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdDeploymentsShBytes() - if err != nil { - return nil, err - } +os::cmd::expect_success 'oc delete all --all' - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/deployments.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +os::test::junit::declare_suite_start "cmd/basicresources/projectadmin" +# switch to test user to be sure that default project admin policy works properly +temp_config="$(mktemp -d)/tempconfig" +os::cmd::expect_success "oc config view --raw > '${temp_config}'" +export KUBECONFIG="${temp_config}" +#os::cmd::expect_success 'oc policy add-role-to-user admin project-admin' +#os::cmd::expect_success 'oc login -u project-admin -p anything' +#os::cmd::expect_success 'oc new-project test-project-admin' +#os::cmd::try_until_success "oc project test-project-admin" -var _testExtendedTestdataCmdTestCmdDescriberSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT +os::cmd::expect_success 'oc create deploymentconfig --image=image-registry.openshift-image-registry.svc:5000/openshift/tools:latest test' +os::cmd::expect_success 'oc run --image=image-registry.openshift-image-registry.svc:5000/openshift/tools:latest --restart=Never test3' +os::cmd::expect_success 'oc create job --image=image-registry.openshift-image-registry.svc:5000/openshift/tools:latest test4' +os::cmd::expect_success 'oc delete dc/test pod/test3 job/test4' -# Cleanup cluster resources created by this test -( - set +e - oc delete all,templates --all - exit 0 -) &>/dev/null +os::cmd::expect_success_and_text 'oc create deploymentconfig --dry-run foo --image=bar -o name' 'deploymentconfig.apps.openshift.io/foo' +os::cmd::expect_success_and_text 'oc run --dry-run foo --image=bar -o name --restart=Never' 'pod/foo' +os::cmd::expect_success_and_text 'oc create job --dry-run foo --image=bar -o name' 'job.batch/foo' +os::cmd::expect_success_and_text 'oc create deploymentconfig --dry-run foo --image=bar -o name' 'deploymentconfig.apps.openshift.io/foo' +os::cmd::expect_success_and_text 'oc run --dry-run foo --image=bar -o name --generator=run-pod/v1' 'pod/foo' +os::cmd::expect_success 'oc process -f ${TEST_DATA}/application-template-stibuild.json -l name=mytemplate | oc create -f -' +os::cmd::expect_success 'oc delete all -l name=mytemplate' +#os::cmd::expect_success 'oc new-app https://github.com/openshift/ruby-hello-world' +#os::cmd::expect_success 'oc get dc/ruby-hello-world' -os::test::junit::declare_suite_start "cmd/describe" -# This test validates non-duplicate errors when describing an existing resource without a defined describer -os::cmd::expect_success 'oc create -f - << __EOF__ -{ - "apiVersion": "v1", - "involvedObject": { - "apiVersion": "v1", - "kind": "Pod", - "name": "test-pod", - "namespace": "cmd-describer" - }, - "kind": "Event", - "message": "test message", - "metadata": { - "name": "test-event" - } -} -__EOF__ -' -os::cmd::try_until_success 'eventnum=$(oc get events | wc -l) && [[ $eventnum -gt 0 ]]' -# resources without describers get a default -os::cmd::expect_success_and_text 'oc describe events' 'Namespace:\s+cmd-describer' +#os::cmd::expect_success_and_text "oc get dc/ruby-hello-world --template='{{ .spec.replicas }}'" '1' +#patch='{"spec": {"replicas": 2}}' +#os::cmd::expect_success "oc patch dc/ruby-hello-world -p '${patch}'" +#os::cmd::expect_success_and_text "oc get dc/ruby-hello-world --template='{{ .spec.replicas }}'" '2' +# +#os::cmd::expect_success 'oc delete all -l app=ruby-hello-world' +#os::cmd::expect_failure 'oc get dc/ruby-hello-world' +echo "delete all: ok" +os::test::junit::declare_suite_end -# TemplateInstance -os::cmd::expect_success 'oc create -f ${TEST_DATA}/templateinstance_objectkinds.yaml' -os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'Name:\s+templateinstance' -os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'Namespace:\s+cmd-describer' -os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'Type:\s+Ready' -os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'Status:\s+True' -os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'Secret:\s+cmd-describer/secret' -os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'Deployment:\s+cmd-describer/deployment' -os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'Route:\s+cmd-describer/route' -os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'Route:\s+cmd-describer/newroute' -os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'NAME:\s+8 bytes' +# service accounts should not be allowed to request new projects +# TODO re-enable once we can use tokens instead of certs +#os::cmd::expect_failure_and_text "oc new-project --token='$( oc sa get-token builder )' will-fail" 'Error from server \(Forbidden\): You may not request a new project via this API.' + +os::test::junit::declare_suite_start "cmd/basicresources/patch" +# Validate patching works correctly +#os::cmd::expect_success 'oc login -u system:admin' +group_json='{"kind":"Group","apiVersion":"v1","metadata":{"name":"patch-group"}}' +os::cmd::expect_success "echo '${group_json}' | oc create -f -" +os::cmd::expect_success "oc patch group patch-group -p 'users: [\"myuser\"]' --loglevel=8" +os::cmd::expect_success_and_text 'oc get group patch-group -o yaml' 'myuser' +os::cmd::expect_success "oc patch group patch-group -p 'users: []' --loglevel=8" +# applying the same patch twice results in exit code 0, and "not patched" text +os::cmd::expect_success_and_text "oc patch group patch-group -p 'users: []'" "patched \(no change\)" +# applying an invalid patch results in exit code 1 and an error +os::cmd::expect_failure_and_text "oc patch group patch-group -p 'users: \"\"'" "cannot restore slice from string" +os::cmd::expect_success_and_text 'oc get group patch-group -o yaml' 'users: \[\]' +echo "patch: ok" +os::test::junit::declare_suite_end -echo "describer: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdDescriberShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdDescriberSh, nil +func testExtendedTestdataCmdTestCmdBasicresourcesShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdBasicresourcesSh, nil } -func testExtendedTestdataCmdTestCmdDescriberSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdDescriberShBytes() +func testExtendedTestdataCmdTestCmdBasicresourcesSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdBasicresourcesShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/describer.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/basicresources.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdEditSh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdBuildsSh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT @@ -32095,6450 +29350,3908 @@ trap os::test::junit::reconcile_output EXIT ) &>/dev/null -os::test::junit::declare_suite_start "cmd/edit" -# This test validates the edit command - -os::cmd::expect_success 'oc create -f ${TEST_DATA}/hello-openshift/hello-pod.json' - -os::cmd::expect_success_and_text 'OC_EDITOR=cat oc edit pod/hello-openshift' 'Edit cancelled' -os::cmd::expect_success_and_text 'OC_EDITOR=cat oc edit pod/hello-openshift' 'name: hello-openshift' -#os::cmd::expect_success_and_text 'OC_EDITOR=cat oc edit --windows-line-endings pod/hello-openshift | file -' 'CRLF' -#os::cmd::expect_success_and_not_text 'OC_EDITOR=cat oc edit --windows-line-endings=false pod/hello-openshift | file -' 'CRFL' - -os::cmd::expect_success 'oc create -f ${TEST_DATA}/services.yaml' -os::cmd::expect_success_and_text 'OC_EDITOR=cat oc edit svc' 'kind: List' - -os::cmd::expect_success 'oc create imagestream test' -os::cmd::expect_success 'oc tag --source=docker docker.io/busybox:latest test:new' -os::cmd::try_until_success 'oc get istag/test:new' -os::cmd::expect_success_and_not_text 'oc get istag/test:new -o jsonpath={.metadata.annotations}' "tags.?:.?hidden" -editorfile="$(mktemp -d)/tmp-editor.sh" -echo '#!/bin/bash' > ${editorfile} -echo 'sed -i "s/^tag: null/tag:\n referencePolicy:\n type: Source/g" $1' >> ${editorfile} -echo 'sed -i "s/^metadata:$/metadata:\n annotations:\n tags: hidden/g" $1' >> ${editorfile} -chmod +x ${editorfile} -os::cmd::expect_success "EDITOR=${editorfile} oc edit istag/test:new" -os::cmd::expect_success_and_text 'oc get istag/test:new -o jsonpath={.metadata.annotations}' "tags.?:.?hidden" - -echo "edit: ok" -os::test::junit::declare_suite_end -`) +url=":${API_PORT:-6443}" +project="$(oc project -q)" -func testExtendedTestdataCmdTestCmdEditShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdEditSh, nil -} +os::test::junit::declare_suite_start "cmd/builds" +# This test validates builds and build related commands +# Disabled because git is required in the container running the test +#os::cmd::expect_success 'oc new-build centos/ruby-26-centos7 https://github.com/openshift/ruby-hello-world.git' +#os::cmd::expect_success 'oc get bc/ruby-hello-world' -func testExtendedTestdataCmdTestCmdEditSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdEditShBytes() - if err != nil { - return nil, err - } +#os::cmd::expect_success "cat '${OS_ROOT}/examples/hello-openshift/Dockerfile' | oc new-build -D - --name=test" +#os::cmd::expect_success 'oc get bc/test' - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/edit.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +template='{{with .spec.output.to}}{{.kind}} {{.name}}{{end}}' -var _testExtendedTestdataCmdTestCmdEnvSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT +# Build from Dockerfile with output to ImageStreamTag +os::cmd::expect_success "oc new-build --to=tests:custom --dockerfile=\$'FROM image-registry.openshift-image-registry.svc:5000/openshift/tests:latest\nRUN yum install -y httpd'" +os::cmd::expect_success_and_text "oc get bc/tests --template '${template}'" '^ImageStreamTag tests:custom$' -os::test::junit::declare_suite_start "cmd/set-env" -# This test validates the value of --image for oc run -os::cmd::expect_success 'oc create deploymentconfig testdc --image=busybox' -os::cmd::expect_failure_and_text 'oc set env dc/testdc' 'error: at least one environment variable must be provided' -os::cmd::expect_success_and_text 'oc set env dc/testdc key=value' 'deploymentconfig.apps.openshift.io/testdc updated' -os::cmd::expect_success_and_text 'oc set env dc/testdc --list' 'deploymentconfigs/testdc, container default-container' -os::cmd::expect_success_and_text 'oc set env dc --all --containers="default-container" key-' 'deploymentconfig.apps.openshift.io/testdc updated' -os::cmd::expect_failure_and_text 'oc set env dc --all --containers="default-container"' 'error: at least one environment variable must be provided' -os::cmd::expect_failure_and_not_text 'oc set env --from=secret/mysecret dc/testdc' 'error: at least one environment variable must be provided' -os::cmd::expect_failure_and_text 'oc set env dc/testdc test#abc=1234' 'environment variable test#abc=1234 is invalid, a valid environment variable name must consist of alphabetic characters' +# Build from a binary with no inputs requires name +os::cmd::expect_failure_and_text "oc new-build --binary" "you must provide a --name" -# ensure deleting a var through --env does not result in an error message -os::cmd::expect_success_and_text 'oc set env dc/testdc key=value' 'deploymentconfig.apps.openshift.io/testdc updated' -os::cmd::expect_success_and_text 'oc set env dc/testdc dots.in.a.key=dots.in.a.value' 'deploymentconfig.apps.openshift.io/testdc updated' -os::cmd::expect_success_and_text 'oc set env dc --all --containers="default-container" --env=key-' 'deploymentconfig.apps.openshift.io/testdc updated' -# ensure deleting a var through --env actually deletes the env var -os::cmd::expect_success_and_not_text "oc get dc/testdc -o jsonpath='{ .spec.template.spec.containers[?(@.name==\"default-container\")].env }'" 'name.?\:.?key' -os::cmd::expect_success_and_text "oc get dc/testdc -o jsonpath='{ .spec.template.spec.containers[?(@.name==\"default-container\")].env }'" 'name.?\:.?dots.in.a.key' -os::cmd::expect_success_and_text 'oc set env dc --all --containers="default-container" --env=dots.in.a.key-' 'deploymentconfig.apps.openshift.io/testdc updated' -os::cmd::expect_success_and_not_text "oc get dc/testdc -o jsonpath='{ .spec.template.spec.containers[?(@.name==\"default-container\")].env }'" 'name.?\:.?dots.in.a.key' +# Build from a binary with inputs creates a binary build +os::cmd::expect_success "oc new-build --binary --name=binary-test" +os::cmd::expect_success_and_text "oc get bc/binary-test" 'Binary' -# check that env vars are not split at commas -os::cmd::expect_success_and_text 'oc set env -o yaml dc/testdc PASS=x,y=z' 'value: x,y=z' -os::cmd::expect_success_and_text 'oc set env -o yaml dc/testdc --env PASS=x,y=z' 'value: x,y=z' -# warning is printed when --env has comma in it -os::cmd::expect_success_and_text 'oc set env dc/testdc --env PASS=x,y=z' 'no longer accepts comma-separated list' -# warning is not printed for variables passed as positional arguments -os::cmd::expect_success_and_not_text 'oc set env dc/testdc PASS=x,y=z' 'no longer accepts comma-separated list' +os::cmd::expect_success 'oc delete is/binary-test bc/binary-test is/tests bc/tests' -# create a build-config object with the JenkinsPipeline strategy -os::cmd::expect_success 'oc process -p NAMESPACE=openshift -f ${TEST_DATA}/jenkins/jenkins-ephemeral-template.json | oc create -f -' -os::cmd::expect_success "echo 'apiVersion: v1 -kind: BuildConfig -metadata: - name: fake-pipeline -spec: - source: - git: - uri: git://github.com/openshift/ruby-hello-world.git - strategy: - jenkinsPipelineStrategy: {} -' | oc create -f -" +# Build from Dockerfile with output to DockerImage +os::cmd::expect_success "oc new-build -D \$'FROM image-registry.openshift-image-registry.svc:5000/openshift/tests:latest' --to-docker" +os::cmd::expect_success_and_text "oc get bc/tests --template '${template}'" '^DockerImage tests:latest$' -# ensure build-config has been created and that its type is "JenkinsPipeline" -os::cmd::expect_success_and_text "oc get bc fake-pipeline -o jsonpath='{ .spec.strategy.type }'" 'JenkinsPipeline' -# attempt to set an environment variable -os::cmd::expect_success_and_text 'oc set env bc/fake-pipeline FOO=BAR' 'buildconfig.build.openshift.io/fake\-pipeline updated' -# ensure environment variable was set -os::cmd::expect_success_and_text "oc get bc fake-pipeline -o jsonpath='{ .spec.strategy.jenkinsPipelineStrategy.env }'" 'name.?\:.?FOO' -os::cmd::expect_success 'oc delete bc fake-pipeline' +os::cmd::expect_success 'oc delete is/tests bc/tests' -echo "oc set env: ok" -os::test::junit::declare_suite_end -`) +# Build from Dockerfile with given output ImageStreamTag spec +os::cmd::expect_success "oc new-build -D \$'FROM image-registry.openshift-image-registry.svc:5000/openshift/tests:latest\nENV ok=1' --to origin-test:v1.1" +os::cmd::expect_success_and_text "oc get bc/origin-test --template '${template}'" '^ImageStreamTag origin-test:v1.1$' -func testExtendedTestdataCmdTestCmdEnvShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdEnvSh, nil -} +os::cmd::expect_success 'oc delete is/tests bc/origin-test' -func testExtendedTestdataCmdTestCmdEnvSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdEnvShBytes() - if err != nil { - return nil, err - } +# Build from Dockerfile with given output DockerImage spec +os::cmd::expect_success "oc new-build -D \$'FROM image-registry.openshift-image-registry.svc:5000/openshift/tests:latest\nENV ok=1' --to-docker --to openshift/origin:v1.1-test" +os::cmd::expect_success_and_text "oc get bc/origin --template '${template}'" '^DockerImage openshift/origin:v1.1-test$' - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/env.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +os::cmd::expect_success 'oc delete is/tests' -var _testExtendedTestdataCmdTestCmdFrameworkTestSh = []byte(`#!/usr/bin/env bash -# -# This script tests os::test::junit functionality. +# Build from Dockerfile with custom name and given output ImageStreamTag spec +os::cmd::expect_success "oc new-build -D \$'FROM image-registry.openshift-image-registry.svc:5000/openshift/tests:latest\nENV ok=1' --to origin-name-test --name origin-test2" +os::cmd::expect_success_and_text "oc get bc/origin-test2 --template '${template}'" '^ImageStreamTag origin-name-test:latest$' -function exit_trap() { - local return_code=$? +#os::cmd::try_until_text 'oc get is ruby-26-centos7' 'latest' +#os::cmd::expect_failure_and_text 'oc new-build ruby-26-centos7~https://github.com/sclorg/ruby-ex ruby-26-centos7~https://github.com/sclorg/ruby-ex --to invalid/argument' 'error: only one component with source can be used when specifying an output image reference' - end_time=$(date +%s) +os::cmd::expect_success 'oc delete all --all' - if [[ "${return_code}" -eq "0" ]]; then - verb="succeeded" - else - verb="failed" - fi +os::cmd::expect_success "oc new-build -D \$'FROM image-registry.openshift-image-registry.svc:5000/openshift/tests:latest' --no-output" +os::cmd::expect_success_and_not_text 'oc get bc/tests -o=jsonpath="{.spec.output.to}"' '.' - echo "$0 ${verb} after $((${end_time} - ${start_time})) seconds" - exit "${return_code}" -} +# Ensure output is valid JSON +#os::cmd::expect_success 'oc new-build -D "FROM image-registry.openshift-image-registry.svc:5000/openshift/tests:latest" -o json | python -m json.tool' -trap exit_trap EXIT +os::cmd::expect_success 'oc delete all --all' +os::cmd::expect_success 'oc process -f ${TEST_DATA}/application-template-dockerbuild.json -l build=docker | oc create -f -' +os::cmd::expect_success 'oc get buildConfigs' +os::cmd::expect_success 'oc get bc' +os::cmd::expect_success 'oc get builds' -start_time=$(date +%s) -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" +# make sure the imagestream has the latest tag before trying to test it or start a build with it +os::cmd::try_until_success 'oc get istag ruby-27-centos7:latest' -# envars used to track these interactions are not propagated out of the subshells used to run these commands -# therefore each os::cmd call is its own sandbox and complicated scenarios need to play out inside one call -# however, envars from this scope *are* propagated into each subshell, so they need to be cleared in each call +os::test::junit::declare_suite_start "cmd/builds/patch-anon-fields" +REAL_OUTPUT_TO=$(oc get bc/ruby-sample-build --template='{{ .spec.output.to.name }}') +os::cmd::expect_success "oc patch bc/ruby-sample-build -p '{\"spec\":{\"output\":{\"to\":{\"name\":\"different:tag1\"}}}}'" +os::cmd::expect_success_and_text "oc get bc/ruby-sample-build --template='{{ .spec.output.to.name }}'" 'different' +os::cmd::expect_success "oc patch bc/ruby-sample-build -p '{\"spec\":{\"output\":{\"to\":{\"name\":\"${REAL_OUTPUT_TO}\"}}}}'" +echo "patchAnonFields: ok" +os::test::junit::declare_suite_end -os::test::junit::declare_suite_start 'lib/test/junit' +os::test::junit::declare_suite_start "cmd/builds/config" +os::cmd::expect_success_and_text 'oc describe buildConfigs ruby-sample-build' "${url}/apis/build.openshift.io/v1/namespaces/${project}/buildconfigs/ruby-sample-build/webhooks//github" +os::cmd::expect_success_and_text 'oc describe buildConfigs ruby-sample-build' "Webhook GitHub" +os::cmd::expect_success_and_text 'oc describe buildConfigs ruby-sample-build' "${url}/apis/build.openshift.io/v1/namespaces/${project}/buildconfigs/ruby-sample-build/webhooks//generic" +os::cmd::expect_success_and_text 'oc describe buildConfigs ruby-sample-build' "Webhook Generic" +os::cmd::expect_success_and_text 'oc set triggers bc/ruby-sample-build --from-gitlab' "triggers updated" +os::cmd::expect_success_and_text 'oc set triggers bc/ruby-sample-build --from-bitbucket' "triggers updated" +os::cmd::expect_success 'oc start-build --list-webhooks=all ruby-sample-build' +os::cmd::expect_success_and_text 'oc start-build --list-webhooks=all bc/ruby-sample-build' 'generic' +os::cmd::expect_success_and_text 'oc start-build --list-webhooks=all ruby-sample-build' 'github' +os::cmd::expect_success_and_text 'oc start-build --list-webhooks=all ruby-sample-build' 'gitlab' +os::cmd::expect_success_and_text 'oc start-build --list-webhooks=all ruby-sample-build' 'bitbucket' +os::cmd::expect_success_and_text 'oc start-build --list-webhooks=github ruby-sample-build' '' +os::cmd::expect_failure 'oc start-build --list-webhooks=blah' +hook=$(oc start-build --list-webhooks='generic' ruby-sample-build | head -n 1) +hook=${hook//secret101} +os::cmd::expect_success_and_text "oc start-build --from-webhook=${hook}" "build.build.openshift.io/ruby-sample-build-[0-9] started" +os::cmd::expect_failure_and_text "oc start-build --from-webhook=${hook}/foo" "error: server rejected our request" +os::cmd::expect_success "oc patch bc/ruby-sample-build -p '{\"spec\":{\"strategy\":{\"dockerStrategy\":{\"from\":{\"name\":\"asdf:7\"}}}}}'" +os::cmd::expect_failure_and_text "oc start-build --from-webhook=${hook}" "Error resolving ImageStreamTag asdf:7" +os::cmd::expect_success 'oc get builds' +os::cmd::expect_success 'oc set triggers bc/ruby-sample-build --from-github --remove' +os::cmd::expect_success_and_not_text 'oc describe buildConfigs ruby-sample-build' "Webhook GitHub" +# make sure we describe webhooks using secretReferences properly +os::cmd::expect_success "oc patch bc/ruby-sample-build -p '{\"spec\":{\"triggers\":[{\"github\":{\"secretReference\":{\"name\":\"mysecret\"}},\"type\":\"GitHub\"}]}}'" +os::cmd::expect_success_and_text 'oc describe buildConfigs ruby-sample-build' "Webhook GitHub" +os::cmd::expect_success 'oc delete all -l build=docker' -# shouldn't be able to end a suite straight away -os::cmd::expect_failure_and_text 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT -os::test::junit::declare_suite_end' '\[ERROR\] jUnit suite marker could not be placed, expected suites in flight, got 0' -# should be able to start one straight away -os::cmd::expect_success 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT -os::test::junit::declare_suite_start whatever' -# should be able to start and end a suite -os::cmd::expect_success 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT -os::test::junit::declare_suite_start whatever -os::test::junit::declare_suite_end' -# should not be able to end more suites than are in flight -os::cmd::expect_failure_and_text 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT -os::test::junit::declare_suite_start whatever -os::test::junit::declare_suite_end -os::test::junit::declare_suite_end' '\[ERROR\] jUnit suite marker could not be placed, expected suites in flight, got 0' -# should not be able to end more suites than are in flight -os::cmd::expect_failure_and_text 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT -os::test::junit::declare_suite_start whatever -os::test::junit::declare_suite_start whateverelse -os::test::junit::declare_suite_end +echo "buildConfig: ok" os::test::junit::declare_suite_end -os::test::junit::declare_suite_end' '\[ERROR\] jUnit suite marker could not be placed, expected suites in flight, got 0' -# should be able to staart a test -os::cmd::expect_success 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT -os::test::junit::declare_suite_start whatever -os::test::junit::declare_test_start' -# shouldn't be able to end a test that hasn't been started -os::cmd::expect_failure_and_text 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT -os::test::junit::declare_test_end' '\[ERROR\] jUnit test marker could not be placed, expected one test in flight, got 0' -# should be able to start and end a test case -os::cmd::expect_success 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT -os::test::junit::declare_suite_start whatever -os::test::junit::declare_test_start -os::test::junit::declare_test_end' -# shouldn't be able to end too many test cases -os::cmd::expect_failure_and_text 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT -os::test::junit::declare_suite_start whatever -os::test::junit::declare_test_start -os::test::junit::declare_test_end -os::test::junit::declare_test_end' '\[ERROR\] jUnit test marker could not be placed, expected one test in flight, got 0' -# shouldn't be able to start a test without a suite -os::cmd::expect_failure_and_text 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT -os::test::junit::declare_test_start' '\[ERROR\] jUnit test marker could not be placed, expected suites in flight, got 0' +os::test::junit::declare_suite_start "cmd/builds/start-build" +os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-buildcli.json' +# a build for which there is not an upstream tag in the corresponding imagerepo, so +# the build should use the image field as defined in the buildconfig +# Use basename to transform "build/build-name" into "build-name" +started="$(basename $(oc start-build -o=name ruby-sample-build-invalidtag))" +os::cmd::expect_success_and_text "oc describe build ${started}" 'openshift/ruby$' +frombuild="$(basename $(oc start-build -o=name --from-build="${started}"))" +os::cmd::expect_success_and_text "oc describe build ${frombuild}" 'openshift/ruby$' +os::cmd::expect_failure_and_text "oc start-build ruby-sample-build-invalid-tag --from-dir=. --from-build=${started}" "cannot use '--from-build' flag with binary builds" +os::cmd::expect_failure_and_text "oc start-build ruby-sample-build-invalid-tag --from-file=. --from-build=${started}" "cannot use '--from-build' flag with binary builds" +os::cmd::expect_failure_and_text "oc start-build ruby-sample-build-invalid-tag --from-repo=. --from-build=${started}" "cannot use '--from-build' flag with binary builds" +# --incremental flag should override Spec.Strategy.SourceStrategy.Incremental +os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-s2i-build.json' +build_name="$(oc start-build -o=name test)" +os::cmd::expect_success_and_not_text "oc describe ${build_name}" 'Incremental Build' +build_name="$(oc start-build -o=name --incremental test)" +os::cmd::expect_success_and_text "oc describe ${build_name}" 'Incremental Build' +os::cmd::expect_success "oc patch bc/test -p '{\"spec\":{\"strategy\":{\"sourceStrategy\":{\"incremental\": true}}}}'" +build_name="$(oc start-build -o=name test)" +os::cmd::expect_success_and_text "oc describe ${build_name}" 'Incremental Build' +build_name="$(oc start-build -o=name --incremental=false test)" +os::cmd::expect_success_and_not_text "oc describe ${build_name}" 'Incremental Build' +os::cmd::expect_success "oc patch bc/test -p '{\"spec\":{\"strategy\":{\"sourceStrategy\":{\"incremental\": false}}}}'" +build_name="$(oc start-build -o=name test)" +os::cmd::expect_success_and_not_text "oc describe ${build_name}" 'Incremental Build' +build_name="$(oc start-build -o=name --incremental test)" +os::cmd::expect_success_and_text "oc describe ${build_name}" 'Incremental Build' +os::cmd::expect_failure_and_text "oc start-build test --no-cache" 'Cannot specify Docker build specific options' +os::cmd::expect_failure_and_text "oc start-build test --build-arg=a=b" 'Cannot specify Docker build specific options' +os::cmd::expect_success 'oc delete all --selector="name=test"' +# --no-cache flag should override Spec.Strategy.SourceStrategy.NoCache +os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-docker-build.json' +build_name="$(oc start-build -o=name test)" +os::cmd::expect_success_and_not_text "oc describe ${build_name}" 'No Cache' +build_name="$(oc start-build -o=name --no-cache test)" +os::cmd::expect_success_and_text "oc describe ${build_name}" 'No Cache' +os::cmd::expect_success "oc patch bc/test -p '{\"spec\":{\"strategy\":{\"dockerStrategy\":{\"noCache\": true}}}}'" +build_name="$(oc start-build -o=name test)" +os::cmd::expect_success_and_text "oc describe ${build_name}" 'No Cache' +build_name="$(oc start-build -o=name --no-cache=false test)" +os::cmd::expect_success_and_not_text "oc describe ${build_name}" 'No Cache' +os::cmd::expect_success "oc patch bc/test -p '{\"spec\":{\"strategy\":{\"dockerStrategy\":{\"noCache\": false}}}}'" +build_name="$(oc start-build -o=name test)" +os::cmd::expect_success_and_not_text "oc describe ${build_name}" 'No Cache' +build_name="$(oc start-build -o=name --no-cache test)" +os::cmd::expect_success_and_text "oc describe ${build_name}" 'No Cache' +os::cmd::expect_failure_and_text "oc start-build test --incremental" 'Cannot specify Source build specific options' +# ensure a specific version can be specified for buildconfigs +os::cmd::expect_failure_and_not_text "oc logs bc/test --version=1" "cannot specify a version and a build" +os::cmd::expect_success 'oc delete all --selector="name=test"' +echo "start-build: ok" +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_start "cmd/builds/cancel-build" +os::cmd::expect_success_and_text "oc cancel-build ${started} --dump-logs --restart" "build.build.openshift.io/${started} restarted" +os::cmd::expect_success 'oc delete all --all' +os::cmd::expect_success 'oc delete secret dbsecret' +os::cmd::expect_success 'oc process -f ${TEST_DATA}/application-template-dockerbuild.json -l build=docker | oc create -f -' +os::cmd::try_until_success 'oc get build/ruby-sample-build-1' +# Uses type/name resource syntax to cancel the build and check for proper message +os::cmd::expect_success_and_text 'oc cancel-build build/ruby-sample-build-1' 'build.build.openshift.io/ruby-sample-build-1 cancelled' +# Make sure canceling already cancelled build returns proper message +os::cmd::expect_success 'oc cancel-build build/ruby-sample-build-1' +# Cancel all builds from a build configuration +os::cmd::expect_success "oc start-build bc/ruby-sample-build" +os::cmd::expect_success "oc start-build bc/ruby-sample-build" +lastbuild="$(basename $(oc start-build -o=name bc/ruby-sample-build))" +os::cmd::expect_success_and_text 'oc cancel-build bc/ruby-sample-build' "build.build.openshift.io/${lastbuild} cancelled" +os::cmd::expect_success_and_text "oc get build ${lastbuild} -o template --template '{{.status.phase}}'" 'Cancelled' +builds=$(oc get builds -o template --template '{{range .items}}{{ .status.phase }} {{end}}') +for state in $builds; do + os::cmd::expect_success "[ \"${state}\" == \"Cancelled\" ]" +done +# Running this command again when all builds are cancelled should be no-op. +os::cmd::expect_success 'oc cancel-build bc/ruby-sample-build' +os::cmd::expect_success 'oc delete all --all' +os::cmd::expect_success 'oc delete secret dbsecret' +echo "cancel-build: ok" os::test::junit::declare_suite_end -`) - -func testExtendedTestdataCmdTestCmdFrameworkTestShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdFrameworkTestSh, nil -} - -func testExtendedTestdataCmdTestCmdFrameworkTestSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdFrameworkTestShBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/framework-test.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataCmdTestCmdGetSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT -# Cleanup cluster resources created by this test -( - set +e - oc delete all,templates --all - oc delete users.user.openshift.io test-user-1 - exit 0 -) &>/dev/null - - -os::test::junit::declare_suite_start "cmd/get" -os::cmd::expect_success_and_text 'oc create service loadbalancer testsvc1 --tcp=8080' "service/testsvc1 created" -# mixed resource output should print resource kind -# prefix even when only one type of resource is present -os::cmd::expect_success_and_text 'oc get all' "service/testsvc1" -# ensure that getting mixed resource types still returns prefixed resources, if there are at most resources of one type -os::cmd::expect_success_and_text 'oc get svc,pod' "service/testsvc1" -os::cmd::expect_failure_and_text 'oc get svc,pod testsvc1' "testsvc1" -# create second resource type and ensure that prefixed resource names are returned for both -os::cmd::expect_success_and_text 'oc create imagestream testimg1' "imagestream.image.openshift.io/testimg1 created" -os::cmd::expect_success_and_text 'oc get svc,is' "service/testsvc1" -# create second service and expect ` + "`" + `get all` + "`" + ` to still append resource kind to multiple of one type of resource -os::cmd::expect_success_and_text 'oc create service loadbalancer testsvc2 --tcp=8081' "service/testsvc2 created" -os::cmd::expect_success_and_text 'oc get all' "service/testsvc2" -# test tuples of same and different resource kinds (tuples of same resource kind should not return prefixed items). -os::cmd::expect_success_and_not_text 'oc get svc/testsvc1 svc/testsvc2' "service/testsvc1" -os::cmd::expect_success_and_text 'oc get svc/testsvc1 is/testimg1' "service/testsvc1" -os::cmd::expect_success_and_text 'oc get --v=8 svc/testsvc1 is/testimg1' "round_trippers.go" -# specific resources should not have their kind prefixed -os::cmd::expect_success_and_text 'oc get svc' "testsvc1" -# test --show-labels displays labels for users -os::cmd::expect_success 'oc create user test-user-1' -os::cmd::expect_success 'oc label user/test-user-1 customlabel=true' -os::cmd::expect_success_and_text 'oc get users test-user-1 --show-labels' "customlabel=true" -os::cmd::expect_success_and_not_text 'oc get users test-user-1' "customlabel=true" -# test structured and unstructured resources print generically without panic -os::cmd::expect_success_and_text 'oc get projectrequests -o yaml' 'status: Success' -os::cmd::expect_success_and_text 'oc get projectrequests,svc,pod -o yaml' 'kind: List' -# test --wacth does not result in an error when a resource list is served in multiple chunks -os::cmd::expect_success 'oc create cm cmone' -os::cmd::expect_success 'oc create cm cmtwo' -os::cmd::expect_success 'oc create cm cmthree' -os::cmd::expect_success_and_not_text 'oc get configmap --chunk-size=1 --watch --request-timeout=1s' 'watch is only supported on individual resources' -os::cmd::expect_success_and_not_text 'oc get configmap --chunk-size=1 --watch-only --request-timeout=1s' 'watch is only supported on individual resources' -echo "oc get: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdGetShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdGetSh, nil +func testExtendedTestdataCmdTestCmdBuildsShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdBuildsSh, nil } -func testExtendedTestdataCmdTestCmdGetSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdGetShBytes() +func testExtendedTestdataCmdTestCmdBuildsSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdBuildsShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/get.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/builds.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdHelpSh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdCompletionsSh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT -os::test::junit::declare_suite_start "cmd/help" -# This test validates the help commands and output text - -# verify some default commands -os::cmd::expect_success 'kubectl' -os::cmd::expect_success 'oc' -os::cmd::expect_success 'oc ex' -os::cmd::expect_failure 'origin' - -# help for root commands must be consistent -os::cmd::expect_success_and_text 'oc' 'OpenShift Client' -os::cmd::expect_success_and_text 'oc -h' 'Build and Deploy Commands:' -os::cmd::expect_success_and_text 'oc -h' 'Other Commands:' -os::cmd::expect_success_and_text 'oc policy --help' 'add-role-to-user' -os::cmd::expect_success_and_not_text 'oc policy --help' 'Other Commands' -os::cmd::expect_success_and_not_text 'oc -h' 'Options' -os::cmd::expect_success_and_not_text 'oc -h' 'Global Options' -os::cmd::expect_failure_and_text 'oc adm ca' 'Manage certificates' -os::cmd::expect_success_and_text 'oc exec --help' '\-\- COMMAND \[args\.\.\.\]$' -os::cmd::expect_success_and_text 'oc rsh --help' 'COMMAND' - -# help for root commands with --help flag must be consistent -os::cmd::expect_success_and_text 'oc --help' 'OpenShift Client' -os::cmd::expect_success_and_text 'oc login --help' 'Options' -os::cmd::expect_success_and_not_text 'oc login --help' 'Global Options' -os::cmd::expect_success_and_text 'oc login --help' 'insecure-skip-tls-verify' - -# help for given command with --help flag must be consistent -os::cmd::expect_success_and_text 'oc get --help' 'Display one or many resources' -os::cmd::expect_success_and_text 'oc project --help' 'Switch to another project' -os::cmd::expect_success_and_text 'oc projects --help' 'existing projects' -os::cmd::expect_success_and_text 'oc get --help' 'oc' - -# help for given command through help command must be consistent -os::cmd::expect_success_and_text 'oc help get' 'Display one or many resources' -os::cmd::expect_success_and_text 'oc help project' 'Switch to another project' -os::cmd::expect_success_and_text 'oc help projects' 'current active project and existing projects on the server' - -# help tips must be consistent -os::cmd::expect_success_and_text 'oc --help' 'Use "oc --help" for more information' -os::cmd::expect_success_and_text 'oc --help' 'Use "oc options" for a list of global' -os::cmd::expect_success_and_text 'oc help' 'Use "oc --help" for more information' -os::cmd::expect_success_and_text 'oc help' 'Use "oc options" for a list of global' -os::cmd::expect_success_and_text 'oc set --help' 'Use "oc set --help" for more information' -os::cmd::expect_success_and_text 'oc set --help' 'Use "oc options" for a list of global' -os::cmd::expect_success_and_text 'oc set env --help' 'Use "oc options" for a list of global' - -# runnable commands with required flags must error consistently -os::cmd::expect_failure_and_text 'oc get' 'Required resource not specified' - -# commands that expect file paths must validate and error out correctly -os::cmd::expect_failure_and_text 'oc login --certificate-authority=/path/to/invalid' 'no such file or directory' - -# make sure that typoed commands come back with non-zero return codes -os::cmd::expect_failure 'oc policy TYPO' -os::cmd::expect_failure 'oc secrets TYPO' +os::test::junit::declare_suite_start "cmd/completions" +# This test validates basic resource retrieval and command interaction -# make sure that LDAP group sync and prune exist under both experimental and ` + "`" + `oc adm` + "`" + ` -os::cmd::expect_success_and_text 'oc adm groups sync --help' 'external provider' -os::cmd::expect_success_and_text 'oc adm groups prune --help' 'external provider' -os::cmd::expect_success_and_text 'oc adm prune groups --help' 'external provider' +# test completion command help +os::cmd::expect_success_and_text "oc completion -h" "interactive completion of oc commands" +# test completion command output +os::cmd::expect_failure_and_text "oc completion" "Shell not specified." +os::cmd::expect_success "oc completion bash" +os::cmd::expect_success "oc completion zsh" +os::cmd::expect_failure_and_text "oc completion test_shell" 'Unsupported shell type "test_shell"' +echo "oc completion: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdHelpShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdHelpSh, nil +func testExtendedTestdataCmdTestCmdCompletionsShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdCompletionsSh, nil } -func testExtendedTestdataCmdTestCmdHelpSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdHelpShBytes() +func testExtendedTestdataCmdTestCmdCompletionsSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdCompletionsShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/help.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/completions.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdIdleSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" +var _testExtendedTestdataCmdTestCmdConfigSh = []byte(`#!/bin/bash + +set -o errexit +set -o nounset +set -o pipefail + +OS_ROOT=$(dirname "${BASH_SOURCE}")/../.. +source "${OS_ROOT}/hack/lib/init.sh" +os::log::stacktrace::install trap os::test::junit::reconcile_output EXIT # Cleanup cluster resources created by this test ( set +e - oc delete all,templates --all + oc delete all,templates,secrets --all exit 0 ) &>/dev/null -project="$(oc project -q)" -idled_at_annotation='idling.alpha.openshift.io/idled-at' -unidle_target_annotation='idling.alpha.openshift.io/unidle-targets' -prev_scale_annotation='idling.alpha.openshift.io/previous-scale' -idled_at_template="{{index .metadata.annotations \"${idled_at_annotation}\"}}" -unidle_target_template="{{index .metadata.annotations \"${unidle_target_annotation}\"}}" -prev_scale_template="{{index .metadata.annotations \"${prev_scale_annotation}\"}}" -dc_name="" - -setup_idling_resources() { - os::cmd::expect_success 'oc delete all --all' - - # set up resources for the idle command - os::cmd::expect_success 'oc create -f ${TEST_DATA}/idling-svc-route.yaml' - dc_name=$(basename $(oc create -f ${TEST_DATA}/idling-dc.yaml -o name)) # ` + "`" + `basename type/name` + "`" + ` --> name - os::cmd::expect_success "oc describe deploymentconfigs '${dc_name}'" - os::cmd::try_until_success 'oc describe endpoints idling-echo' - - # deployer pod won't work, so just scale up the rc ourselves - os::cmd::try_until_success "oc get replicationcontroller ${dc_name}-1" - os::cmd::expect_success "oc scale replicationcontroller ${dc_name}-1 --replicas=2" - os::cmd::try_until_text "oc get pod -l app=idling-echo -o go-template='{{ len .items }}'" "2" +# check to make sure that "get"ting a resource with no config file present +# still returns error indicating that no config-file is set +os::test::junit::declare_suite_start "cmd/configuration" +os::cmd::expect_success_and_not_text 'oc get bc' 'does not exist' +( + export HOME=/tmp + unset KUBECONFIG + unset KUBERNETES_MASTER - # wait for endpoints to populate. Ensure subset exists first to avoid nil dereference. - os::cmd::try_until_success "oc get endpoints idling-echo -o go-template='{{ index .subsets 0 }}'" - os::cmd::try_until_text "oc get endpoints idling-echo -o go-template='{{ len (index .subsets 0).addresses }}'" "2" -} + os::cmd::expect_failure_and_text 'env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --user=""' 'Missing or incomplete configuration info' + os::cmd::expect_failure_and_text 'env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --context=""' 'Missing or incomplete configuration info' + os::cmd::expect_failure_and_text 'env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --cluster=""' 'Missing or incomplete configuration info' -os::test::junit::declare_suite_start "cmd/idle/by-name" -setup_idling_resources -os::cmd::expect_failure "oc idle dc/${dc_name}" # make sure manually passing non-endpoints resources fails -os::cmd::expect_success_and_text 'oc idle idling-echo' "The service will unidle DeploymentConfig \"${project}/${dc_name}\" to 2 replicas once it receives traffic" -os::cmd::expect_success_and_text "oc get endpoints idling-echo -o go-template='${idled_at_template}'" '.' -#os::cmd::expect_success_and_text "oc get endpoints idling-echo -o go-template='${unidle_target_template}' | jq '.[] | select(.name == \"${dc_name}\") | (.replicas == 2 and .kind == \"DeploymentConfig\")'" 'true' -os::test::junit::declare_suite_end + os::cmd::expect_failure_and_text 'env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --context="test"' 'context was not found for specified context: test' + os::cmd::expect_failure_and_text 'env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --cluster="test"' 'no server found for cluster "test"' + # need some level of default (both upstream and here) to get the pretty auth message because you fail on namespace first. + os::cmd::expect_failure_and_text 'KUBERNETES_MASTER=anything env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --user="test"' 'auth info "test" does not exist' -os::test::junit::declare_suite_start "cmd/idle/by-label" -setup_idling_resources -os::cmd::expect_success_and_text 'oc idle -l app=idling-echo' "The service will unidle DeploymentConfig \"${project}/${dc_name}\" to 2 replicas once it receives traffic" -os::cmd::expect_success_and_text "oc get endpoints idling-echo -o go-template='${idled_at_template}'" '.' -#os::cmd::expect_success_and_text "oc get endpoints idling-echo -o go-template='${unidle_target_template}' | jq '.[] | select(.name == \"${dc_name}\") | (.replicas == 2 and .kind == \"DeploymentConfig\")'" 'true' -os::test::junit::declare_suite_end + os::cmd::expect_failure_and_text 'oc get bc --kubeconfig=missing' 'missing: no such file or directory' -os::test::junit::declare_suite_start "cmd/idle/all" -setup_idling_resources -os::cmd::expect_success_and_text 'oc idle --all' "The service will unidle DeploymentConfig \"${project}/${dc_name}\" to 2 replicas once it receives traffic" -os::cmd::expect_success_and_text "oc get endpoints idling-echo -o go-template='${idled_at_template}'" '.' -#os::cmd::expect_success_and_text "oc get endpoints idling-echo -o go-template='${unidle_target_template}' | jq '.[] | select(.name == \"${dc_name}\") | (.replicas == 2 and .kind == \"DeploymentConfig\")'" 'true' -os::test::junit::declare_suite_end + # define temp location for new config + NEW_CONFIG_LOC="${BASETMPDIR}/new-config.yaml" -os::test::junit::declare_suite_start "cmd/idle/check-previous-scale" -setup_idling_resources # scales up to 2 replicas -os::cmd::expect_success_and_text 'oc idle idling-echo' "The service will unidle DeploymentConfig \"${project}/${dc_name}\" to 2 replicas once it receives traffic" -os::cmd::expect_success_and_text "oc get dc ${dc_name} -o go-template='${prev_scale_template}'" '2' # we see the result of the initial scale as the previous scale + # make sure non-existing --cluster and --user can still be set + os::cmd::expect_success_and_text "oc config set-context new-context-name --cluster=missing-cluster --user=missing-user --namespace=default --kubeconfig='${NEW_CONFIG_LOC}'" 'Context "new-context-name" ' + os::cmd::expect_failure_and_text "env -u KUBERNETES_SERVICE_HOST -u KUBECONFIG -u KUBERNETES_MASTER oc get buildconfigs --kubeconfig='${NEW_CONFIG_LOC}'" 'Missing or incomplete configuration info' + os::cmd::expect_failure_and_text "env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --kubeconfig='${NEW_CONFIG_LOC}'" 'Missing or incomplete configuration info' +) +echo "config error handling: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdIdleShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdIdleSh, nil +func testExtendedTestdataCmdTestCmdConfigShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdConfigSh, nil } -func testExtendedTestdataCmdTestCmdIdleSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdIdleShBytes() +func testExtendedTestdataCmdTestCmdConfigSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdConfigShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/idle.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/config.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdImageLookupSh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdCreateSh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT # Cleanup cluster resources created by this test ( set +e - oc delete all,is,pods --all - + oc delete all,templates --all exit 0 -) &> /dev/null +) &>/dev/null -project="$( oc project -q )" -os::test::junit::declare_suite_start "cmd/image-lookup" -## This test validates image lookup resolution -# -## TODO: fix and re-enable these tests before 4.0 release -# -## Verify image resolution on default resource types -os::cmd::expect_success_and_text "oc import-image --confirm --from=nginx:latest nginx:latest" "sha256:" -os::cmd::expect_success_and_text "oc set image-lookup is/nginx" "updated" -## Image lookup works for pods -os::cmd::expect_success "oc run --generator=run-pod/v1 --restart=Never --image=nginx:latest nginx" -os::cmd::expect_success_and_text "oc get pod/nginx -o jsonpath='{.spec.containers[0].image}'" "nginx@sha256:" -## Image lookup works for jobs -os::cmd::expect_success "oc create job --image=nginx:latest nginx" -os::cmd::expect_success_and_text "oc get job/nginx -o jsonpath='{.spec.template.spec.containers[0].image}'" "nginx@sha256:" -## Image lookup works for replica sets -os::cmd::expect_success "oc create deployment --image=nginx:latest nginx" -os::cmd::expect_success_and_text "oc get rs -o jsonpath='{..spec.template.spec.containers[0].image}'" "nginx@sha256:" -## Image lookup works for replication controllers -rc='{"kind":"ReplicationController","apiVersion":"v1","metadata":{"name":"nginx"},"spec":{"template":{"metadata":{"labels":{"app":"test"}},"spec":{"containers":[{"name":"main","image":"nginx:latest"}]}}}}' -os::cmd::expect_success "echo '${rc}' | oc create -f -" -os::cmd::expect_success_and_text "oc get rc/nginx -o jsonpath='{.spec.template.spec.containers[0].image}'" "nginx@sha256:" -# -## Verify swapping settings on image stream -os::cmd::expect_success_and_text "oc set image-lookup is/nginx --v=1" "was not changed" -os::cmd::expect_success_and_text "oc set image-lookup nginx --v=1" "was not changed" -os::cmd::expect_success_and_text "oc set image-lookup is --list" "nginx.*true" -os::cmd::expect_success_and_text "oc set image-lookup nginx --enabled=false" "updated" -os::cmd::expect_success_and_text "oc set image-lookup is --list" "nginx.*false" -os::cmd::expect_failure_and_text "oc set image-lookup unknown --list" "the server doesn't have a resource type" -os::cmd::expect_success_and_text "oc set image-lookup secrets --list" "false" -# -## Clear resources -os::cmd::expect_success "oc delete deploy,dc,rs,rc,pods --all" -# -## Resource annotated with image lookup will create pods that resolve -os::cmd::expect_success "oc tag nginx:latest alternate:latest" -rc='{"kind":"Deployment","apiVersion":"apps/v1","metadata":{"name":"alternate"},"spec":{"selector":{"matchLabels":{"app":"test"}},"template":{"metadata":{"labels":{"app":"test"}},"spec":{"containers":[{"name":"main","image":"alternate:latest"}]}}}}' -os::cmd::expect_success "echo '${rc}' | oc set image-lookup --local -f - -o json | oc create -f -" -os::cmd::expect_success "oc run --generator=run-pod/v1 --restart=Never --image=alternate:latest alternate" -os::cmd::expect_success_and_text "oc get pod/alternate -o jsonpath='{.spec.containers[0].image}'" "alternate:latest" -os::cmd::expect_success_and_text "oc get rs -o jsonpath='{..spec.template.spec.containers[0].image}'" "nginx@sha256:" +os::test::junit::declare_suite_start "cmd/create" +# validate --dry-run outputs correct success message +os::cmd::expect_success_and_text 'oc create quota quota --dry-run' 'resourcequota/quota created \(dry run\)' +# validate -- works in create +os::cmd::expect_success_and_text 'oc create deploymentconfig sleep --image=busybox -- /bin/sleep infinity' 'deploymentconfig.apps.openshift.io/sleep created' +echo "oc create: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdImageLookupShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdImageLookupSh, nil +func testExtendedTestdataCmdTestCmdCreateShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdCreateSh, nil } -func testExtendedTestdataCmdTestCmdImageLookupSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdImageLookupShBytes() +func testExtendedTestdataCmdTestCmdCreateSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdCreateShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/image-lookup.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/create.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdImagesSh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdDeploymentsSh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT # Cleanup cluster resources created by this test ( set +e - original_context="$( oc config current-context )" - os::cmd::expect_success 'oc login -u system:admin' - cluster_admin_context="$( oc config current-context )" - os::cmd::expect_success "oc config use-context '${original_context}'" - oc delete project test-cmd-images-2 merge-tags --context=${cluster_admin_context} - oc delete all,templates --all --context=${cluster_admin_context} - + oc delete all,templates --all exit 0 -) &> /dev/null +) &>/dev/null -project="$( oc project -q )" -os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}" -# This test validates images and image streams along with the tag and import-image commands +os::test::junit::declare_suite_start "cmd/deployments" +# This test validates deployments and the env command -# some steps below require that we use system:admin privileges, but we don't -# want to stomp on whatever context we were given when we started -original_context="$( oc config current-context )" -os::cmd::expect_success 'oc login -u system:admin' -cluster_admin_context="$( oc config current-context )" -os::cmd::expect_success "oc config use-context '${original_context}'" +os::cmd::expect_success 'oc get deploymentConfigs' +os::cmd::expect_success 'oc get dc' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-deployment-config.yaml' +os::cmd::expect_success 'oc describe deploymentConfigs test-deployment-config' +os::cmd::expect_success_and_text 'oc get dc -o name' 'deploymentconfig.apps.openshift.io/test-deployment-config' +os::cmd::try_until_success 'oc get rc/test-deployment-config-1' +os::cmd::expect_success_and_text 'oc describe dc test-deployment-config' 'deploymentconfig=test-deployment-config' +os::cmd::expect_success_and_text 'oc status' 'dc/test-deployment-config deploys image-registry.openshift-image-registry.svc:5000/openshift/tools:latest' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/hello-openshift/hello-pod.json' +os::cmd::try_until_text 'oc status' 'pod/hello-openshift runs' -os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/images" -os::cmd::expect_success "oc get images --context='${cluster_admin_context}'" -os::cmd::expect_success "oc create -f '${TEST_DATA}/test-image.json' --context='${cluster_admin_context}'" -os::cmd::expect_success "oc delete images test --context='${cluster_admin_context}'" -echo "images: ok" +os::test::junit::declare_suite_start "cmd/deployments/env" +# Patch a nil list +os::cmd::expect_success 'oc set env dc/test-deployment-config TEST=value' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'TEST=value' +# Remove only env in the list +os::cmd::expect_success 'oc set env dc/test-deployment-config TEST-' +os::cmd::expect_success_and_not_text 'oc set env dc/test-deployment-config --list' 'TEST=value' +# Add back to empty list +os::cmd::expect_success 'oc set env dc/test-deployment-config TEST=value' +os::cmd::expect_success_and_not_text 'oc set env dc/test-deployment-config TEST=foo --list' 'TEST=value' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config TEST=foo --list' 'TEST=foo' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config OTHER=foo --list' 'TEST=value' +os::cmd::expect_success_and_not_text 'oc set env dc/test-deployment-config OTHER=foo -c ruby --list' 'OTHER=foo' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config OTHER=foo -c ruby* --list' 'OTHER=foo' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config OTHER=foo -c *hello* --list' 'OTHER=foo' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config OTHER=foo -c *world --list' 'OTHER=foo' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config OTHER=foo --list' 'OTHER=foo' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config OTHER=foo -o yaml' 'name: OTHER' +os::cmd::expect_success_and_text 'echo OTHER=foo | oc set env dc/test-deployment-config -e - --list' 'OTHER=foo' +os::cmd::expect_success_and_not_text 'echo #OTHER=foo | oc set env dc/test-deployment-config -e - --list' 'OTHER=foo' +os::cmd::expect_success 'oc set env dc/test-deployment-config TEST=bar OTHER=baz BAR-' +os::cmd::expect_success_and_text 'oc set env -f ${TEST_DATA}/test-deployment-config.yaml TEST=VERSION -o yaml' 'v1' +os::cmd::expect_success 'oc set env dc/test-deployment-config A=a B=b C=c D=d E=e F=f G=g' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'A=a' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'B=b' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'C=c' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'D=d' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'E=e' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'F=f' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'G=g' +os::cmd::expect_success 'oc set env dc/test-deployment-config H=h G- E=updated C- A-' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'B=b' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'D=d' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'E=updated' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'F=f' +os::cmd::expect_success_and_text 'oc set env dc/test-deployment-config --list' 'H=h' +os::cmd::expect_success_and_not_text 'oc set env dc/test-deployment-config --list' 'A=a' +os::cmd::expect_success_and_not_text 'oc set env dc/test-deployment-config --list' 'C=c' +os::cmd::expect_success_and_not_text 'oc set env dc/test-deployment-config --list' 'G=g' +echo "env: ok" os::test::junit::declare_suite_end -os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/imagestreams" -os::cmd::expect_success 'oc get imageStreams' -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-image-stream.json' -# can't check status since there is no registry running so internalRegistryHostname isn't populated. -#os::cmd::expect_success_and_text "oc get imageStreams test --template='{{.status.dockerImageRepository}}'" 'test' -os::cmd::expect_success 'oc delete imageStreams test' -os::cmd::expect_failure 'oc get imageStreams test' - -os::cmd::expect_success 'oc create -f ${TEST_DATA}/image-streams/image-streams-centos7.json' -# can't check status since there is no registry running so internalRegistryHostname isn't populated. -#os::cmd::expect_success_and_text "oc get imageStreams ruby --template='{{.status.dockerImageRepository}}'" 'ruby' -#os::cmd::expect_success_and_text "oc get imageStreams nodejs --template='{{.status.dockerImageRepository}}'" 'nodejs' -#os::cmd::expect_success_and_text "oc get imageStreams wildfly --template='{{.status.dockerImageRepository}}'" 'wildfly' -#os::cmd::expect_success_and_text "oc get imageStreams mysql --template='{{.status.dockerImageRepository}}'" 'mysql' -#os::cmd::expect_success_and_text "oc get imageStreams postgresql --template='{{.status.dockerImageRepository}}'" 'postgresql' -#os::cmd::expect_success_and_text "oc get imageStreams mongodb --template='{{.status.dockerImageRepository}}'" 'mongodb' -#os::cmd::expect_success_and_text "oc get imageStreams httpd --template='{{.status.dockerImageRepository}}'" 'httpd' - -# verify the image repository had its tags populated -os::cmd::try_until_success 'oc get imagestreamtags wildfly:latest' -os::cmd::expect_success_and_text "oc get imageStreams wildfly --template='{{ index .metadata.annotations \"openshift.io/image.dockerRepositoryCheck\"}}'" '[0-9]{4}\-[0-9]{2}\-[0-9]{2}' # expect a date like YYYY-MM-DD -os::cmd::expect_success_and_text 'oc get istag' 'wildfly' - -# create an image stream and post a mapping to it -#os::cmd::expect_success 'oc create imagestream test' -#os::cmd::expect_success 'oc create -f test/testdata/mysql-image-stream-mapping.yaml' -#os::cmd::expect_success_and_text 'oc get istag/test:new --template="{{ index .image.dockerImageMetadata.Config.Entrypoint 0 }}"' "docker-entrypoint.sh" -#os::cmd::expect_success_and_text 'oc get istag/test:new -o jsonpath={.image.metadata.name}' 'sha256:b2f400f4a5e003b0543decf61a0a010939f3fba07bafa226f11ed7b5f1e81237' -# reference should point to the current repository, and that repository should match the reported dockerImageRepository for pushes -#repository="$( oc get is/test -o jsonpath='{.status.dockerImageRepository}' )" -#os::cmd::expect_success_and_text 'oc get istag/test:new -o jsonpath={.image.dockerImageReference}' "^$repository@sha256:b2f400f4a5e003b0543decf61a0a010939f3fba07bafa226f11ed7b5f1e81237" -#os::cmd::expect_success_and_text 'oc get istag/test:new -o jsonpath={.image.dockerImageReference}' "/$project/test@sha256:b2f400f4a5e003b0543decf61a0a010939f3fba07bafa226f11ed7b5f1e81237" - -#repository="$( oc get is/test -o jsonpath='{.status.dockerImageRepository}' )" -#os::cmd::expect_success "oc annotate --context='${cluster_admin_context}' --overwrite image/sha256:b2f400f4a5e003b0543decf61a0a010939f3fba07bafa226f11ed7b5f1e81237 images.openshift.io/deny-execution=true" -# TODO: re-enable before 4.0 release -#os::cmd::expect_failure_and_text "oc run vulnerable --image=${repository}:new --restart=Never" 'spec.containers\[0\].image: Forbidden: this image is prohibited by policy' - -# test image stream tag operations -os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.generation}' '2' -os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.from.kind}' 'ImageStreamTag' -os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.from.name}' '15.0' -os::cmd::expect_success 'oc annotate istag/wildfly:latest foo=bar' -os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.metadata.annotations.foo}' 'bar' -os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.annotations.foo}' 'bar' -os::cmd::expect_success 'oc annotate istag/wildfly:latest foo-' -os::cmd::expect_success_and_not_text 'oc get istag/wildfly:latest -o jsonpath={.metadata.annotations}' 'bar' -os::cmd::expect_success_and_not_text 'oc get istag/wildfly:latest -o jsonpath={.tag.annotations}' 'bar' -os::cmd::expect_success "oc patch istag/wildfly:latest -p='{\"tag\":{\"from\":{\"kind\":\"DockerImage\",\"name\":\"mysql:latest\"}}}'" -os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.from.kind}' 'DockerImage' -os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.from.name}' 'mysql:latest' -os::cmd::expect_success_and_not_text 'oc get istag/wildfly:latest -o jsonpath={.tag.generation}' '2' - -# create an image stream tag -os::cmd::expect_success 'oc create imagestreamtag tag:1 --from=wildfly:15.0' -os::cmd::expect_success 'oc create imagestreamtag tag:2 --from-image=mysql:latest' -os::cmd::try_until_success 'oc get imagestreamtags tag:2' -os::cmd::expect_success 'oc create imagestreamtag tag:3 -A foo=bar' -os::cmd::expect_success 'oc create imagestreamtag tag:4 --from=:2' -os::cmd::expect_success 'oc create imagestreamtag tag:5 --from=tag:2' -os::cmd::expect_success 'oc create imagestreamtag tag:6 --reference --from-image=mysql:latest' -os::cmd::expect_success 'oc create imagestreamtag tag:7 --reference-policy=Local --from=tag:2' -os::cmd::expect_success 'oc create istag tag:8 --insecure --from-image=mysql:latest' -os::cmd::try_until_success 'oc get imagestreamtags tag:8' -os::cmd::expect_success 'oc create imagestreamtag tag:9 --scheduled --reference-policy=Local --from-image=mysql:latest' -os::cmd::expect_success 'oc create imagestream tag-b' -os::cmd::expect_success 'oc create imagestreamtag tag-b:1 --from=wildfly:15.0' -os::cmd::expect_success 'oc create imagestreamtag tag-c:1 -A annotation.with.dots=are.ok' - -os::cmd::expect_failure_and_text 'oc create imagestreamtag tag-c --from-image=mysql:latest' 'must be of the form :' -os::cmd::expect_failure_and_text 'oc create imagestreamtag tag-c:1 -A foo' 'annotations must be of the form key=value, but is "foo"' -os::cmd::expect_failure_and_text 'oc create imagestreamtag tag-c:2 --from=mysql --from-image=mysql:latest' '\--from and --from-image may not be used together' - -os::cmd::expect_success_and_text 'oc get istag/tag:1 -o jsonpath={.image.dockerImageReference}' 'wildfly.*@sha256:' -tag1=$( oc get istag/wildfly:15.0 -o jsonpath={.image.metadata.name} ) -os::cmd::expect_success_and_text 'oc get istag/tag-b:1 -o jsonpath={.image.metadata.name}' "${tag1}" -os::cmd::expect_success_and_text 'oc get istag/tag:2 -o jsonpath={.image.dockerImageReference}' 'mysql@sha256:' -tag2=$( oc get istag/tag:2 -o jsonpath={.image.metadata.name} ) -os::cmd::expect_success_and_text "oc get is/tag -o 'jsonpath={.spec.tags[?(@.name==\"3\")].annotations.foo}'" 'bar' -os::cmd::expect_success_and_text 'oc get istag/tag:4 -o jsonpath={.image.metadata.name}' "${tag2}" -os::cmd::expect_success_and_text "oc get is/tag -o 'jsonpath={.spec.tags[?(@.name==\"4\")].from.name}'" '^2$' -os::cmd::expect_success_and_text 'oc get istag/tag:5 -o jsonpath={.image.metadata.name}' "${tag2}" -os::cmd::expect_success_and_text "oc get is/tag -o 'jsonpath={.spec.tags[?(@.name==\"6\")].reference}'" 'true' -os::cmd::expect_success_and_text "oc get is/tag -o 'jsonpath={.spec.tags[?(@.name==\"7\")].referencePolicy}'" 'Local' -os::cmd::expect_success_and_text "oc get is/tag -o 'jsonpath={.spec.tags[?(@.name==\"8\")].importPolicy.insecure}'" 'true' -os::cmd::expect_success_and_text "oc get is/tag -o 'jsonpath={.spec.tags[?(@.name==\"9\")].importPolicy.scheduled}'" 'true' +os::test::junit::declare_suite_start "cmd/deployments/config" +#os::cmd::expect_failure_and_text 'oc rollout latest test-deployment-config' 'already in progress' +#os::cmd::expect_failure_and_text 'oc rollout latest dc/test-deployment-config' 'already in progress' +## ensure that a cancelled deployment can be retried successfully +#os::cmd::expect_success 'oc rollout cancel dc/test-deployment-config' +#os::cmd::expect_success_and_text 'oc rollout retry dc/test-deployment-config' 'deploymentconfig.apps.openshift.io/test-deployment-config retried rollout' +#os::cmd::expect_success 'oc delete deploymentConfigs test-deployment-config' +echo "deploymentConfigs: ok" +os::test::junit::declare_suite_end -os::cmd::expect_success 'oc delete imageStreams ruby' -os::cmd::expect_success 'oc delete imageStreams nodejs' -os::cmd::expect_success 'oc delete imageStreams wildfly' -os::cmd::expect_success 'oc delete imageStreams postgresql' -os::cmd::expect_success 'oc delete imageStreams mongodb' -os::cmd::expect_failure 'oc get imageStreams ruby' -os::cmd::expect_failure 'oc get imageStreams nodejs' -os::cmd::expect_failure 'oc get imageStreams postgresql' -os::cmd::expect_failure 'oc get imageStreams mongodb' -os::cmd::expect_failure 'oc get imageStreams wildfly' -os::cmd::try_until_success 'oc get imagestreamTags mysql:5.5' -os::cmd::try_until_success 'oc get imagestreamTags mysql:5.6' -os::cmd::try_until_success 'oc get imagestreamTags mysql:5.7' -os::cmd::expect_success_and_text "oc get imagestreams mysql --template='{{ index .metadata.annotations \"openshift.io/image.dockerRepositoryCheck\"}}'" '[0-9]{4}\-[0-9]{2}\-[0-9]{2}' # expect a date like YYYY-MM-DD -os::cmd::expect_success 'oc describe istag/mysql:latest' -os::cmd::expect_success_and_text 'oc describe istag/mysql:latest' 'Environment:' -os::cmd::expect_success_and_text 'oc describe istag/mysql:latest' 'Image Created:' -os::cmd::expect_success_and_text 'oc describe istag/mysql:latest' 'Image Name:' -os::cmd::expect_success_and_text 'oc describe istag/mysql:latest' 'Layers:' -name=$(oc get istag/mysql:latest --template='{{ .image.metadata.name }}') -imagename="isimage/mysql@${name:0:15}" -os::cmd::expect_success "oc describe ${imagename}" -os::cmd::expect_success_and_text "oc describe ${imagename}" 'Environment:' -os::cmd::expect_success_and_text "oc describe ${imagename}" 'Image Created:' -os::cmd::expect_success_and_text "oc describe ${imagename}" 'Image Name:' +os::cmd::expect_success 'oc delete all --all' +# TODO: remove, flake caused by deployment controller updating the following dc +sleep 1 +os::cmd::expect_success 'oc delete all --all' -# test prefer-os and prefer-arch annotations -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-multiarch-stream.yaml' -os::cmd::try_until_success 'oc get istag test-multiarch-stream:linux-amd64' -os::cmd::try_until_success 'oc get istag test-multiarch-stream:linux-s390x' -os::cmd::expect_success_and_text 'oc get istag test-multiarch-stream:linux-amd64 --template={{.image.dockerImageMetadata.Architecture}}' 'amd64' -os::cmd::expect_success_and_text 'oc get istag test-multiarch-stream:linux-s390x --template={{.image.dockerImageMetadata.Architecture}}' 's390x' -os::cmd::expect_success 'oc delete is test-multiarch-stream' -echo "imageStreams: ok" -os::test::junit::declare_suite_end +os::cmd::expect_success 'oc process -f ${TEST_DATA}/application-template-dockerbuild.json -l app=dockerbuild | oc create -f -' +os::cmd::try_until_success 'oc get rc/database-1' -os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/import-image" -# should follow the latest reference to 5.6 and update that, and leave latest unchanged -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 1).from.kind}}'" 'DockerImage' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 2).from.kind}}'" 'DockerImage' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 3).from.kind}}'" 'ImageStreamTag' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 3).from.name}}'" '5.7' -# import existing tag (implicit latest) -os::cmd::expect_success_and_text 'oc import-image mysql' 'sha256:' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 1).from.kind}}'" 'DockerImage' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 2).from.kind}}'" 'DockerImage' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 3).from.kind}}'" 'ImageStreamTag' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 3).from.name}}'" '5.7' -# should prevent changing source -os::cmd::expect_failure_and_text 'oc import-image mysql --from=docker.io/mysql' "use the 'tag' command if you want to change the source" -os::cmd::expect_success 'oc describe is/mysql' -# import existing tag (explicit) -os::cmd::expect_success_and_text 'oc import-image mysql:5.6' "sha256:" -os::cmd::expect_success_and_text 'oc import-image mysql:latest' "sha256:" -# import existing image stream creating new tag -os::cmd::expect_success_and_text 'oc import-image mysql:external --from=docker.io/mysql' "sha256:" -os::cmd::expect_success_and_text "oc get istag/mysql:external --template='{{.tag.from.kind}}'" 'DockerImage' -os::cmd::expect_success_and_text "oc get istag/mysql:external --template='{{.tag.from.name}}'" 'docker.io/mysql' -# import creates new image stream with single tag -os::cmd::expect_failure_and_text 'oc import-image mysql-new-single:latest --from=docker.io/mysql:latest' '\-\-confirm' -os::cmd::expect_success_and_text 'oc import-image mysql-new-single:latest --from=docker.io/mysql:latest --confirm' 'sha256:' -os::cmd::expect_success_and_text "oc get is/mysql-new-single --template='{{(len .spec.tags)}}'" '1' -os::cmd::expect_success 'oc delete is/mysql-new-single' -# import creates new image stream with all tags -os::cmd::expect_failure_and_text 'oc import-image mysql-new-all --from=mysql --all' '\-\-confirm' -os::cmd::expect_success_and_text 'oc import-image mysql-new-all --from=mysql --all --confirm --request-timeout=1m' 'sha256:' -name=$(oc get istag/mysql-new-all:latest --template='{{ .image.metadata.name }}') -echo "import-image: ok" +os::test::junit::declare_suite_start "cmd/deployments/get" +os::cmd::expect_success_and_text "oc get dc --show-labels" "app=dockerbuild,template=application-template-dockerbuild" +os::cmd::expect_success_and_text "oc get dc frontend --show-labels" "app=dockerbuild,template=application-template-dockerbuild" +os::cmd::expect_success_and_not_text "oc get dc" "app=dockerbuild,template=application-template-dockerbuild" +os::cmd::expect_success_and_not_text "oc get dc frontend" "app=dockerbuild,template=application-template-dockerbuild" +os::cmd::expect_success "oc process -f ${TEST_DATA}/old-template.json | oc create -f -" +os::cmd::expect_success_and_text "oc get dc/eap-app -o yaml" ":latest" +echo "get: ok" os::test::junit::declare_suite_end -os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/tag" -# oc tag -os::cmd::expect_success 'oc tag mysql:latest mysql:tag1 --alias' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 5).from.kind}}'" 'ImageStreamTag' - -os::cmd::expect_success "oc tag mysql@${name} mysql:tag2 --alias" -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 6).from.kind}}'" 'ImageStreamImage' +os::test::junit::declare_suite_start "cmd/deployments/rollout" +os::cmd::try_until_success 'oc rollout pause dc/database' +os::cmd::try_until_text "oc get dc/database --template='{{.spec.paused}}'" "true" +os::cmd::try_until_success 'oc rollout resume dc/database' +os::cmd::try_until_text "oc get dc/database --template='{{.spec.paused}}'" "" +# create a replication controller and attempt to perform ` + "`" + `oc rollout cancel` + "`" + ` on it. +# expect an error about the resource type, rather than a panic or a success. +os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-replication-controller.yaml' +os::cmd::expect_failure_and_text 'oc rollout cancel rc/test-replication-controller' 'expected deployment configuration, got replicationcontrollers' -os::cmd::expect_success 'oc tag mysql:notfound mysql:tag3 --alias' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 7).from.kind}}'" 'ImageStreamTag' +echo "rollout: ok" +os::test::junit::declare_suite_end -os::cmd::expect_success 'oc tag --source=imagestreamtag mysql:latest mysql:tag4 --alias' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 8).from.kind}}'" 'ImageStreamTag' +os::test::junit::declare_suite_start "cmd/deployments/rollback" +# should fail because there's no previous deployment +os::cmd::expect_failure 'oc rollback database --to-version=1 -o=yaml' +os::cmd::expect_failure 'oc rollback dc/database --to-version=1 -o=yaml' +os::cmd::expect_failure 'oc rollback dc/database --to-version=1 --dry-run' +os::cmd::expect_failure 'oc rollback database-1 -o=yaml' +os::cmd::expect_failure 'oc rollback rc/database-1 -o=yaml' +os::cmd::expect_failure 'oc rollback database -o yaml' +# trigger a new deployment with 'foo' image +os::cmd::expect_success 'oc set image dc/database ruby-helloworld-database=foo --source=docker' +# wait for the new deployment +os::cmd::try_until_success 'oc rollout history dc/database --revision=2' +# rolling back to the same revision should fail +os::cmd::expect_failure 'oc rollback dc/database --to-version=2' +# undo --dry-run should report the original image +os::cmd::expect_success_and_text 'oc rollout undo dc/database --dry-run' 'image-registry.openshift-image-registry.svc:5000/openshift/mysql:5.7' +echo "rollback: ok" +os::test::junit::declare_suite_end -os::cmd::expect_success 'oc tag --source=istag mysql:latest mysql:tag5 --alias' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 9).from.kind}}'" 'ImageStreamTag' +os::test::junit::declare_suite_start "cmd/deployments/stop" +os::cmd::expect_success 'oc get dc/database' +os::cmd::expect_success 'oc expose dc/database --name=fromdc' +# should be a service +os::cmd::expect_success 'oc get svc/fromdc' +os::cmd::expect_success 'oc delete svc/fromdc' +os::cmd::expect_success 'oc delete dc/database' +os::cmd::expect_failure 'oc get dc/database' +os::cmd::try_until_failure 'oc get rc/database-1' +echo "stop: ok" +os::test::junit::declare_suite_end -os::cmd::expect_success "oc tag --source=imagestreamimage mysql@${name} mysql:tag6 --alias" -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 10).from.kind}}'" 'ImageStreamImage' +os::test::junit::declare_suite_start "cmd/deployments/autoscale" +os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-deployment-config.yaml' +os::cmd::expect_success 'oc autoscale dc/test-deployment-config --max 5' +os::cmd::expect_success_and_text "oc get hpa/test-deployment-config --template='{{.spec.maxReplicas}}'" "5" +os::cmd::expect_success_and_text "oc get hpa/test-deployment-config -o jsonpath='{.spec.scaleTargetRef.apiVersion}'" "apps.openshift.io/v1" +os::cmd::expect_success 'oc delete dc/test-deployment-config' +os::cmd::expect_success 'oc delete hpa/test-deployment-config' +echo "autoscale: ok" +os::test::junit::declare_suite_end -os::cmd::expect_success "oc tag --source=isimage mysql@${name} mysql:tag7 --alias" -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 11).from.kind}}'" 'ImageStreamImage' +os::test::junit::declare_suite_start "cmd/deployments/setimage" +os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-deployment-config.yaml' +os::cmd::expect_success 'oc set image dc/test-deployment-config ruby-helloworld=myshinynewimage --source=docker' +os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o jsonpath='{.spec.template.spec.containers[0].image}'" "myshinynewimage" +os::cmd::expect_success 'oc delete dc/test-deployment-config' +echo "set image: ok" +os::test::junit::declare_suite_end -os::cmd::expect_success 'oc tag --source=docker mysql:latest mysql:tag8 --alias' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 12).from.kind}}'" 'DockerImage' +os::test::junit::declare_suite_start "cmd/deployments/setdeploymenthook" +# Validate the set deployment-hook command +arg="-f ${TEST_DATA}/test-deployment-config.yaml" +os::cmd::expect_failure_and_text "oc set deployment-hook" "error: one or more deployment configs" +os::cmd::expect_failure_and_text "oc set deployment-hook ${arg}" "error: you must specify one of --pre, --mid, or --post" +os::cmd::expect_failure_and_text "oc set deployment-hook ${arg} -o yaml --pre -- mycmd" 'deploymentconfigs.apps.openshift.io "test-deployment-config" not found' +os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local -o yaml --post -- mycmd" 'mycmd' +os::cmd::expect_success_and_not_text "oc set deployment-hook ${arg} --local -o yaml --post -- mycmd | oc set deployment-hook -f - --local -o yaml --post --remove" 'mycmd' +os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre -o yaml -- echo 'hello world'" 'pre:' +os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre -o yaml -- echo 'hello world'" 'execNewPod:' +os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre -o yaml -- echo 'hello world'" '\- echo' +os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre -o yaml -- echo 'hello world'" '\- hello world' +os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --post -o yaml -- echo 'hello world'" 'post:' +os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --mid -o yaml -- echo 'hello world'" 'mid:' +os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre --failure-policy=ignore -o yaml -- echo 'hello world'" 'failurePolicy: Ignore' +os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre --failure-policy=retry -o yaml -- echo 'hello world'" 'failurePolicy: Retry' +os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre --failure-policy=abort -o yaml -- echo 'hello world'" 'failurePolicy: Abort' +# Non-existent container +os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre --container=blah -o yaml -- echo 'hello world'" 'does not have a container named' +# Non-existent volume +os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre --volumes=blah -o yaml -- echo 'hello world'" 'does not have a volume named' +# Existing container +os::cmd::expect_success_and_not_text "oc set deployment-hook ${arg} --local --pre --container=ruby-helloworld -o yaml -- echo 'hello world'" 'does not have a container named' +os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre --container=ruby-helloworld -o yaml -- echo 'hello world'" 'containerName: ruby-helloworld' +# Existing volume +os::cmd::expect_success_and_not_text "oc set deployment-hook ${arg} --local --pre --volumes=vol1 -o yaml -- echo 'hello world'" 'does not have a volume named' +os::cmd::expect_success_and_text "oc set deployment-hook ${arg} --local --pre --volumes=vol1 -o yaml -- echo 'hello world'" '\- vol1' +# Server object tests +os::cmd::expect_success "oc create -f ${TEST_DATA}/test-deployment-config.yaml" +os::cmd::expect_failure_and_text "oc set deployment-hook dc/test-deployment-config --pre" "you must specify a command" +os::cmd::expect_success_and_text "oc set deployment-hook test-deployment-config --pre -- echo 'hello world'" "updated" +os::cmd::expect_success_and_text "oc set deployment-hook dc/test-deployment-config --loglevel=1 --pre -- echo 'hello world'" "was not changed" +os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "pre:" +os::cmd::expect_success_and_text "oc set deployment-hook dc/test-deployment-config --pre --failure-policy=abort -- echo 'test'" "updated" +os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o yaml" "failurePolicy: Abort" +os::cmd::expect_success_and_text "oc set deployment-hook --all --pre -- echo 'all dc'" "updated" +os::cmd::expect_success_and_text "oc get dc -o yaml" "all dc" +os::cmd::expect_success_and_text "oc set deployment-hook dc/test-deployment-config --pre --remove" "updated" +os::cmd::expect_success_and_not_text "oc get dc/test-deployment-config -o yaml" "pre:" +# Environment handling +os::cmd::expect_success_and_text "oc set deployment-hook dc/test-deployment-config --pre -o yaml --environment X=Y,Z=W -- echo 'test'" "value: Y,Z=W" +os::cmd::expect_success_and_text "oc set deployment-hook dc/test-deployment-config --pre -o yaml --environment X=Y,Z=W -- echo 'test'" "no longer accepts comma-separated list" +os::cmd::expect_success_and_not_text "oc set deployment-hook dc/test-deployment-config --pre -o yaml --environment X=Y -- echo 'test'" "no longer accepts comma-separated list" -os::cmd::expect_success 'oc tag mysql:latest mysql:zzz mysql:yyy --alias' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 13).from.kind}}'" 'ImageStreamTag' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 14).from.kind}}'" 'ImageStreamTag' +os::cmd::expect_success "oc delete dc/test-deployment-config" +echo "set deployment-hook: ok" +os::test::junit::declare_suite_end -os::cmd::expect_failure_and_text 'oc tag mysql:latest tagtest:tag1 --alias' 'cannot set alias across' +os::test::junit::declare_suite_end +`) -# label image -imgsha256=$(oc get istag/mysql:latest --template='{{ .image.metadata.name }}') -os::cmd::expect_success "oc label image ${imgsha256} foo=bar || true" -os::cmd::expect_success_and_text "oc get image ${imgsha256} --show-labels" 'foo=bar' +func testExtendedTestdataCmdTestCmdDeploymentsShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdDeploymentsSh, nil +} -# tag labeled image -os::cmd::expect_success 'oc label is/mysql labelA=value' -os::cmd::expect_success 'oc tag mysql:latest mysql:labeled' -os::cmd::expect_success_and_text "oc get istag/mysql:labeled -o jsonpath='{.metadata.labels.labelA}'" 'value' -# test copying tags -os::cmd::expect_success 'oc tag registry-1.docker.io/openshift/origin:v1.0.4 newrepo:latest' -os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .spec.tags 0).from.kind}}'" 'DockerImage' -os::cmd::try_until_success 'oc get istag/mysql:5.5' -# default behavior is to copy the current image, but since this is an external image we preserve the dockerImageReference -os::cmd::expect_success 'oc tag mysql:5.5 newrepo:latest' -os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .spec.tags 0).from.kind}}'" 'ImageStreamImage' -os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .status.tags 0 \"items\" 0).dockerImageReference}}'" '^docker.io/openshift/mysql-55-centos7@sha256:' -# when copying a tag that points to the internal registry, update the container image reference -#os::cmd::expect_success "oc tag test:new newrepo:direct" -#os::cmd::expect_success_and_text 'oc get istag/newrepo:direct -o jsonpath={.image.dockerImageReference}' "/$project/newrepo@sha256:" -# test references -os::cmd::expect_success 'oc tag mysql:5.5 reference:latest --reference' -os::cmd::expect_success_and_text "oc get is/reference --template='{{(index .spec.tags 0).from.kind}}'" 'ImageStreamImage' -os::cmd::expect_success_and_text "oc get is/reference --template='{{(index .spec.tags 0).reference}}'" 'true' -# create a second project to test tagging across projects -os::cmd::expect_success 'oc new-project test-cmd-images-2' -os::cmd::expect_success "oc tag $project/mysql:5.5 newrepo:latest" -os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .spec.tags 0).from.kind}}'" 'ImageStreamImage' -os::cmd::expect_success_and_text 'oc get istag/newrepo:latest -o jsonpath={.image.dockerImageReference}' 'docker.io/openshift/mysql-55-centos7@sha256:' -# tag across projects without specifying the source's project -os::cmd::expect_success_and_text "oc tag newrepo:latest '${project}/mysql:tag1'" "mysql:tag1 set to" -os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .spec.tags 0).name}}'" "latest" -# tagging an image with a DockerImageReference that points to the internal registry across namespaces updates the reference -#os::cmd::expect_success "oc tag $project/test:new newrepo:direct" -# reference should point to the current repository, and that repository should match the reported dockerImageRepository for pushes -# can't check status since there is no registry running so internalRegistryHostname isn't populated. -#repository="$( oc get is/newrepo -o jsonpath='{.status.dockerImageRepository}' )" -#os::cmd::expect_success_and_text 'oc get istag/newrepo:direct -o jsonpath={.image.dockerImageReference}' "^$repository@sha256:" -#os::cmd::expect_success_and_text 'oc get istag/newrepo:direct -o jsonpath={.image.dockerImageReference}' '/test-cmd-images-2/newrepo@sha256:' -# tagging an image using --reference does not -#os::cmd::expect_success "oc tag $project/test:new newrepo:indirect --reference" -#os::cmd::expect_success_and_text 'oc get istag/newrepo:indirect -o jsonpath={.image.dockerImageReference}' "/$project/test@sha256:" -os::cmd::expect_success "oc project $project" -# test scheduled and insecure tagging -os::cmd::expect_success 'oc tag --source=docker mysql:5.7 newrepo:latest --scheduled' -os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .spec.tags 0).importPolicy.scheduled}}'" 'true' -os::cmd::expect_success_and_text "oc describe is/newrepo" 'updates automatically from registry mysql:5.7' -os::cmd::expect_success 'oc tag --source=docker mysql:5.7 newrepo:latest --insecure' -os::cmd::expect_success_and_text "oc describe is/newrepo" 'will use insecure HTTPS or HTTP connections' -os::cmd::expect_success_and_not_text "oc describe is/newrepo" 'updates automatically from' -os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .spec.tags 0).importPolicy.insecure}}'" 'true' +func testExtendedTestdataCmdTestCmdDeploymentsSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdDeploymentsShBytes() + if err != nil { + return nil, err + } -# test creating streams that don't exist -os::cmd::expect_failure_and_text 'oc get imageStreams tagtest1' 'not found' -os::cmd::expect_failure_and_text 'oc get imageStreams tagtest2' 'not found' -os::cmd::expect_success 'oc tag mysql:latest tagtest1:latest tagtest2:latest' -os::cmd::expect_success_and_text "oc get is/tagtest1 --template='{{(index .spec.tags 0).from.kind}}'" 'ImageStreamImage' -os::cmd::expect_success_and_text "oc get is/tagtest2 --template='{{(index .spec.tags 0).from.kind}}'" 'ImageStreamImage' -os::cmd::expect_success 'oc delete is/tagtest1 is/tagtest2' -os::cmd::expect_success_and_text 'oc tag mysql:latest tagtest:new1' 'Tag tagtest:new1 set to mysql@sha256:' + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/deployments.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} -# test deleting a spec tag using oc tag -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-stream.yaml' -os::cmd::expect_success_and_text 'oc tag test-stream:latest -d' 'Deleted' -os::cmd::expect_success 'oc delete is/test-stream' -echo "tag: ok" -os::test::junit::declare_suite_end +var _testExtendedTestdataCmdTestCmdDescriberSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" +trap os::test::junit::reconcile_output EXIT -os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/delete-istag" -# test deleting a tag using oc delete -os::cmd::expect_success_and_text "oc get is perl --template '{{(index .spec.tags 0).name}}'" '5.16' -os::cmd::expect_success_and_text "oc get is perl --template '{{(index .status.tags 0).tag}}'" '5.16' -os::cmd::expect_success_and_text "oc describe is perl | sed -n -e '0,/^Tags:/d' -e '/^\s\+/d' -e '/./p' | head -n 1" 'latest' -os::cmd::expect_success "oc delete istag/perl:5.16 --context='${cluster_admin_context}'" -os::cmd::expect_success_and_not_text 'oc get is/perl --template={{.spec.tags}}' 'version:5.16' -os::cmd::expect_success_and_not_text 'oc get is/perl --template={{.status.tags}}' 'version:5.16' -os::cmd::expect_success 'oc delete all --all' +# Cleanup cluster resources created by this test +( + set +e + oc delete all,templates --all + exit 0 +) &>/dev/null -echo "delete istag: ok" -os::test::junit::declare_suite_end -os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/merge-tags-on-apply" -os::cmd::expect_success 'oc new-project merge-tags' -os::cmd::expect_success 'oc create -f ${TEST_DATA}/image-streams/image-streams-centos7.json' -os::cmd::expect_success_and_text 'oc get is ruby -o jsonpath={.spec.tags[*].name}' '2.7-ubi8 latest' -os::cmd::expect_success 'oc apply -f ${TEST_DATA}/modified-ruby-imagestream.json' -os::cmd::expect_success_and_text 'oc get is ruby -o jsonpath={.spec.tags[*].name}' '2.7-ubi8 latest newtag' -os::cmd::expect_success_and_text 'oc get is ruby -o jsonpath={.spec.tags[0].annotations.version}' '2.7 patched' -os::cmd::expect_success 'oc delete project merge-tags' -echo "apply new imagestream tags: ok" -os::test::junit::declare_suite_end +os::test::junit::declare_suite_start "cmd/describe" +# This test validates non-duplicate errors when describing an existing resource without a defined describer +os::cmd::expect_success 'oc create -f - << __EOF__ +{ + "apiVersion": "v1", + "involvedObject": { + "apiVersion": "v1", + "kind": "Pod", + "name": "test-pod", + "namespace": "cmd-describer" + }, + "kind": "Event", + "message": "test message", + "metadata": { + "name": "test-event" + } +} +__EOF__ +' +os::cmd::try_until_success 'eventnum=$(oc get events | wc -l) && [[ $eventnum -gt 0 ]]' +# resources without describers get a default +os::cmd::expect_success_and_text 'oc describe events' 'Namespace:\s+cmd-describer' -# test importing images with wrong docker secrets -os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/import-public-images-with-fake-secret" -os::cmd::expect_success 'oc new-project import-images' -os::cmd::expect_success 'oc create secret docker-registry dummy-secret1 --docker-server=docker.io --docker-username=dummy1 --docker-password=dummy1 --docker-email==dummy1@example.com' -os::cmd::expect_success 'oc create secret docker-registry dummy-secret2 --docker-server=docker.io --docker-username=dummy2 --docker-password=dummy2 --docker-email==dummy2@example.com' -os::cmd::expect_success_and_text 'oc import-image example --from=openshift/hello-openshift --confirm' 'imagestream.image.openshift.io/example imported' -os::cmd::expect_success 'oc delete project import-images' -echo "import public images with fake secret ok" -os::test::junit::declare_suite_end +# TemplateInstance +os::cmd::expect_success 'oc create -f ${TEST_DATA}/templateinstance_objectkinds.yaml' +os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'Name:\s+templateinstance' +os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'Namespace:\s+cmd-describer' +os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'Type:\s+Ready' +os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'Status:\s+True' +os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'Secret:\s+cmd-describer/secret' +os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'Deployment:\s+cmd-describer/deployment' +os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'Route:\s+cmd-describer/route' +os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'Route:\s+cmd-describer/newroute' +os::cmd::expect_success_and_text 'oc describe templateinstances templateinstance' 'NAME:\s+8 bytes' +echo "describer: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdImagesShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdImagesSh, nil +func testExtendedTestdataCmdTestCmdDescriberShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdDescriberSh, nil } -func testExtendedTestdataCmdTestCmdImagesSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdImagesShBytes() +func testExtendedTestdataCmdTestCmdDescriberSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdDescriberShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/images.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/describer.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdLoginSh = []byte(`#!/bin/bash - -set -o errexit -set -o nounset -set -o pipefail - -OS_ROOT=$(dirname "${BASH_SOURCE}")/../.. -source "${OS_ROOT}/hack/lib/init.sh" -os::log::stacktrace::install +var _testExtendedTestdataCmdTestCmdEditSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT # Cleanup cluster resources created by this test ( set +e - oc delete project project-foo + oc delete all,templates --all exit 0 ) &>/dev/null -os::test::junit::declare_suite_start "cmd/login" -# This test validates login functionality for the client -# we want this test to run without $KUBECONFIG or $KUBERNETES_MASTER as it tests that functionality -# ` + "`" + `oc` + "`" + ` will use in-cluster config if KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT -# are set, as well as /var/run/secrets/kubernetes.io/serviceaccount/token exists. we -# therefore can be sure that we are picking up no client configuration if we unset these variables -login_kubeconfig="${ARTIFACT_DIR}/login.kubeconfig" -CA_CERT=${MASTER_CONFIG_DIR}/server-ca.crt -cp "${KUBECONFIG}" "${login_kubeconfig}" -unset KUBECONFIG -unset KUBERNETES_MASTER -# test client not configured -os::cmd::expect_failure_and_text "env -u KUBERNETES_SERVICE_HOST oc get services" 'Missing or incomplete configuration info. Please login' -unused_port="33333" -# setting env bypasses the not configured message -os::cmd::expect_failure_and_text "env -u KUBERNETES_SERVICE_HOST KUBERNETES_MASTER=http://${API_HOST}:${unused_port} oc get services" 'did you specify the right host or port' -# setting --server bypasses the not configured message -os::cmd::expect_failure_and_text "env -u KUBERNETES_SERVICE_HOST oc get services --server=http://${API_HOST}:${unused_port}" 'did you specify the right host or port' - -# Set KUBERNETES_MASTER for oc from now on -export KUBERNETES_MASTER="${API_SCHEME}://${API_HOST}:${API_PORT}" - -# Set certificates for oc from now on -if [[ "${API_SCHEME}" == "https" ]]; then - # test bad certificate - os::cmd::expect_failure_and_text "env -u KUBERNETES_SERVICE_HOST oc get services" 'certificate signed by unknown authority' -fi -# remove self-provisioner role from user and test login prompt before creating any projects -os::cmd::expect_success "oc adm policy remove-cluster-role-from-group self-provisioner system:authenticated:oauth --kubeconfig='${login_kubeconfig}'" -os::cmd::expect_success_and_text "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${CA_CERT}' -u no-project-test-user -p anything" "You don't have any projects. Contact your system administrator to request a project" -# make sure standard login prompt is printed once self-provisioner status is restored -os::cmd::expect_success "oc adm policy add-cluster-role-to-group self-provisioner system:authenticated:oauth --kubeconfig='${login_kubeconfig}'" -os::cmd::try_until_text "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${CA_CERT}' -u no-project-test-user -p anything" "You don't have any projects. You can try to create a new project, by running" $(( 30 * second )) 0.25 -# make sure ` + "`" + `oc login` + "`" + ` fails with unauthorized error -os::cmd::expect_failure_and_text 'oc login <<< \n' 'Login failed \(401 Unauthorized\)' -os::cmd::expect_success 'oc logout' -echo "login and status messages: ok" +os::test::junit::declare_suite_start "cmd/edit" +# This test validates the edit command -# login and logout tests -# bad token should error -os::cmd::expect_failure_and_text "oc login ${KUBERNETES_MASTER} --certificate-authority='${CA_CERT}' --token=badvalue" 'The token provided is invalid or expired' -# --token and --username are mutually exclusive -os::cmd::expect_failure_and_text "oc login ${KUBERNETES_MASTER} -u test-user --token=tmp --insecure-skip-tls-verify" 'mutually exclusive' -# must only accept one arg (server) -os::cmd::expect_failure_and_text "oc login https://server1 https://server2.com" 'Only the server URL may be specified' -# logs in with a valid certificate authority -os::cmd::expect_success "oc login ${KUBERNETES_MASTER} --certificate-authority='${CA_CERT}' -u test-user -p anything" -os::cmd::expect_success_and_text "cat ${HOME}/.kube/config" "v1" -os::cmd::expect_success 'oc logout' -# logs in skipping certificate check -os::cmd::expect_success "oc login ${KUBERNETES_MASTER} --insecure-skip-tls-verify -u test-user -p anything" -# logs in by an existing and valid token -temp_token="$(oc whoami -t)" -os::cmd::expect_success_and_text "oc login --token=${temp_token}" 'using the token provided' -os::cmd::expect_success 'oc logout' -# properly parse server port -os::cmd::expect_failure_and_text 'oc login https://server1:844333' 'Not a valid port' -# properly handle trailing slash -os::cmd::expect_success "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${CA_CERT}' -u test-user -p anything" -# create a new project -os::cmd::expect_success "oc new-project project-foo --display-name='my project' --description='boring project description'" -os::cmd::expect_success_and_text "oc project" 'Using project "project-foo"' -# new user should get default context -os::cmd::expect_success "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${CA_CERT}' -u new-and-unknown-user -p anything" -os::cmd::expect_success_and_text 'oc config view' "current-context.+/${API_HOST}:${API_PORT}/new-and-unknown-user" -# denies access after logging out -os::cmd::expect_success 'oc logout' -os::cmd::expect_failure_and_text 'oc get pods' '"system:anonymous" cannot list resource "pods" in API group ""' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/hello-openshift/hello-pod.json' -# make sure we report an error if the config file we pass is not writable -# Does not work inside of a container, determine why and reenable -# os::cmd::expect_failure_and_text "oc login '${KUBERNETES_MASTER}' -u test -p test '--kubeconfig=${templocation}/file' --insecure-skip-tls-verify" 'KUBECONFIG is set to a file that cannot be created or modified' -echo "login warnings: ok" +os::cmd::expect_success_and_text 'KUBE_EDITOR=cat oc edit pod/hello-openshift' 'Edit cancelled' +os::cmd::expect_success_and_text 'KUBE_EDITOR=cat oc edit pod/hello-openshift' 'name: hello-openshift' +#os::cmd::expect_success_and_text 'KUBE_EDITOR=cat oc edit --windows-line-endings pod/hello-openshift | file -' 'CRLF' +#os::cmd::expect_success_and_not_text 'KUBE_EDITOR=cat oc edit --windows-line-endings=false pod/hello-openshift | file -' 'CRFL' -# login and create serviceaccount and test login and logout with a service account token -os::cmd::expect_success "oc login ${KUBERNETES_MASTER} --certificate-authority='${CA_CERT}' -u test-user -p anything" -os::cmd::expect_success_and_text "oc create sa testserviceaccount" "serviceaccount/testserviceaccount created" -os::cmd::try_until_success "oc sa get-token testserviceaccount" -os::cmd::expect_success_and_text "oc login --token=$(oc sa get-token testserviceaccount)" "system:serviceaccount:project-foo:testserviceaccount" -# attempt to logout successfully -os::cmd::expect_success_and_text "oc logout" "Logged \"system:serviceaccount:project-foo:testserviceaccount\" out" -# verify that the token is no longer present in our local config -os::cmd::expect_failure_and_text "oc whoami" 'User "system:anonymous" cannot get resource "users" in API group "user.openshift.io"' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/services.yaml' +os::cmd::expect_success_and_text 'KUBE_EDITOR=cat oc edit svc' 'kind: List' -# log in and set project to use from now on -os::cmd::expect_success "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${CA_CERT}' -u test-user -p anything" -os::cmd::expect_success 'oc get projects' -os::cmd::expect_success 'oc project project-foo' -os::cmd::expect_success_and_text 'oc config view' "current-context.+project-foo/${API_HOST}:${API_PORT}/test-user" -os::cmd::expect_success_and_text 'oc whoami' 'test-user' -os::cmd::expect_success_and_text "oc whoami --config='${login_kubeconfig}'" 'system:admin' -os::cmd::expect_success_and_text "oc whoami --kubeconfig='${login_kubeconfig}'" 'system:admin' -os::cmd::expect_success_and_text 'oc whoami -t' '.' -os::cmd::expect_success_and_text 'oc whoami -c' '.' +os::cmd::expect_success 'oc create imagestream test' +os::cmd::expect_success 'oc tag --source=docker quay.io/openshifttest/hello-openshift:openshift test:new' +os::cmd::try_until_success 'oc get istag/test:new' +os::cmd::expect_success_and_not_text 'oc get istag/test:new -o jsonpath={.metadata.annotations}' "tags.?:.?hidden" +editorfile="$(mktemp -d)/tmp-editor.sh" +echo '#!/bin/bash' > ${editorfile} +echo 'sed -i "s/^tag: null/tag:\n referencePolicy:\n type: Source/g" $1' >> ${editorfile} +echo 'sed -i "s/^metadata:$/metadata:\n annotations:\n tags: hidden/g" $1' >> ${editorfile} +chmod +x ${editorfile} +os::cmd::expect_success "EDITOR=${editorfile} oc edit istag/test:new" +os::cmd::expect_success_and_text 'oc get istag/test:new -o jsonpath={.metadata.annotations}' "tags.?:.?hidden" -# test config files from the --kubeconfig flag -os::cmd::expect_success "oc get services --kubeconfig='${login_kubeconfig}'" -# test config files from env vars -os::cmd::expect_success "KUBECONFIG='${login_kubeconfig}' oc get services" +echo "edit: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdLoginShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdLoginSh, nil +func testExtendedTestdataCmdTestCmdEditShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdEditSh, nil } -func testExtendedTestdataCmdTestCmdLoginSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdLoginShBytes() +func testExtendedTestdataCmdTestCmdEditSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdEditShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/login.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/edit.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdMigrateSh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdEnvSh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT -# Cleanup cluster resources created by this test -( - set +e - oc delete all --all - exit 0 -) &>/dev/null +os::test::junit::declare_suite_start "cmd/set-env" +# This test validates the value of --image for oc run +os::cmd::expect_success 'oc create deploymentconfig testdc --image=busybox' +os::cmd::expect_failure_and_text 'oc set env dc/testdc' 'error: at least one environment variable must be provided' +os::cmd::expect_success_and_text 'oc set env dc/testdc key=value' 'deploymentconfig.apps.openshift.io/testdc updated' +os::cmd::expect_success_and_text 'oc set env dc/testdc --list' 'deploymentconfigs/testdc, container default-container' +os::cmd::expect_success_and_text 'oc set env dc --all --containers="default-container" key-' 'deploymentconfig.apps.openshift.io/testdc updated' +os::cmd::expect_failure_and_text 'oc set env dc --all --containers="default-container"' 'error: at least one environment variable must be provided' +os::cmd::expect_failure_and_not_text 'oc set env --from=secret/mysecret dc/testdc' 'error: at least one environment variable must be provided' +os::cmd::expect_failure_and_text 'oc set env dc/testdc test#abc=1234' 'environment variable test#abc=1234 is invalid, a valid environment variable name must consist of alphabetic characters' -os::test::junit::declare_suite_start "cmd/migrate" -# This test validates storage migration +# ensure deleting a var through --env does not result in an error message +os::cmd::expect_success_and_text 'oc set env dc/testdc key=value' 'deploymentconfig.apps.openshift.io/testdc updated' +os::cmd::expect_success_and_text 'oc set env dc/testdc dots.in.a.key=dots.in.a.value' 'deploymentconfig.apps.openshift.io/testdc updated' +os::cmd::expect_success_and_text 'oc set env dc --all --containers="default-container" --env=key-' 'deploymentconfig.apps.openshift.io/testdc updated' +# ensure deleting a var through --env actually deletes the env var +os::cmd::expect_success_and_not_text "oc get dc/testdc -o jsonpath='{ .spec.template.spec.containers[?(@.name==\"default-container\")].env }'" 'name.?\:.?key' +os::cmd::expect_success_and_text "oc get dc/testdc -o jsonpath='{ .spec.template.spec.containers[?(@.name==\"default-container\")].env }'" 'name.?\:.?dots.in.a.key' +os::cmd::expect_success_and_text 'oc set env dc --all --containers="default-container" --env=dots.in.a.key-' 'deploymentconfig.apps.openshift.io/testdc updated' +os::cmd::expect_success_and_not_text "oc get dc/testdc -o jsonpath='{ .spec.template.spec.containers[?(@.name==\"default-container\")].env }'" 'name.?\:.?dots.in.a.key' -os::cmd::expect_success 'oc login -u system:admin' -# ensure all namespaces have been deleted before attempting to perform global action -os::cmd::try_until_not_text 'oc get ns --template "{{ range .items }}{{ if not (eq .status.phase \"Active\") }}1{{ end }}{{ end }}"' '1' +# check that env vars are not split at commas +os::cmd::expect_success_and_text 'oc set env -o yaml dc/testdc PASS=x,y=z' 'value: x,y=z' +os::cmd::expect_success_and_text 'oc set env -o yaml dc/testdc --env PASS=x,y=z' 'value: x,y=z' +# warning is printed when --env has comma in it +os::cmd::expect_success_and_text 'oc set env dc/testdc --env PASS=x,y=z' 'no longer accepts comma-separated list' +# warning is not printed for variables passed as positional arguments +os::cmd::expect_success_and_not_text 'oc set env dc/testdc PASS=x,y=z' 'no longer accepts comma-separated list' -project="$( oc project -q )" +# create a build-config object with the JenkinsPipeline strategy +os::cmd::expect_success 'oc process -p NAMESPACE=openshift -f ${TEST_DATA}/jenkins/jenkins-ephemeral-template.json | oc create -f -' +os::cmd::expect_success "echo 'apiVersion: v1 +kind: BuildConfig +metadata: + name: fake-pipeline +spec: + source: + git: + uri: https://github.com/openshift/ruby-hello-world.git + strategy: + jenkinsPipelineStrategy: {} +' | oc create -f -" -os::test::junit::declare_suite_start "cmd/migrate/storage" -os::cmd::expect_success_and_text 'oc adm migrate storage' 'summary' -os::cmd::expect_success_and_text 'oc adm migrate storage --loglevel=2' ": -n ${project} serviceaccounts/deployer" -os::cmd::expect_success_and_not_text 'oc adm migrate storage --loglevel=2 --include=pods' ": -n ${project} serviceaccounts/deployer" -os::cmd::expect_success_and_text 'oc adm migrate storage --loglevel=2 --include=sa --from-key=default/ --to-key=default/\xFF' ": -n default serviceaccounts/deployer" -os::cmd::expect_success_and_not_text 'oc adm migrate storage --loglevel=2 --include=sa --from-key=default/ --to-key=default/deployer' ": -n default serviceaccounts/deployer" -os::cmd::expect_success_and_text 'oc adm migrate storage --loglevel=2' 'unchanged:' -os::cmd::expect_success_and_text 'oc adm migrate storage --bandwidth=20' 'summary:' -os::cmd::expect_success_and_text 'oc adm migrate storage --confirm' 'storage migration does not support dry run, this flag is ignored' -os::cmd::expect_success_and_text 'oc adm migrate storage -o=yaml' 'storage migration does not support dry run, this flag is ignored' +# ensure build-config has been created and that its type is "JenkinsPipeline" +os::cmd::expect_success_and_text "oc get bc fake-pipeline -o jsonpath='{ .spec.strategy.type }'" 'JenkinsPipeline' +# attempt to set an environment variable +os::cmd::expect_success_and_text 'oc set env bc/fake-pipeline FOO=BAR' 'buildconfig.build.openshift.io/fake\-pipeline updated' +# ensure environment variable was set +os::cmd::expect_success_and_text "oc get bc fake-pipeline -o jsonpath='{ .spec.strategy.jenkinsPipelineStrategy.env }'" 'name.?\:.?FOO' +os::cmd::expect_success 'oc delete bc fake-pipeline' + +echo "oc set env: ok" os::test::junit::declare_suite_end +`) -os::test::junit::declare_suite_start "cmd/migrate/storage_oauthclientauthorizations" -# Create valid OAuth client -os::cmd::expect_success_and_text 'oc create -f test/testdata/oauth/client.yaml' 'oauthclient.oauth.openshift.io/test-oauth-client created' -# Create OAuth client authorization for client -os::cmd::expect_success_and_text 'oc create -f test/testdata/oauth/clientauthorization.yaml' 'oauthclientauthorization.oauth.openshift.io/user1:test-oauth-client created' -# Delete client -os::cmd::expect_success_and_text 'oc delete oauthclient test-oauth-client' 'oauthclient.oauth.openshift.io "test-oauth-client" deleted' -# Assert that migration/update still works even though the client authorization is no longer valid -os::cmd::expect_success_and_text 'oc adm migrate storage --loglevel=6 --include=oauthclientauthorizations' 'PUT.*oauthclientauthorizations/user1:test-oauth-client' +func testExtendedTestdataCmdTestCmdEnvShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdEnvSh, nil +} + +func testExtendedTestdataCmdTestCmdEnvSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdEnvShBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/env.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _testExtendedTestdataCmdTestCmdFrameworkTestSh = []byte(`#!/usr/bin/env bash +# +# This script tests os::test::junit functionality. + +function exit_trap() { + local return_code=$? + + end_time=$(date +%s) + + if [[ "${return_code}" -eq "0" ]]; then + verb="succeeded" + else + verb="failed" + fi + + echo "$0 ${verb} after $((${end_time} - ${start_time})) seconds" + exit "${return_code}" +} + +trap exit_trap EXIT + +start_time=$(date +%s) +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" + +# envars used to track these interactions are not propagated out of the subshells used to run these commands +# therefore each os::cmd call is its own sandbox and complicated scenarios need to play out inside one call +# however, envars from this scope *are* propagated into each subshell, so they need to be cleared in each call + +os::test::junit::declare_suite_start 'lib/test/junit' + +# shouldn't be able to end a suite straight away +os::cmd::expect_failure_and_text 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT +os::test::junit::declare_suite_end' '\[ERROR\] jUnit suite marker could not be placed, expected suites in flight, got 0' +# should be able to start one straight away +os::cmd::expect_success 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT +os::test::junit::declare_suite_start whatever' +# should be able to start and end a suite +os::cmd::expect_success 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT +os::test::junit::declare_suite_start whatever +os::test::junit::declare_suite_end' +# should not be able to end more suites than are in flight +os::cmd::expect_failure_and_text 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT +os::test::junit::declare_suite_start whatever os::test::junit::declare_suite_end - -os::test::junit::declare_suite_start "cmd/migrate/imagereferences" -# create alternating items in history -os::cmd::expect_success 'oc import-image --from=mysql:latest test:1 --confirm' -os::cmd::expect_success 'oc import-image --from=php:latest test:2 --confirm' -os::cmd::expect_success 'oc tag --source=docker php:latest test:1' -os::cmd::expect_success 'oc tag --source=docker mysql:latest test:1' -os::cmd::expect_success 'oc tag --source=docker mysql:latest test:2' -os::cmd::expect_success 'oc tag --source=docker php:latest test:2' -os::cmd::expect_success 'oc tag --source=docker myregistry.com/php:latest test:3' -# verify error cases -os::cmd::expect_failure_and_text 'oc adm migrate image-references' 'at least one mapping argument must be specified: REGISTRY/NAME=REGISTRY/NAME' -os::cmd::expect_failure_and_text 'oc adm migrate image-references my.docker.io=docker.io/* --loglevel=1' 'all arguments' -os::cmd::expect_failure_and_text 'oc adm migrate image-references my.docker.io/=docker.io/* --loglevel=1' 'not a valid source' -os::cmd::expect_failure_and_text 'oc adm migrate image-references /*=docker.io/* --loglevel=1' 'not a valid source' -os::cmd::expect_failure_and_text 'oc adm migrate image-references my.docker.io/*=docker.io --loglevel=1' 'all arguments' -os::cmd::expect_failure_and_text 'oc adm migrate image-references my.docker.io/*=docker.io/ --loglevel=1' 'not a valid target' -os::cmd::expect_failure_and_text 'oc adm migrate image-references my.docker.io/*=/x --loglevel=1' 'not a valid target' -os::cmd::expect_failure_and_text 'oc adm migrate image-references my.docker.io/*=*/* --loglevel=1' 'at least one change' -os::cmd::expect_failure_and_text 'oc adm migrate image-references a/b=a/b --loglevel=1' 'at least one field' -os::cmd::expect_failure_and_text 'oc adm migrate image-references */*=*/* --loglevel=1' 'at least one change' -# verify dry run -os::cmd::expect_success_and_text 'oc adm migrate image-references my.docker.io/*=docker.io/* --loglevel=1' 'migrated=0' -os::cmd::expect_success_and_text 'oc adm migrate image-references --include=imagestreams docker.io/*=my.docker.io/* --loglevel=1' "migrated \(dry run\): -n ${project} imagestreams.image.openshift.io/test" -os::cmd::expect_success_and_text 'oc adm migrate image-references --include=imagestreams docker.io/mysql=my.docker.io/* --all-namespaces=false --loglevel=1' 'migrated=1' -os::cmd::expect_success_and_text 'oc adm migrate image-references --include=imagestreams docker.io/mysql=my.docker.io/* --all-namespaces=false --loglevel=1 -o yaml' 'dockerImageReference: my.docker.io/mysql@sha256:' -os::cmd::expect_success_and_text 'oc adm migrate image-references --include=imagestreams docker.io/other=my.docker.io/* --all-namespaces=false --loglevel=1' 'migrated=0' -# only mysql references are changed -os::cmd::expect_success_and_text 'oc adm migrate image-references --include=imagestreams docker.io/mysql=my.docker.io/mysql2 --all-namespaces=false --loglevel=1 --confirm' 'migrated=1' -os::cmd::expect_success_and_text 'oc get istag test:1 --template "{{ .image.dockerImageReference }}"' '^my.docker.io/mysql2@sha256:' -os::cmd::expect_success_and_text 'oc get istag test:2 --template "{{ .image.dockerImageReference }}"' '^php@sha256:' -# all items in history are changed -os::cmd::expect_success_and_text 'oc adm migrate image-references --include=imagestreams docker.io/*=my.docker.io/* --all-namespaces=false --loglevel=1 --confirm' 'migrated=1' -os::cmd::expect_success_and_not_text 'oc get is test --template "{{ range .status.tags }}{{ range .items }}{{ .dockerImageReference }}{{ \"\n\" }}{{ end }}{{ end }}"' '^php' -os::cmd::expect_success_and_not_text 'oc get is test --template "{{ range .status.tags }}{{ range .items }}{{ .dockerImageReference }}{{ \"\n\" }}{{ end }}{{ end }}"' '^mysql' +os::test::junit::declare_suite_end' '\[ERROR\] jUnit suite marker could not be placed, expected suites in flight, got 0' +# should not be able to end more suites than are in flight +os::cmd::expect_failure_and_text 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT +os::test::junit::declare_suite_start whatever +os::test::junit::declare_suite_start whateverelse os::test::junit::declare_suite_end - -os::test::junit::declare_suite_start "cmd/migrate/legacyhpa" -# create a legacy and a normal HPA -os::cmd::expect_success 'oc create -f test/testdata/hpa/legacy-and-normal-hpa.yaml' -# verify dry run -os::cmd::expect_success_and_text 'oc adm migrate legacy-hpa' 'migrated=1' -# confirm... -os::cmd::expect_success_and_text 'oc adm migrate legacy-hpa --confirm' 'migrated=1' -# verify that all HPAs are as they should be -os::cmd::expect_success_and_text 'oc get hpa legacy-hpa -o jsonpath="{.spec.scaleTargetRef.apiVersion}.{.spec.scaleTargetRef.kind} {.spec.scaleTargetRef.name}"' 'apps.openshift.io/v1.DeploymentConfig legacy-target' -os::cmd::expect_success_and_text 'oc get hpa other-hpa -o jsonpath="{.spec.scaleTargetRef.apiVersion}.{.spec.scaleTargetRef.kind} {.spec.scaleTargetRef.name}"' 'apps/v1.Deployment other-target' os::test::junit::declare_suite_end +os::test::junit::declare_suite_end' '\[ERROR\] jUnit suite marker could not be placed, expected suites in flight, got 0' +# should be able to staart a test +os::cmd::expect_success 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT +os::test::junit::declare_suite_start whatever +os::test::junit::declare_test_start' +# shouldn't be able to end a test that hasn't been started +os::cmd::expect_failure_and_text 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT +os::test::junit::declare_test_end' '\[ERROR\] jUnit test marker could not be placed, expected one test in flight, got 0' +# should be able to start and end a test case +os::cmd::expect_success 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT +os::test::junit::declare_suite_start whatever +os::test::junit::declare_test_start +os::test::junit::declare_test_end' +# shouldn't be able to end too many test cases +os::cmd::expect_failure_and_text 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT +os::test::junit::declare_suite_start whatever +os::test::junit::declare_test_start +os::test::junit::declare_test_end +os::test::junit::declare_test_end' '\[ERROR\] jUnit test marker could not be placed, expected one test in flight, got 0' +# shouldn't be able to start a test without a suite +os::cmd::expect_failure_and_text 'unset NUM_OS_JUNIT_SUITES_IN_FLIGHT NUM_OS_JUNIT_TESTS_IN_FLIGHT JUNIT_REPORT_OUTPUT +os::test::junit::declare_test_start' '\[ERROR\] jUnit test marker could not be placed, expected suites in flight, got 0' os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdMigrateShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdMigrateSh, nil +func testExtendedTestdataCmdTestCmdFrameworkTestShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdFrameworkTestSh, nil } -func testExtendedTestdataCmdTestCmdMigrateSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdMigrateShBytes() +func testExtendedTestdataCmdTestCmdFrameworkTestSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdFrameworkTestShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/migrate.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/framework-test.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdNewappSh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdGetSh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT # Cleanup cluster resources created by this test ( set +e - oc login -u system:admin oc delete all,templates --all - oc delete all,templates --all -n openshift - oc delete project template-substitute - oc delete project prefix-template-substitute - oc delete project test-imagestreams - oc delete project new-app-syntax - rm -rf ./test/testdata/testapp + oc delete users.user.openshift.io test-user-1 exit 0 ) &>/dev/null -os::util::environment::setup_time_vars - -os::test::junit::declare_suite_start "cmd/newapp" - -default_project=$(oc project -q) -#os::cmd::expect_success 'git clone https://github.com/openshift/ruby-hello-world.git ./test/testdata/testapp' - -# imagestream/tag creation and reuse -os::cmd::expect_success 'oc create -f ${TEST_DATA}/image-streams/image-streams-centos7.json -n openshift' -os::cmd::expect_success 'oc delete istag php:latest -n openshift' -os::cmd::expect_success 'oc new-project test-imagestreams' -os::cmd::try_until_failure 'oc get istag php:latest -n openshift' - -# should fail due to missing php:latest tag -os::cmd::expect_failure 'oc new-app --image-stream=openshift/php https://github.com/sclorg/cakephp-ex' -# should succeed and create the php:latest tag in the current namespace -os::cmd::expect_success 'oc new-app --docker-image=library/php https://github.com/sclorg/cakephp-ex --strategy=source' -os::cmd::try_until_success 'oc get istag php:latest -n test-imagestreams' -os::cmd::expect_success 'oc create istag php:latest --from=openshift/php:7.1 -n openshift' +os::test::junit::declare_suite_start "cmd/get" +os::cmd::expect_success_and_text 'oc create service loadbalancer testsvc1 --tcp=8080' "service/testsvc1 created" +# mixed resource output should print resource kind +# prefix even when only one type of resource is present +os::cmd::expect_success_and_text 'oc get all' "service/testsvc1" +# ensure that getting mixed resource types still returns prefixed resources, if there are at most resources of one type +os::cmd::expect_success_and_text 'oc get svc,pod' "service/testsvc1" +os::cmd::expect_failure_and_text 'oc get svc,pod testsvc1' "testsvc1" +# create second resource type and ensure that prefixed resource names are returned for both +os::cmd::expect_success_and_text 'oc create imagestream testimg1' "imagestream.image.openshift.io/testimg1 created" +os::cmd::expect_success_and_text 'oc get svc,is' "service/testsvc1" +# create second service and expect ` + "`" + `get all` + "`" + ` to still append resource kind to multiple of one type of resource +os::cmd::expect_success_and_text 'oc create service loadbalancer testsvc2 --tcp=8081' "service/testsvc2 created" +os::cmd::expect_success_and_text 'oc get all' "service/testsvc2" +# test tuples of same and different resource kinds (tuples of same resource kind should not return prefixed items). +os::cmd::expect_success_and_not_text 'oc get svc/testsvc1 svc/testsvc2' "service/testsvc1" +os::cmd::expect_success_and_text 'oc get svc/testsvc1 is/testimg1' "service/testsvc1" +os::cmd::expect_success_and_text 'oc get --v=8 svc/testsvc1 is/testimg1' "round_trippers.go" +# specific resources should not have their kind prefixed +os::cmd::expect_success_and_text 'oc get svc' "testsvc1" +# test --show-labels displays labels for users +os::cmd::expect_success 'oc create user test-user-1' +os::cmd::expect_success 'oc label user/test-user-1 customlabel=true' +os::cmd::expect_success_and_text 'oc get users test-user-1 --show-labels' "customlabel=true" +os::cmd::expect_success_and_not_text 'oc get users test-user-1' "customlabel=true" +# test structured and unstructured resources print generically without panic +os::cmd::expect_success_and_text 'oc get projectrequests -o yaml' 'status: Success' +os::cmd::expect_success_and_text 'oc get projectrequests,svc,pod -o yaml' 'kind: List' +# test --wacth does not result in an error when a resource list is served in multiple chunks +os::cmd::expect_success 'oc create cm cmone' +os::cmd::expect_success 'oc create cm cmtwo' +os::cmd::expect_success 'oc create cm cmthree' +os::cmd::expect_success_and_not_text 'oc get configmap --chunk-size=1 --watch --request-timeout=1s' 'watch is only supported on individual resources' +os::cmd::expect_success_and_not_text 'oc get configmap --chunk-size=1 --watch-only --request-timeout=1s' 'watch is only supported on individual resources' +echo "oc get: ok" +os::test::junit::declare_suite_end +`) -# create a new tag for an existing imagestream in the current namespace -os::cmd::expect_success 'oc create istag perl:5.20 --from=openshift/perl:5.20' -os::cmd::expect_success 'oc new-app --docker-image=library/perl https://github.com/sclorg/dancer-ex --strategy=source' -os::cmd::try_until_success 'oc get istag perl:latest -n test-imagestreams' +func testExtendedTestdataCmdTestCmdGetShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdGetSh, nil +} -# remove redundant imagestream tag before creating objects -os::cmd::expect_success_and_text 'oc new-app openshift/ruby-27-centos7 https://github.com/openshift/ruby-hello-world --strategy=docker --loglevel=5' 'Removing duplicate tag from object list' +func testExtendedTestdataCmdTestCmdGetSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdGetShBytes() + if err != nil { + return nil, err + } -# create imagestream in the correct namespace -os::cmd::expect_success 'oc new-app --name=mytest --image-stream=mysql --env=MYSQL_USER=test --env=MYSQL_PASSWORD=redhat --env=MYSQL_DATABASE=testdb -l app=mytest' -os::cmd::try_until_success 'oc get is mytest -n test-imagestreams' + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/get.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} -# don't create an unnecessary imagestream -os::cmd::expect_success 'oc new-app https://github.com/sclorg/nodejs-ex' -os::cmd::expect_failure_and_text 'oc get is nodejs -n test-imagestreams' 'not found' +var _testExtendedTestdataCmdTestCmdHelpSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" +trap os::test::junit::reconcile_output EXIT -# check reuse imagestreams -os::cmd::expect_success "oc new-build -D $'FROM node:8\nRUN echo \"Test\"' --name=node8" -os::cmd::try_until_success 'oc get istag node:8' -os::cmd::expect_success "oc new-build -D $'FROM node:10\nRUN echo \"Test\"' --name=node10" -os::cmd::try_until_success 'oc get istag node:10' +os::test::junit::declare_suite_start "cmd/help" +# This test validates the help commands and output text -# cleanup and reset to default namespace -os::cmd::expect_success 'oc delete is --all -n openshift' -os::cmd::expect_success 'oc delete project test-imagestreams' +# verify some default commands +os::cmd::expect_success 'kubectl' +os::cmd::expect_success 'oc' +os::cmd::expect_success 'oc ex' +os::cmd::expect_failure 'origin' -# This test validates the new-app command -os::cmd::expect_success 'oc project ${default_project}' -os::cmd::expect_success_and_text 'oc new-app library/php mysql -o yaml' '3306' -os::cmd::expect_success_and_text 'oc new-app library/php mysql --dry-run' "Image \"library/php\" runs as the 'root' user which may not be permitted by your cluster administrator" -os::cmd::expect_failure 'oc new-app unknownhubimage -o yaml' -os::cmd::expect_failure_and_text 'oc new-app docker.io/node~https://github.com/sclorg/nodejs-ex' 'the image match \"docker.io/node\" for source repository \"https://github.com/sclorg/nodejs-ex\" does not appear to be a source-to-image builder.' -os::cmd::expect_failure_and_text 'oc new-app https://github.com/sclorg/rails-ex' 'the image match \"ruby\" for source repository \"https://github.com/sclorg/rails-ex\" does not appear to be a source-to-image builder.' -os::cmd::expect_success 'oc new-app https://github.com/sclorg/rails-ex --strategy=source --dry-run' -# verify we can generate a container image based component "mongodb" directly -os::cmd::expect_success_and_text 'oc new-app mongo -o yaml' 'image:\s*mongo' -# the local image repository takes precedence over the Docker Hub "mysql" image -os::cmd::expect_success 'oc create -f examples/image-streams/image-streams-centos7.json' -os::cmd::try_until_success 'oc get imagestreamtags mysql:latest' $((2*TIME_MIN)) -os::cmd::try_until_success 'oc get imagestreamtags mysql:5.5' $((2*TIME_MIN)) -os::cmd::try_until_success 'oc get imagestreamtags mysql:5.6' $((2*TIME_MIN)) -os::cmd::try_until_success 'oc get imagestreamtags mysql:5.7' $((2*TIME_MIN)) -os::cmd::expect_success_and_not_text 'oc new-app mysql -o yaml' 'image:\s*mysql' -os::cmd::expect_success_and_not_text 'oc new-app mysql --dry-run' "runs as the 'root' user which may not be permitted by your cluster administrator" -# trigger and output should say 5.6 -os::cmd::expect_success_and_text 'oc new-app mysql -o yaml' 'mysql:5.7' -os::cmd::expect_success_and_text 'oc new-app mysql --dry-run' 'tag "5.7" for "mysql"' -# test deployments are created with the boolean flag and printed in the UI -os::cmd::expect_success_and_text 'oc new-app mysql --dry-run --as-test' 'This image will be test deployed' -os::cmd::expect_success_and_text 'oc new-app mysql -o yaml --as-test' 'test: true' -os::cmd::expect_success_and_text 'oc new-app ${TEST_DATA}/new-app/template-minimal-expose.json --as-test' 'Access your application via route' -os::cmd::expect_success 'oc delete all -l app=expose-output' -os::cmd::expect_success_and_text 'oc new-app mysql --as-test' 'Application is not exposed' -os::cmd::expect_success 'oc delete all -l app=mysql' +# help for root commands must be consistent +os::cmd::expect_success_and_text 'oc' 'OpenShift Client' +os::cmd::expect_success_and_text 'oc -h' 'Build and Deploy Commands:' +os::cmd::expect_success_and_text 'oc -h' 'Other Commands:' +os::cmd::expect_success_and_text 'oc policy --help' 'add-role-to-user' +os::cmd::expect_success_and_not_text 'oc policy --help' 'Other Commands' +os::cmd::expect_success_and_not_text 'oc -h' 'Options' +os::cmd::expect_success_and_not_text 'oc -h' 'Global Options' +os::cmd::expect_failure_and_text 'oc adm ca' 'Manage certificates' +os::cmd::expect_success_and_text 'oc exec --help' '\-\- COMMAND \[args\.\.\.\]$' +os::cmd::expect_success_and_text 'oc rsh --help' 'COMMAND' -# ensure that oc new-app does not emit a BuildConfigInstantiateFailed event when creating a new application -os::cmd::expect_success 'oc new-app https://github.com/sclorg/ruby-ex' -os::cmd::expect_success_and_not_text 'oc describe bc/ruby-ex' 'BuildConfigInstantiateFailed' -os::cmd::expect_success 'oc delete all -l app=ruby-ex' +# help for root commands with --help flag must be consistent +os::cmd::expect_success_and_text 'oc --help' 'OpenShift Client' +os::cmd::expect_success_and_text 'oc login --help' 'Options' +os::cmd::expect_success_and_not_text 'oc login --help' 'Global Options' +os::cmd::expect_success_and_text 'oc login --help' 'insecure-skip-tls-verify' -# Ensure that an invalid build strategy in a template does not throw a segmentation fault -os::cmd::expect_success_and_not_text 'oc new-app --file ${TEST_DATA}/new-app/invalid-build-strategy.yaml --dry-run' 'invalid memory address or nil pointer dereference' +# help for given command with --help flag must be consistent +os::cmd::expect_success_and_text 'oc get --help' 'Display one or many resources' +os::cmd::expect_success_and_text 'oc project --help' 'Switch to another project' +os::cmd::expect_success_and_text 'oc projects --help' 'existing projects' +os::cmd::expect_success_and_text 'oc get --help' 'oc' -# test that imagestream references across imagestreams do not cause an error -os::cmd::try_until_success 'oc get imagestreamtags ruby:2.7' -os::cmd::expect_success 'oc create -f ${TEST_DATA}/new-app/imagestream-ref.yaml' -os::cmd::try_until_success 'oc get imagestreamtags myruby:latest' -os::cmd::expect_success 'oc new-app myruby~https://github.com/openshift/ruby-hello-world.git --dry-run' -os::cmd::expect_success 'oc delete is myruby' +# help for given command through help command must be consistent +os::cmd::expect_success_and_text 'oc help get' 'Display one or many resources' +os::cmd::expect_success_and_text 'oc help project' 'Switch to another project' +os::cmd::expect_success_and_text 'oc help projects' 'current active project and existing projects on the server' -# Ensure clear error message wrt templates container CRDs and new-app appears -os::cmd::expect_failure_and_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-crd.yaml' 'error: The template contained an object type unknown to ' +# help tips must be consistent +os::cmd::expect_success_and_text 'oc --help' 'Use "oc --help" for more information' +os::cmd::expect_success_and_text 'oc --help' 'Use "oc options" for a list of global' +os::cmd::expect_success_and_text 'oc help' 'Use "oc --help" for more information' +os::cmd::expect_success_and_text 'oc help' 'Use "oc options" for a list of global' +os::cmd::expect_success_and_text 'oc set --help' 'Use "oc set --help" for more information' +os::cmd::expect_success_and_text 'oc set --help' 'Use "oc options" for a list of global' +os::cmd::expect_success_and_text 'oc set env --help' 'Use "oc options" for a list of global' -# docker strategy with repo that has no dockerfile -os::cmd::expect_failure_and_text 'oc new-app https://github.com/sclorg/nodejs-ex --strategy=docker' 'No Dockerfile was found' +# runnable commands with required flags must error consistently +os::cmd::expect_failure_and_text 'oc get' 'Required resource not specified' -# repo related error message validation -os::cmd::expect_success 'oc create -f examples/db-templates/mysql-persistent-template.json' -os::cmd::expect_failure_and_text 'oc new-app mysql-persisten mysql' 'only a partial match was found for' -os::cmd::expect_success 'oc delete template/mysql-persistent' -os::cmd::expect_failure_and_text 'oc new-app --strategy=docker https://192.30.253.113/openshift/ruby-hello-world.git' 'none of the arguments provided could be classified as a source code location' -os::cmd::expect_failure_and_text 'oc new-app https://www.google.com/openshift/nodejs-e' 'unable to load template file' -os::cmd::expect_failure_and_text 'oc new-app https://www.google.com/openshift/nodejs-e' 'unable to locate any' -os::cmd::expect_failure_and_text 'oc new-app https://www.google.com/openshift/nodejs-e' 'was classified as an image, image~source, or loaded template reference.' -os::cmd::expect_failure_and_text 'oc new-app https://examplegit.com/openshift/nodejs-e' 'unable to load template file' -os::cmd::expect_failure_and_text 'oc new-app https://examplegit.com/openshift/nodejs-e' 'unable to locate any' -os::cmd::expect_failure_and_text 'oc new-app https://examplegit.com/openshift/nodejs-e' 'was classified as an image, image~source, or loaded template reference.' -os::cmd::expect_failure_and_text 'oc new-build --strategy=docker https://192.30.253.113/openshift/ruby-hello-world.git' 'none of the arguments provided could be classified as a source code location' -os::cmd::expect_failure_and_text 'oc new-build https://www.google.com/openshift/nodejs-e' 'unable to load template file' -os::cmd::expect_failure_and_text 'oc new-build https://www.google.com/openshift/nodejs-e' 'unable to locate any' -os::cmd::expect_failure_and_text 'oc new-build https://www.google.com/openshift/nodejs-e' 'was classified as an image, image~source, or loaded template reference.' -os::cmd::expect_failure_and_text 'oc new-build https://examplegit.com/openshift/nodejs-e' 'unable to load template file' -os::cmd::expect_failure_and_text 'oc new-build https://examplegit.com/openshift/nodejs-e' 'unable to locate any' -os::cmd::expect_failure_and_text 'oc new-build https://examplegit.com/openshift/nodejs-e' 'was classified as an image, image~source, or loaded template reference.' -os::cmd::expect_failure_and_text 'oc new-build --name imagesourcetest python~https://github.com/openshift-katacoda/blog-django-py --source-image xxx --source-image-path=yyy --dry-run' 'unable to locate any ' -os::cmd::expect_failure_and_text 'oc new-app ~java' 'you must specify a image name' +# commands that expect file paths must validate and error out correctly +os::cmd::expect_failure_and_text 'oc login --certificate-authority=/path/to/invalid' 'no such file or directory' -# setting source secret via the --source-secret flag -os::cmd::expect_success_and_text 'oc new-app https://github.com/sclorg/cakephp-ex --source-secret=mysecret -o yaml' 'name: mysecret' -os::cmd::expect_success_and_text 'oc new-build https://github.com/sclorg/cakephp-ex --source-secret=mynewsecret -o yaml' 'name: mynewsecret' -os::cmd::expect_failure_and_text 'oc new-app https://github.com/sclorg/cakephp-ex --source-secret=InvalidSecretName -o yaml' 'error: source secret name "InvalidSecretName" is invalid' -os::cmd::expect_success_and_text 'oc new-app -f examples/quickstarts/cakephp-mysql.json --source-secret=mysecret -o yaml' 'name: mysecret' -os::cmd::expect_success 'oc new-app https://github.com/sclorg/cakephp-ex --source-secret=mysecret' -os::cmd::expect_success 'oc delete all --selector="label=cakephp-ex"' -# setting push secret via the --push-secret flag -os::cmd::expect_success_and_text 'oc new-build https://github.com/sclorg/cakephp-ex --push-secret=mynewsecret -o yaml' 'name: mynewsecret' -os::cmd::expect_failure_and_text 'oc new-build https://github.com/sclorg/cakephp-ex --push-secret=InvalidSecretName -o yaml' 'error: push secret name "InvalidSecretName" is invalid' +# make sure that typoed commands come back with non-zero return codes +os::cmd::expect_failure 'oc policy TYPO' +os::cmd::expect_failure 'oc secrets TYPO' +# make sure that LDAP group sync and prune exist under both experimental and ` + "`" + `oc adm` + "`" + ` +os::cmd::expect_success_and_text 'oc adm groups sync --help' 'external provider' +os::cmd::expect_success_and_text 'oc adm groups prune --help' 'external provider' +os::cmd::expect_success_and_text 'oc adm prune groups --help' 'external provider' -# check label creation -os::cmd::try_until_success 'oc get imagestreamtags php:latest' -os::cmd::try_until_success 'oc get imagestreamtags php:5.5' -os::cmd::try_until_success 'oc get imagestreamtags php:5.6' -os::cmd::expect_success 'oc new-app php mysql -l no-source=php-mysql' -os::cmd::expect_success 'oc delete all -l no-source=php-mysql' -os::cmd::expect_success 'oc new-app php mysql' -os::cmd::expect_success 'oc delete all -l app=php' -os::cmd::expect_failure 'oc get dc/mysql' -os::cmd::expect_failure 'oc get dc/php' -os::cmd::expect_success_and_text 'oc new-app -f ${TEST_DATA}/new-app/template-without-app-label.json -o yaml' 'app: ruby-helloworld-sample' +os::test::junit::declare_suite_end +`) -# check object namespace handling -# hardcoded values should be stripped -os::cmd::expect_success_and_not_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-namespaces.json -o jsonpath="{.items[?(@.metadata.name==\"stripped\")].metadata.namespace}"' 'STRIPPED' -# normal parameterized values should be substituted and retained -os::cmd::expect_success_and_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-namespaces.json -o jsonpath="{.items[?(@.metadata.name==\"route-edge-substituted\")].metadata.namespace}"' 'substituted' -os::cmd::expect_success_and_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-namespaces.json -o jsonpath="{.items[?(@.metadata.name==\"route-edge-prefix-substituted\")].metadata.namespace}"' 'prefix-substituted' -# non-string parameterized values should be stripped -os::cmd::expect_failure_and_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-namespaces.json -o jsonpath="{.items[?(@.metadata.name==\"route-edge-refstripped\")].metadata.namespace}"' 'namespace is not found' -os::cmd::expect_failure_and_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-namespaces.json -o jsonpath="{.items[?(@.metadata.name==\"route-edge-prefix-refstripped\")].metadata.namespace}"' 'namespace is not found' -# ensure --build-env environment variables get added to the buildconfig -os::cmd::expect_success_and_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-app-label.json --build-env FOO=bar -o yaml' 'FOO' -# ensure the objects can actually get created with a namespace specified -os::cmd::expect_success 'oc new-project template-substitute' -os::cmd::expect_success 'oc new-project prefix-template-substitute' -os::cmd::expect_success 'oc project ${default_project}' -os::cmd::expect_success 'oc new-app -f ${TEST_DATA}/new-app/template-with-namespaces.json -p SUBSTITUTED=template-substitute' -os::cmd::expect_success 'oc delete all -l app=ruby-helloworld-sample' +func testExtendedTestdataCmdTestCmdHelpShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdHelpSh, nil +} -# ensure non-duplicate invalid label errors show up -os::cmd::expect_failure_and_text 'oc new-app docker.io/library/wordpress -l qwer1345%$$#=self' 'error: ImageStream.image.openshift.io "wordpress" is invalid' -os::cmd::expect_failure_and_text 'oc new-app docker.io/library/wordpress -l qwer1345%$$#=self' 'DeploymentConfig.apps.openshift.io "wordpress" is invalid' -os::cmd::expect_failure_and_text 'oc new-app docker.io/library/wordpress -l qwer1345%$$#=self' 'Service "wordpress" is invalid' +func testExtendedTestdataCmdTestCmdHelpSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdHelpShBytes() + if err != nil { + return nil, err + } -# check if we can create from a stored template -os::cmd::expect_success 'oc create -f examples/sample-app/application-template-stibuild.json' -os::cmd::expect_success 'oc get template ruby-helloworld-sample' -os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample -o yaml' 'MYSQL_USER' -os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample -o yaml' 'MYSQL_PASSWORD' -os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample --param MYSQL_PASSWORD=hello -o yaml' 'hello' -os::cmd::expect_success_and_text 'oc new-app -e FOO=BAR -f examples/jenkins/jenkins-ephemeral-template.json -o jsonpath="{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"FOO\")].value}" ' '^BAR$' -os::cmd::expect_success_and_text 'oc new-app -e OPENSHIFT_ENABLE_OAUTH=false -f examples/jenkins/jenkins-ephemeral-template.json -o jsonpath="{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"OPENSHIFT_ENABLE_OAUTH\")].value}" ' 'false' + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/help.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} -# check that multiple resource groups are printed with their respective external version -os::cmd::expect_success_and_text 'oc new-app -f ${TEST_DATA}/new-app/template_multiple_resource_gvs.yaml -o yaml' 'apiVersion: apps/v1' +var _testExtendedTestdataCmdTestCmdIdleSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" +trap os::test::junit::reconcile_output EXIT -# check that an error is produced when using --context-dir with a template -os::cmd::expect_failure_and_text 'oc new-app -f examples/sample-app/application-template-stibuild.json --context-dir=example' '\-\-context-dir is not supported when using a template' +# Cleanup cluster resources created by this test +( + set +e + oc delete all,templates --all + exit 0 +) &>/dev/null -# check that values are not split on commas -os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample --param MYSQL_DATABASE=hello,MYSQL_USER=fail -o yaml' 'value: hello,MYSQL_USER=fail' -# check that warning is printed when --param PARAM1=VAL1,PARAM2=VAL2 is used -os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample --param MYSQL_DATABASE=hello,MYSQL_USER=fail -o yaml' 'no longer accepts comma-separated list' -# check that env vars are not split on commas -os::cmd::expect_success_and_text 'oc new-app php --env PASS=one,two=three -o yaml' 'value: one,two=three' -# check that warning is printed when --env PARAM1=VAL1,PARAM2=VAL2 is used -os::cmd::expect_success_and_text 'oc new-app php --env PASS=one,two=three -o yaml' 'no longer accepts comma-separated list' -# check that warning is not printed when --param/env doesn't contain two k-v pairs -os::cmd::expect_success_and_not_text 'oc new-app php --env DEBUG=disabled -o yaml' 'no longer accepts comma-separated list' -os::cmd::expect_success_and_not_text 'oc new-app php --env LEVELS=INFO,WARNING -o yaml' 'no longer accepts comma-separated list' -os::cmd::expect_success_and_not_text 'oc new-app ruby-helloworld-sample --param MYSQL_USER=mysql -o yaml' 'no longer accepts comma-separated list' -os::cmd::expect_success_and_not_text 'oc new-app ruby-helloworld-sample --param MYSQL_PASSWORD=com,ma -o yaml' 'no longer accepts comma-separated list' -# check that warning is not printed when env vars are passed positionally -os::cmd::expect_success_and_text 'oc new-app php PASS=one,two=three -o yaml' 'value: one,two=three' -os::cmd::expect_success_and_not_text 'oc new-app php PASS=one,two=three -o yaml' 'no longer accepts comma-separated list' +project="$(oc project -q)" +idled_at_annotation='idling.alpha.openshift.io/idled-at' +unidle_target_annotation='idling.alpha.openshift.io/unidle-targets' +prev_scale_annotation='idling.alpha.openshift.io/previous-scale' +idled_at_template="{{index .metadata.annotations \"${idled_at_annotation}\"}}" +unidle_target_template="{{index .metadata.annotations \"${unidle_target_annotation}\"}}" +prev_scale_template="{{index .metadata.annotations \"${prev_scale_annotation}\"}}" +dc_name="" -# check that we can populate template parameters from file -param_file="${TEST_DATA}/new-app/test-cmd-newapp-params.env" -os::cmd::expect_success_and_text "oc new-app ruby-helloworld-sample --param-file ${param_file} -o jsonpath='{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"MYSQL_DATABASE\")].value}'" 'thisisadatabase' -os::cmd::expect_success_and_text "oc new-app ruby-helloworld-sample --param-file ${param_file} --param MYSQL_DATABASE=otherdatabase -o jsonpath='{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"MYSQL_DATABASE\")].value}'" 'otherdatabase' -os::cmd::expect_success_and_text "oc new-app ruby-helloworld-sample --param-file ${param_file} --param MYSQL_DATABASE=otherdatabase -o yaml" 'ignoring value from file' -os::cmd::expect_success_and_text "cat ${param_file} | oc new-app ruby-helloworld-sample --param-file - -o jsonpath='{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"MYSQL_DATABASE\")].value}'" 'thisisadatabase' +setup_idling_resources() { + os::cmd::expect_success 'oc delete all --all' -os::cmd::expect_failure_and_text "oc new-app ruby-helloworld-sample --param-file does/not/exist" 'no such file or directory' -os::cmd::expect_failure_and_text "oc new-app ruby-helloworld-sample --param-file ${TEST_DATA}" 'is a directory' -os::cmd::expect_success "oc new-app ruby-helloworld-sample --param-file /dev/null -o yaml" -os::cmd::expect_success "oc new-app ruby-helloworld-sample --param-file /dev/null --param-file ${param_file} -o yaml" -os::cmd::expect_failure_and_text "echo 'fo%(o=bar' | oc new-app ruby-helloworld-sample --param-file -" 'invalid parameter assignment' -os::cmd::expect_failure_and_text "echo 'S P A C E S=test' | oc new-app ruby-helloworld-sample --param-file -" 'invalid parameter assignment' + # set up resources for the idle command + os::cmd::expect_success 'oc create -f ${TEST_DATA}/idling-svc-route.yaml' + dc_name=$(basename $(oc create -f ${TEST_DATA}/idling-dc.yaml -o name)) # ` + "`" + `basename type/name` + "`" + ` --> name + os::cmd::expect_success "oc describe deploymentconfigs '${dc_name}'" + os::cmd::try_until_success 'oc describe endpoints idling-echo' -os::cmd::expect_failure_and_text 'oc new-app ruby-helloworld-sample --param ABSENT_PARAMETER=absent -o yaml' 'unexpected parameter name' -os::cmd::expect_success 'oc new-app ruby-helloworld-sample --param ABSENT_PARAMETER=absent -o yaml --ignore-unknown-parameters' + # deployer pod won't work, so just scale up the rc ourselves + os::cmd::try_until_success "oc get replicationcontroller ${dc_name}-1" + os::cmd::expect_success "oc scale replicationcontroller ${dc_name}-1 --replicas=2" + os::cmd::try_until_text "oc get pod -l app=idling-echo -o go-template='{{ len .items }}'" "2" -# check that we can set environment variables from env file -env_file="${TEST_DATA}/new-app/test-cmd-newapp-env.env" -os::cmd::expect_success_and_text "oc new-app php --env-file ${env_file} -o jsonpath='{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"SOME_VAR\")].value}'" 'envvarfromfile' -os::cmd::expect_success_and_text "oc new-app php --env-file ${env_file} --env SOME_VAR=fromcmdline -o jsonpath='{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"SOME_VAR\")].value}'" 'fromcmdline' -os::cmd::expect_success_and_text "oc new-app php --env-file ${env_file} --env SOME_VAR=fromcmdline -o yaml" 'ignoring value from file' -os::cmd::expect_success_and_text "cat ${env_file} | oc new-app php --env-file - -o jsonpath='{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"SOME_VAR\")].value}'" 'envvarfromfile' + # wait for endpoints to populate. Ensure subset exists first to avoid nil dereference. + os::cmd::try_until_success "oc get endpoints idling-echo -o go-template='{{ index .subsets 0 }}'" + os::cmd::try_until_text "oc get endpoints idling-echo -o go-template='{{ len (index .subsets 0).addresses }}'" "2" +} -os::cmd::expect_failure_and_text "oc new-app php --env-file does/not/exist" 'no such file or directory' -os::cmd::expect_failure_and_text "oc new-app php --env-file ${TEST_DATA}/new-app" 'is a directory' -os::cmd::expect_success "oc new-app php --env-file /dev/null -o yaml" -os::cmd::expect_success "oc new-app php --env-file /dev/null --env-file ${env_file} -o yaml" -os::cmd::expect_failure_and_text "echo 'fo%(o=bar' | oc new-app php --env-file -" 'invalid parameter assignment' -os::cmd::expect_failure_and_text "echo 'S P A C E S=test' | oc new-app php --env-file -" 'invalid parameter assignment' +os::test::junit::declare_suite_start "cmd/idle/by-name" +setup_idling_resources +os::cmd::expect_failure "oc idle dc/${dc_name}" # make sure manually passing non-endpoints resources fails +os::cmd::expect_success_and_text 'oc idle idling-echo' "The service will unidle DeploymentConfig \"${project}/${dc_name}\" to 2 replicas once it receives traffic" +os::cmd::expect_success_and_text "oc get endpoints idling-echo -o go-template='${idled_at_template}'" '.' +#os::cmd::expect_success_and_text "oc get endpoints idling-echo -o go-template='${unidle_target_template}' | jq '.[] | select(.name == \"${dc_name}\") | (.replicas == 2 and .kind == \"DeploymentConfig\")'" 'true' +os::test::junit::declare_suite_end -# new-build -# check that env vars are not split on commas and warning is printed where they previously have -os::cmd::expect_success_and_text 'oc new-build --binary php --env X=Y,Z=W -o yaml' 'value: Y,Z=W' -os::cmd::expect_success_and_text 'oc new-build --binary php --env X=Y,Z=W -o yaml' 'no longer accepts comma-separated list' -os::cmd::expect_success_and_text 'oc new-build --binary php --env X=Y,Z,W -o yaml' 'value: Y,Z,W' -os::cmd::expect_success_and_not_text 'oc new-build --binary php --env X=Y,Z,W -o yaml' 'no longer accepts comma-separated list' -os::cmd::expect_success_and_not_text 'oc new-build --binary php --env X=Y -o yaml' 'no longer accepts comma-separated list' +os::test::junit::declare_suite_start "cmd/idle/by-label" +setup_idling_resources +os::cmd::expect_success_and_text 'oc idle -l app=idling-echo' "The service will unidle DeploymentConfig \"${project}/${dc_name}\" to 2 replicas once it receives traffic" +os::cmd::expect_success_and_text "oc get endpoints idling-echo -o go-template='${idled_at_template}'" '.' +#os::cmd::expect_success_and_text "oc get endpoints idling-echo -o go-template='${unidle_target_template}' | jq '.[] | select(.name == \"${dc_name}\") | (.replicas == 2 and .kind == \"DeploymentConfig\")'" 'true' +os::test::junit::declare_suite_end -# new-build - load envvars from file -os::cmd::expect_success_and_text "oc new-build --binary php --env-file ${env_file} -o jsonpath='{.items[?(@.kind==\"BuildConfig\")].spec.strategy.sourceStrategy.env[?(@.name==\"SOME_VAR\")].value}'" 'envvarfromfile' -os::cmd::expect_success_and_text "oc new-build --binary php --env-file ${env_file} --env SOME_VAR=fromcmdline -o jsonpath='{.items[?(@.kind==\"BuildConfig\")].spec.strategy.sourceStrategy.env[?(@.name==\"SOME_VAR\")].value}'" 'fromcmdline' -os::cmd::expect_success_and_text "oc new-build --binary php --env-file ${env_file} --env SOME_VAR=fromcmdline -o yaml" 'ignoring value from file' -os::cmd::expect_success_and_text "cat ${env_file} | oc new-build --binary php --env-file ${env_file} -o jsonpath='{.items[?(@.kind==\"BuildConfig\")].spec.strategy.sourceStrategy.env[?(@.name==\"SOME_VAR\")].value}'" 'envvarfromfile' +os::test::junit::declare_suite_start "cmd/idle/all" +setup_idling_resources +os::cmd::expect_success_and_text 'oc idle --all' "The service will unidle DeploymentConfig \"${project}/${dc_name}\" to 2 replicas once it receives traffic" +os::cmd::expect_success_and_text "oc get endpoints idling-echo -o go-template='${idled_at_template}'" '.' +#os::cmd::expect_success_and_text "oc get endpoints idling-echo -o go-template='${unidle_target_template}' | jq '.[] | select(.name == \"${dc_name}\") | (.replicas == 2 and .kind == \"DeploymentConfig\")'" 'true' +os::test::junit::declare_suite_end -os::cmd::expect_failure_and_text "oc new-build --binary php --env-file does/not/exist" 'no such file or directory' -os::cmd::expect_failure_and_text "oc new-build --binary php --env-file ${TEST_DATA}/new-app" 'is a directory' -os::cmd::expect_success "oc new-build --binary php --env-file /dev/null -o yaml" -os::cmd::expect_success "oc new-build --binary php --env-file /dev/null --env-file ${env_file} -o yaml" -os::cmd::expect_failure_and_text "echo 'fo%(o=bar' | oc new-build --binary php --env-file -" 'invalid parameter assignment' -os::cmd::expect_failure_and_text "echo 'S P A C E S=test' | oc new-build --binary php --env-file -" 'invalid parameter assignment' +os::test::junit::declare_suite_start "cmd/idle/check-previous-scale" +setup_idling_resources # scales up to 2 replicas +os::cmd::expect_success_and_text 'oc idle idling-echo' "The service will unidle DeploymentConfig \"${project}/${dc_name}\" to 2 replicas once it receives traffic" +os::cmd::expect_success_and_text "oc get dc ${dc_name} -o go-template='${prev_scale_template}'" '2' # we see the result of the initial scale as the previous scale +os::test::junit::declare_suite_end +`) -# check that we can set environment variables from build-env file -build_env_file="${TEST_DATA}/new-app/test-cmd-newapp-build-env.env" +func testExtendedTestdataCmdTestCmdIdleShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdIdleSh, nil +} -os::cmd::expect_failure_and_text "oc new-app php --build-env-file does/not/exist" 'no such file or directory' -os::cmd::expect_failure_and_text "oc new-app php --build-env-file ${TEST_DATA}/new-app" 'is a directory' -os::cmd::expect_success "oc new-app php --build-env-file /dev/null -o yaml" -os::cmd::expect_success "oc new-app php --build-env-file /dev/null --build-env-file ${build_env_file} -o yaml" -os::cmd::expect_failure_and_text "echo 'fo%(o=bar' | oc new-app php --build-env-file -" 'invalid parameter assignment' -os::cmd::expect_failure_and_text "echo 'S P A C E S=test' | oc new-app php --build-env-file -" 'invalid parameter assignment' +func testExtendedTestdataCmdTestCmdIdleSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdIdleShBytes() + if err != nil { + return nil, err + } -# new-build -# check that build env vars are not split on commas and warning is printed where they previously have -os::cmd::expect_success_and_text 'oc new-build --binary php --build-env X=Y,Z=W -o yaml' 'value: Y,Z=W' -os::cmd::expect_success_and_text 'oc new-build --binary php --build-env X=Y,Z=W -o yaml' 'no longer accepts comma-separated list' -os::cmd::expect_success_and_text 'oc new-build --binary php --build-env X=Y,Z,W -o yaml' 'value: Y,Z,W' -os::cmd::expect_success_and_not_text 'oc new-build --binary php --build-env X=Y,Z,W -o yaml' 'no longer accepts comma-separated list' -os::cmd::expect_success_and_not_text 'oc new-build --binary php --build-env X=Y -o yaml' 'no longer accepts comma-separated list' + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/idle.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} -# new-build - load build env vars from file -os::cmd::expect_success_and_text "oc new-build --binary php --build-env-file ${build_env_file} -o jsonpath='{.items[?(@.kind==\"BuildConfig\")].spec.strategy.sourceStrategy.env[?(@.name==\"SOME_VAR\")].value}'" 'buildenvvarfromfile' -os::cmd::expect_success_and_text "oc new-build --binary php --build-env-file ${build_env_file} --env SOME_VAR=fromcmdline -o jsonpath='{.items[?(@.kind==\"BuildConfig\")].spec.strategy.sourceStrategy.env[?(@.name==\"SOME_VAR\")].value}'" 'fromcmdline' -os::cmd::expect_success_and_text "oc new-build --binary php --build-env-file ${build_env_file} --env SOME_VAR=fromcmdline -o yaml" 'ignoring value from file' -os::cmd::expect_success_and_text "cat ${build_env_file} | oc new-build --binary php --build-env-file - -o jsonpath='{.items[?(@.kind==\"BuildConfig\")].spec.strategy.sourceStrategy.env[?(@.name==\"SOME_VAR\")].value}'" 'buildenvvarfromfile' +var _testExtendedTestdataCmdTestCmdImageLookupSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" +trap os::test::junit::reconcile_output EXIT -os::cmd::expect_failure_and_text "oc new-build --binary php --build-env-file does/not/exist" 'no such file or directory' -os::cmd::expect_failure_and_text "oc new-build --binary php --build-env-file ${TEST_DATA}/new-app" 'is a directory' -os::cmd::expect_success "oc new-build --binary php --build-env-file /dev/null -o yaml" -os::cmd::expect_success "oc new-build --binary php --build-env-file /dev/null --env-file ${build_env_file} -o yaml" -os::cmd::expect_failure_and_text "echo 'fo%(o=bar' | oc new-build --binary php --build-env-file -" 'invalid parameter assignment' -os::cmd::expect_failure_and_text "echo 'S P A C E S=test' | oc new-build --binary php --build-env-file -" 'invalid parameter assignment' +# Cleanup cluster resources created by this test +( + set +e + oc delete all,is,pods --all -# new-build - check that we can set build args in DockerStrategy -os::cmd::expect_success_and_text "oc new-build ${TEST_DATA}/new-app/build-arg-dockerfile --build-arg 'foo=bar' --to 'test' -o jsonpath='{.items[?(@.kind==\"BuildConfig\")].spec.strategy.dockerStrategy.buildArgs[?(@.name==\"foo\")].value}'" 'bar' + exit 0 +) &> /dev/null -# check that we cannot set build args in a non-DockerStrategy build -os::cmd::expect_failure_and_text "oc new-build https://github.com/openshift/ruby-hello-world --strategy=source --build-arg 'foo=bar'" "error: Cannot use '--build-arg' without a Docker build" -os::cmd::expect_failure_and_text "oc new-build https://github.com/sclorg/ruby-ex --build-arg 'foo=bar'" "error: Cannot use '--build-arg' without a Docker build" +project="$( oc project -q )" +os::test::junit::declare_suite_start "cmd/image-lookup" +## This test validates image lookup resolution # -# verify we can create from a template when some objects in the template declare an app label -# the app label will not be applied to any objects in the template. -os::cmd::expect_success_and_not_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-app-label.json -o yaml' 'app: ruby-helloworld-sample' -# verify the existing app label on an object is not overridden by new-app -os::cmd::expect_success_and_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-app-label.json -o yaml' 'app: myapp' +## TODO: fix and re-enable these tests before 4.0 release +# +## Verify image resolution on default resource types +os::cmd::expect_success_and_text "oc import-image --confirm --from=nginx:latest nginx:latest" "sha256:" +os::cmd::expect_success_and_text "oc set image-lookup is/nginx" "updated" +## Image lookup works for pods +os::cmd::expect_success "oc run --generator=run-pod/v1 --restart=Never --image=nginx:latest nginx" +os::cmd::expect_success_and_text "oc get pod/nginx -o jsonpath='{.spec.containers[0].image}'" "nginx@sha256:" +## Image lookup works for jobs +os::cmd::expect_success "oc create job --image=nginx:latest nginx" +os::cmd::expect_success_and_text "oc get job/nginx -o jsonpath='{.spec.template.spec.containers[0].image}'" "nginx@sha256:" +## Image lookup works for replica sets +os::cmd::expect_success "oc create deployment --image=nginx:latest nginx" +os::cmd::expect_success_and_text "oc get rs -o jsonpath='{..spec.template.spec.containers[0].image}'" "nginx@sha256:" +## Image lookup works for replication controllers +rc='{"kind":"ReplicationController","apiVersion":"v1","metadata":{"name":"nginx"},"spec":{"template":{"metadata":{"labels":{"app":"test"}},"spec":{"containers":[{"name":"main","image":"nginx:latest"}]}}}}' +os::cmd::expect_success "echo '${rc}' | oc create -f -" +os::cmd::expect_success_and_text "oc get rc/nginx -o jsonpath='{.spec.template.spec.containers[0].image}'" "nginx@sha256:" +# +## Verify swapping settings on image stream +os::cmd::expect_success_and_text "oc set image-lookup is/nginx --v=1" "was not changed" +os::cmd::expect_success_and_text "oc set image-lookup nginx --v=1" "was not changed" +os::cmd::expect_success_and_text "oc set image-lookup is --list" "nginx.*true" +os::cmd::expect_success_and_text "oc set image-lookup nginx --enabled=false" "updated" +os::cmd::expect_success_and_text "oc set image-lookup is --list" "nginx.*false" +os::cmd::expect_failure_and_text "oc set image-lookup unknown --list" "the server doesn't have a resource type" +os::cmd::expect_success_and_text "oc set image-lookup secrets --list" "false" +# +## Clear resources +os::cmd::expect_success "oc delete deploy,dc,rs,rc,pods --all" +# +## Resource annotated with image lookup will create pods that resolve +os::cmd::expect_success "oc tag nginx:latest alternate:latest" +rc='{"kind":"Deployment","apiVersion":"apps/v1","metadata":{"name":"alternate"},"spec":{"selector":{"matchLabels":{"app":"test"}},"template":{"metadata":{"labels":{"app":"test"}},"spec":{"containers":[{"name":"main","image":"alternate:latest"}]}}}}' +os::cmd::expect_success "echo '${rc}' | oc set image-lookup --local -f - -o json | oc create -f -" +os::cmd::expect_success "oc run --generator=run-pod/v1 --restart=Never --image=alternate:latest alternate" +os::cmd::expect_success_and_text "oc get pod/alternate -o jsonpath='{.spec.containers[0].image}'" "alternate:latest" +os::cmd::expect_success_and_text "oc get rs -o jsonpath='{..spec.template.spec.containers[0].image}'" "nginx@sha256:" -# verify that a template can be passed in stdin -os::cmd::expect_success 'cat ${TEST_DATA}/application-template-stibuild.json | oc new-app -o yaml -f -' +os::test::junit::declare_suite_end +`) -# check search -os::cmd::expect_success_and_text 'oc new-app --search mysql' "Tags:\s+5.7, latest" -os::cmd::expect_success_and_text 'oc new-app --search ruby-helloworld-sample' 'ruby-helloworld-sample' -# check search - partial matches -os::cmd::expect_success_and_text 'oc new-app --search ruby-hellow' 'ruby-helloworld-sample' -os::cmd::expect_success_and_text 'oc new-app --search --template=ruby-hel' 'ruby-helloworld-sample' -os::cmd::expect_success_and_text 'oc new-app --search --template=ruby-helloworld-sam -o yaml' 'ruby-helloworld-sample' -os::cmd::expect_success_and_text 'oc new-app --search rub' "Tags:\s+2.3, 2.4, 2.5, latest" -os::cmd::expect_success_and_text 'oc new-app --search --image-stream=rub' "Tags:\s+2.3, 2.4, 2.5, latest" -# check search - check correct usage of filters -os::cmd::expect_failure_and_not_text 'oc new-app --search --image-stream=ruby-heloworld-sample' 'application-template-stibuild' -os::cmd::expect_failure 'oc new-app --search --template=php' -os::cmd::expect_failure 'oc new-app -S --template=nodejs' -os::cmd::expect_failure 'oc new-app -S --template=perl' -# check search - filtered, exact matches -# make sure the imagestreams are imported first. -os::cmd::try_until_success 'oc get imagestreamtags mariadb:latest' -os::cmd::try_until_success 'oc get imagestreamtags mariadb:10.1' -os::cmd::try_until_success 'oc get imagestreamtags mariadb:10.2' -os::cmd::try_until_success 'oc get imagestreamtags mongodb:latest' -os::cmd::try_until_success 'oc get imagestreamtags mongodb:2.4' -os::cmd::try_until_success 'oc get imagestreamtags mongodb:2.6' -os::cmd::try_until_success 'oc get imagestreamtags mongodb:3.2' -os::cmd::try_until_success 'oc get imagestreamtags mongodb:3.4' -os::cmd::try_until_success 'oc get imagestreamtags mysql:latest' -os::cmd::try_until_success 'oc get imagestreamtags mysql:5.5' -os::cmd::try_until_success 'oc get imagestreamtags mysql:5.6' -os::cmd::try_until_success 'oc get imagestreamtags mysql:5.7' -os::cmd::try_until_success 'oc get imagestreamtags nginx:latest' -os::cmd::try_until_success 'oc get imagestreamtags nginx:1.8' -os::cmd::try_until_success 'oc get imagestreamtags nginx:1.10' -os::cmd::try_until_success 'oc get imagestreamtags nginx:1.12' -os::cmd::try_until_success 'oc get imagestreamtags nodejs:latest' -os::cmd::try_until_success 'oc get imagestreamtags nodejs:0.10' -os::cmd::try_until_success 'oc get imagestreamtags nodejs:4' -os::cmd::try_until_success 'oc get imagestreamtags nodejs:6' -os::cmd::try_until_success 'oc get imagestreamtags nodejs:8' -os::cmd::try_until_success 'oc get imagestreamtags perl:latest' -os::cmd::try_until_success 'oc get imagestreamtags perl:5.16' -os::cmd::try_until_success 'oc get imagestreamtags perl:5.20' -os::cmd::try_until_success 'oc get imagestreamtags perl:5.24' -os::cmd::try_until_success 'oc get imagestreamtags php:latest' -os::cmd::try_until_success 'oc get imagestreamtags php:5.5' -os::cmd::try_until_success 'oc get imagestreamtags php:5.6' -os::cmd::try_until_success 'oc get imagestreamtags php:7.0' -os::cmd::try_until_success 'oc get imagestreamtags php:7.1' -os::cmd::try_until_success 'oc get imagestreamtags postgresql:latest' -os::cmd::try_until_success 'oc get imagestreamtags postgresql:9.2' -os::cmd::try_until_success 'oc get imagestreamtags postgresql:9.4' -os::cmd::try_until_success 'oc get imagestreamtags postgresql:9.5' -os::cmd::try_until_success 'oc get imagestreamtags postgresql:9.6' -os::cmd::try_until_success 'oc get imagestreamtags python:latest' -os::cmd::try_until_success 'oc get imagestreamtags python:2.7' -os::cmd::try_until_success 'oc get imagestreamtags python:3.3' -os::cmd::try_until_success 'oc get imagestreamtags python:3.4' -os::cmd::try_until_success 'oc get imagestreamtags python:3.5' -os::cmd::try_until_success 'oc get imagestreamtags python:3.6' -os::cmd::try_until_success 'oc get imagestreamtags ruby:latest' -os::cmd::try_until_success 'oc get imagestreamtags ruby:2.7' -os::cmd::try_until_success 'oc get imagestreamtags wildfly:latest' -os::cmd::try_until_success 'oc get imagestreamtags wildfly:12.0' -os::cmd::try_until_success 'oc get imagestreamtags wildfly:11.0' -os::cmd::try_until_success 'oc get imagestreamtags wildfly:10.1' -os::cmd::try_until_success 'oc get imagestreamtags wildfly:10.0' -os::cmd::try_until_success 'oc get imagestreamtags wildfly:9.0' -os::cmd::try_until_success 'oc get imagestreamtags wildfly:8.1' +func testExtendedTestdataCmdTestCmdImageLookupShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdImageLookupSh, nil +} -os::cmd::expect_success_and_text 'oc new-app --search --image-stream=mariadb' "Tags:\s+10.1, 10.2, latest" -os::cmd::expect_success_and_text 'oc new-app --search --image-stream=mongodb' "Tags:\s+3.2, 3.4, 3.6, latest" -os::cmd::expect_success_and_text 'oc new-app --search --image-stream=mysql' "Tags:\s+5.7, latest" -os::cmd::expect_success_and_text 'oc new-app --search --image-stream=nginx' "Tags:\s+1.10, 1.12, 1.8, latest" -os::cmd::expect_success_and_text 'oc new-app --search --image-stream=nodejs' "Tags:\s+10, 11, 6, 8, 8-RHOAR, latest" -os::cmd::expect_success_and_text 'oc new-app --search --image-stream=perl' "Tags:\s+5.24, 5.26, latest" -os::cmd::expect_success_and_text 'oc new-app --search --image-stream=php' "Tags:\s+7.0, 7.1, latest" -os::cmd::expect_success_and_text 'oc new-app --search --image-stream=postgresql' "Tags:\s+9.5, 9.6, latest" -os::cmd::expect_success_and_text 'oc new-app -S --image-stream=python' "Tags:\s+2.7, 3.6, latest" -os::cmd::expect_success_and_text 'oc new-app -S --image-stream=ruby' "Tags:\s+2.6, 2.7, latest" -os::cmd::expect_success_and_text 'oc new-app -S --image-stream=wildfly' "Tags:\s+20.0, 21.0, latest" -os::cmd::expect_success_and_text 'oc new-app --search --template=ruby-helloworld-sample' 'ruby-helloworld-sample' -# check search - no matches -os::cmd::expect_failure_and_text 'oc new-app -S foo-the-bar' 'no matches found' -os::cmd::expect_failure_and_text 'oc new-app --search winter-is-coming' 'no matches found' -# check search - mutually exclusive flags -os::cmd::expect_failure_and_text 'oc new-app -S mysql --env=FOO=BAR' "can't be used" -os::cmd::expect_failure_and_text 'oc new-app --search mysql --code=https://github.com/openshift/ruby-hello-world' "can't be used" -os::cmd::expect_failure_and_text 'oc new-app --search mysql --param=FOO=BAR' "can't be used" -# check specifying a non-existent template does not cause an index out of range error -os::cmd::expect_failure_and_not_text 'oc new-app --template foo' 'index out of range' +func testExtendedTestdataCmdTestCmdImageLookupSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdImageLookupShBytes() + if err != nil { + return nil, err + } -# set context-dir -os::cmd::expect_success_and_text 'oc new-app https://github.com/sclorg/s2i-ruby-container.git --context-dir="2.4/test/puma-test-app" -o yaml' 'contextDir: 2.4/test/puma-test-app' -os::cmd::expect_success_and_text 'oc new-app ruby~https://github.com/sclorg/s2i-ruby-container.git --context-dir="2.4/test/puma-test-app" -o yaml' 'contextDir: 2.4/test/puma-test-app' + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/image-lookup.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} -# set strategy -os::cmd::expect_success_and_text 'oc new-app ruby~https://github.com/openshift/ruby-hello-world.git --strategy=docker -o yaml' 'dockerStrategy' -os::cmd::expect_success_and_text 'oc new-app https://github.com/openshift/ruby-hello-world.git --strategy=source -o yaml' 'sourceStrategy' +var _testExtendedTestdataCmdTestCmdImagesSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" +trap os::test::junit::reconcile_output EXIT -# prints root user info -os::cmd::expect_success_and_not_text 'oc new-app --dry-run mysql' "runs as the 'root' user" -os::cmd::expect_success_and_text 'oc new-app --dry-run --docker-image=mysql' "WARNING: Image \"mysql\" runs as the 'root' user" +# Cleanup cluster resources created by this test +( + set +e + original_context="$( oc config current-context )" + os::cmd::expect_success 'oc login -u system:admin' + cluster_admin_context="$( oc config current-context )" + os::cmd::expect_success "oc config use-context '${original_context}'" + oc delete project test-cmd-images-2 merge-tags --context=${cluster_admin_context} + oc delete all,templates --all --context=${cluster_admin_context} -# verify multiple errors are displayed together, a nested error is returned, and that the usage message is displayed -os::cmd::expect_failure_and_text 'oc new-app --dry-run __template_fail __templatefile_fail' 'error: unable to locate any' -os::cmd::expect_failure_and_text 'oc new-app --dry-run __template_fail __templatefile_fail' 'with name "__templatefile_fail"' -os::cmd::expect_failure_and_text 'oc new-app --dry-run __template_fail __templatefile_fail' 'error: unable to find the specified template file' -os::cmd::expect_failure_and_text 'oc new-app --dry-run __template_fail __templatefile_fail' "The 'oc new-app' command will match arguments" + exit 0 +) &> /dev/null -# verify partial match error -os::cmd::expect_failure_and_text 'oc new-app --dry-run mysq' 'error: only a partial match was found for "mysq"' -os::cmd::expect_failure_and_text 'oc new-app --dry-run mysq' 'The argument "mysq" only partially matched' -os::cmd::expect_failure_and_text 'oc new-app --dry-run mysq' "Image stream \"mysql\" \\(tag \"5.7\"\\) in project" +project="$( oc project -q )" -# ensure new-app with pr ref does not fail -os::cmd::expect_success 'oc new-app https://github.com/openshift/ruby-hello-world#refs/pull/58/head --dry-run' +os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}" +# This test validates images and image streams along with the tag and import-image commands -# verify image streams with no tags are reported correctly and that --allow-missing-imagestream-tags works -# new-app -os::cmd::expect_success 'printf "apiVersion: v1\nkind: ImageStream\nmetadata:\n name: emptystream\n" | oc create -f -' -os::cmd::expect_failure_and_text 'oc new-app --dry-run emptystream' 'error: no tags found on matching image stream' -os::cmd::expect_success 'oc new-app --dry-run emptystream --allow-missing-imagestream-tags' -# new-build -os::cmd::expect_failure_and_text 'oc new-build --dry-run emptystream~https://github.com/sclorg/ruby-ex' 'error: no tags found on matching image stream' -os::cmd::expect_success 'oc new-build --dry-run emptystream~https://github.com/sclorg/ruby-ex --allow-missing-imagestream-tags --strategy=source' +# some steps below require that we use system:admin privileges, but we don't +# want to stomp on whatever context we were given when we started +original_context="$( oc config current-context )" +os::cmd::expect_success 'oc login -u system:admin' +cluster_admin_context="$( oc config current-context )" +os::cmd::expect_success "oc config use-context '${original_context}'" -# Allow setting --name when specifying grouping -os::cmd::expect_success "oc new-app mysql+ruby~https://github.com/sclorg/ruby-ex --name foo -o yaml" -# but not with multiple components -os::cmd::expect_failure_and_text "oc new-app mysql ruby~https://github.com/sclorg/ruby-ex --name foo -o yaml" "error: only one component or source repository can be used when specifying a name" -# do not allow specifying output image when specifying multiple input repos -os::cmd::expect_failure_and_text 'oc new-build https://github.com/sclorg/nodejs-ex https://github.com/sclorg/ruby-ex --to foo' 'error: only one component with source can be used when specifying an output image reference' -# but succeed with multiple input repos and no output image specified -os::cmd::expect_success 'oc new-build https://github.com/sclorg/nodejs-ex https://github.com/sclorg/ruby-ex -o yaml' -# check that binary build with a builder image results in a source type build -os::cmd::expect_success_and_text 'oc new-build --binary --image-stream=ruby -o yaml' 'type: Source' -# check that binary build with a specific strategy uses that strategy regardless of the image type -os::cmd::expect_success_and_text 'oc new-build --binary --image=ruby --strategy=docker -o yaml' 'type: Docker' +os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/images" +os::cmd::expect_success "oc get images --context='${cluster_admin_context}'" +os::cmd::expect_success "oc create -f '${TEST_DATA}/test-image.json' --context='${cluster_admin_context}'" +os::cmd::expect_success "oc delete images test --context='${cluster_admin_context}'" +echo "images: ok" +os::test::junit::declare_suite_end -# When only a single imagestreamtag exists, and it does not match the implicit default -# latest tag, new-app should fail. -# when latest exists, we default to it and match it. -os::cmd::expect_success 'oc new-app --image-stream ruby https://github.com/sclorg/rails-ex --dry-run' -# when latest does not exist, there are multiple partial matches (2.2, 2.3, 2.4, 2.5) -os::cmd::expect_success 'oc delete imagestreamtag ruby:latest' -os::cmd::expect_failure_and_text 'oc new-app --image-stream ruby https://github.com/sclorg/rails-ex --dry-run' 'error: multiple images or templates matched \"ruby\"' -# when only 2.6 exists, there is a single partial match (2.6) -os::cmd::expect_success 'oc delete imagestreamtag ruby:2.7' -os::cmd::expect_failure_and_text 'oc new-app --image-stream ruby https://github.com/sclorg/rails-ex --dry-run' 'error: only a partial match was found for \"ruby\":' -# when the tag is specified explicitly, the operation is successful -os::cmd::expect_success 'oc new-app --image-stream ruby:2.7 https://github.com/sclorg/rails-ex --dry-run' -os::cmd::expect_success 'oc delete imagestreams --all' +os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/imagestreams" +os::cmd::expect_success 'oc get imageStreams' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-image-stream.json' +# can't check status since there is no registry running so internalRegistryHostname isn't populated. +#os::cmd::expect_success_and_text "oc get imageStreams test --template='{{.status.dockerImageRepository}}'" 'test' +os::cmd::expect_success 'oc delete imageStreams test' +os::cmd::expect_failure 'oc get imageStreams test' -# newapp does not attempt to create an imagestream that already exists for a container image -os::cmd::expect_success_and_text 'oc new-app docker.io/ruby:latest~https://github.com/sclorg/ruby-ex.git --name=testapp1 --strategy=docker' 'imagestream.image.openshift.io "ruby" created' -# make sure the ruby:latest tag is imported before we run new-app again -os::cmd::try_until_success 'oc get imagestreamtags ruby:latest' -os::cmd::expect_success_and_not_text 'oc new-app docker.io/ruby:latest~https://github.com/sclorg/ruby-ex.git --name=testapp2 --strategy=docker' '"ruby:latest" already exists' -os::cmd::expect_success 'oc delete all -l app=testapp2' -os::cmd::expect_success 'oc delete all -l app=testapp1' -os::cmd::expect_success 'oc delete all -l app=ruby --ignore-not-found' -os::cmd::expect_success 'oc delete imagestreams --all --ignore-not-found' -# newapp does not attempt to create an imagestream that already exists for a container image -os::cmd::expect_success 'oc new-app docker.io/ruby:2.7' -# the next one technically fails cause the DC is already created, but we should still see the ist created -os::cmd::expect_failure_and_text 'oc new-app docker.io/ruby:2.7' 'imagestreamtag.image.openshift.io "ruby:2.7" created' -os::cmd::expect_success 'oc delete imagestreams --all --ignore-not-found' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/image-streams/image-streams-centos7.json' +# can't check status since there is no registry running so internalRegistryHostname isn't populated. +#os::cmd::expect_success_and_text "oc get imageStreams ruby --template='{{.status.dockerImageRepository}}'" 'ruby' +#os::cmd::expect_success_and_text "oc get imageStreams nodejs --template='{{.status.dockerImageRepository}}'" 'nodejs' +#os::cmd::expect_success_and_text "oc get imageStreams wildfly --template='{{.status.dockerImageRepository}}'" 'wildfly' +#os::cmd::expect_success_and_text "oc get imageStreams mysql --template='{{.status.dockerImageRepository}}'" 'mysql' +#os::cmd::expect_success_and_text "oc get imageStreams postgresql --template='{{.status.dockerImageRepository}}'" 'postgresql' +#os::cmd::expect_success_and_text "oc get imageStreams mongodb --template='{{.status.dockerImageRepository}}'" 'mongodb' +#os::cmd::expect_success_and_text "oc get imageStreams httpd --template='{{.status.dockerImageRepository}}'" 'httpd' -# check that we can create from the template without errors -os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample -l app=helloworld' 'service "frontend" created' -os::cmd::expect_success 'oc delete all -l app=helloworld' -os::cmd::expect_success 'oc delete secret dbsecret' -os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample -l app=helloworld -o name' 'service/frontend' -os::cmd::expect_success 'oc delete all -l app=helloworld' -os::cmd::expect_success 'oc delete secret dbsecret' -os::cmd::expect_success 'oc delete template ruby-helloworld-sample' -# override component names -os::cmd::expect_success_and_text 'oc new-app mysql --name=db' 'db' -os::cmd::expect_success 'oc new-app https://github.com/openshift/ruby-hello-world -l app=ruby' -os::cmd::expect_success 'oc delete all -l app=ruby' -# check for error when template JSON file has errors -jsonfile="${TEST_DATA}/new-app/invalid.json" -os::cmd::expect_failure_and_text "oc new-app '${jsonfile}'" "error: unable to load template file \"${jsonfile}\": error parsing ${jsonfile}: json: line 0: invalid character '}' after object key" +# verify the image repository had its tags populated +os::cmd::try_until_success 'oc get imagestreamtags wildfly:latest' +os::cmd::expect_success_and_text "oc get imageStreams wildfly --template='{{ index .metadata.annotations \"openshift.io/image.dockerRepositoryCheck\"}}'" '[0-9]{4}\-[0-9]{2}\-[0-9]{2}' # expect a date like YYYY-MM-DD +os::cmd::expect_success_and_text 'oc get istag' 'wildfly' -# check new-build -os::cmd::expect_failure_and_text 'oc new-build mysql -o yaml' 'you must specify at least one source repository URL' -os::cmd::expect_success_and_text 'oc new-build mysql --binary -o yaml --to mysql:bin' 'type: Binary' -os::cmd::expect_success_and_text 'oc new-build mysql https://github.com/openshift/ruby-hello-world --strategy=docker -o yaml' 'type: Docker' -os::cmd::expect_failure_and_text 'oc new-build mysql https://github.com/openshift/ruby-hello-world --binary' 'specifying binary builds and source repositories at the same time is not allowed' -# binary builds cannot be created unless a builder image is specified. -os::cmd::expect_failure_and_text 'oc new-build --name mybuild --binary --strategy=source -o yaml' 'you must provide a builder image when using the source strategy with a binary build' -os::cmd::expect_success_and_text 'oc new-build --name mybuild registry.centos.org/centos/ruby-27-centos7 --binary --strategy=source -o yaml' 'name: ruby-27-centos7:latest' -# binary builds can be created with no builder image if no strategy or docker strategy is specified -os::cmd::expect_success_and_text 'oc new-build --name mybuild --binary -o yaml' 'type: Binary' -os::cmd::expect_success_and_text 'oc new-build --name mybuild --binary --strategy=docker -o yaml' 'type: Binary' +# create an image stream and post a mapping to it +#os::cmd::expect_success 'oc create imagestream test' +#os::cmd::expect_success 'oc create -f test/testdata/mysql-image-stream-mapping.yaml' +#os::cmd::expect_success_and_text 'oc get istag/test:new --template="{{ index .image.dockerImageMetadata.Config.Entrypoint 0 }}"' "docker-entrypoint.sh" +#os::cmd::expect_success_and_text 'oc get istag/test:new -o jsonpath={.image.metadata.name}' 'sha256:b2f400f4a5e003b0543decf61a0a010939f3fba07bafa226f11ed7b5f1e81237' +# reference should point to the current repository, and that repository should match the reported dockerImageRepository for pushes +#repository="$( oc get is/test -o jsonpath='{.status.dockerImageRepository}' )" +#os::cmd::expect_success_and_text 'oc get istag/test:new -o jsonpath={.image.dockerImageReference}' "^$repository@sha256:b2f400f4a5e003b0543decf61a0a010939f3fba07bafa226f11ed7b5f1e81237" +#os::cmd::expect_success_and_text 'oc get istag/test:new -o jsonpath={.image.dockerImageReference}' "/$project/test@sha256:b2f400f4a5e003b0543decf61a0a010939f3fba07bafa226f11ed7b5f1e81237" -# new-build image source tests -os::cmd::expect_failure_and_text 'oc new-build mysql --source-image centos' 'error: --source-image-path must be specified when --source-image is specified.' -os::cmd::expect_failure_and_text 'oc new-build mysql --source-image-path foo' 'error: --source-image must be specified when --source-image-path is specified.' +#repository="$( oc get is/test -o jsonpath='{.status.dockerImageRepository}' )" +#os::cmd::expect_success "oc annotate --context='${cluster_admin_context}' --overwrite image/sha256:b2f400f4a5e003b0543decf61a0a010939f3fba07bafa226f11ed7b5f1e81237 images.openshift.io/deny-execution=true" +# TODO: re-enable before 4.0 release +#os::cmd::expect_failure_and_text "oc run vulnerable --image=${repository}:new --restart=Never" 'spec.containers\[0\].image: Forbidden: this image is prohibited by policy' -# ensure circular ref flagged but allowed for template -os::cmd::expect_success 'oc create -f ${TEST_DATA}/new-app/circular-is.yaml' -os::cmd::expect_success_and_text 'oc new-app -f ${TEST_DATA}/new-app/circular.yaml' 'should be different than input' -# ensure circular does not choke on image stream image -os::cmd::expect_success_and_not_text 'oc new-app -f ${TEST_DATA}/new-app/bc-from-imagestreamimage.json --dry-run' 'Unable to follow reference type' +# test image stream tag operations +os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.generation}' '2' +os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.from.kind}' 'ImageStreamTag' +os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.from.name}' '21.0' +os::cmd::expect_success 'oc annotate istag/wildfly:latest foo=bar' +os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.metadata.annotations.foo}' 'bar' +os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.annotations.foo}' 'bar' +os::cmd::expect_success 'oc annotate istag/wildfly:latest foo-' +os::cmd::expect_success_and_not_text 'oc get istag/wildfly:latest -o jsonpath={.metadata.annotations}' 'bar' +os::cmd::expect_success_and_not_text 'oc get istag/wildfly:latest -o jsonpath={.tag.annotations}' 'bar' +os::cmd::expect_success "oc patch istag/wildfly:latest -p='{\"tag\":{\"from\":{\"kind\":\"DockerImage\",\"name\":\"quay.io/wildfly/wildfly-centos7:19.0\"}}}'" +os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.from.kind}' 'DockerImage' +os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.from.name}' 'quay.io/wildfly/wildfly-centos7:19.0' +os::cmd::expect_success_and_not_text 'oc get istag/wildfly:latest -o jsonpath={.tag.generation}' '2' -# do not allow use of non-existent image (should fail) -os::cmd::expect_failure_and_text 'oc new-app openshift/bogusimage https://github.com/openshift/ruby-hello-world.git -o yaml' "unable to locate any" -# allow use of non-existent image (should succeed) -os::cmd::expect_success 'oc new-app openshift/bogusimage https://github.com/openshift/ruby-hello-world.git -o yaml --allow-missing-images' +# create an image stream tag +os::cmd::expect_success 'oc create imagestreamtag tag:1 --from=wildfly:21.0' +os::cmd::expect_success 'oc create imagestreamtag tag:2 --from-image=quay.io/openshifttest/hello-openshift:openshift' +os::cmd::try_until_success 'oc get imagestreamtags tag:2' +os::cmd::expect_success 'oc create imagestreamtag tag:3 -A foo=bar' +os::cmd::expect_success 'oc create imagestreamtag tag:4 --from=:2' +os::cmd::expect_success 'oc create imagestreamtag tag:5 --from=tag:2' +os::cmd::expect_success 'oc create imagestreamtag tag:6 --reference --from-image=quay.io/openshifttest/hello-openshift:openshift' +os::cmd::expect_success 'oc create imagestreamtag tag:7 --reference-policy=Local --from=tag:2' +os::cmd::expect_success 'oc create istag tag:8 --insecure --from-image=quay.io/openshifttest/hello-openshift:openshift' +os::cmd::try_until_success 'oc get imagestreamtags tag:8' +os::cmd::expect_success 'oc create imagestreamtag tag:9 --scheduled --reference-policy=Local --from-image=quay.io/openshifttest/hello-openshift:openshift' +os::cmd::expect_success 'oc create imagestream tag-b' +os::cmd::expect_success 'oc create imagestreamtag tag-b:1 --from-image=quay.io/wildfly/wildfly-centos7:20.0' +os::cmd::expect_success 'oc create imagestreamtag tag-c:1 -A annotation.with.dots=are.ok' -os::cmd::expect_success 'oc create -f ${TEST_DATA}/new-app/installable-stream.yaml' +os::cmd::expect_failure_and_text 'oc create imagestreamtag tag-b:1 --from=quay.io/wildfly/wildfly-centos7:20.0' 'registry may not be specified' +os::cmd::expect_failure_and_text 'oc create imagestreamtag tag-c --from-image=quay.io/openshifttest/hello-openshift:openshift' 'must be of the form :' +os::cmd::expect_failure_and_text 'oc create imagestreamtag tag-c:1 -A foo' 'annotations must be of the form key=value, but is "foo"' +os::cmd::expect_failure_and_text 'oc create imagestreamtag tag-c:2 --from=mysql --from-image=quay.io/openshifttest/hello-openshift:openshift' '\--from and --from-image may not be used together' -os::cmd::expect_success 'oc policy add-role-to-user edit test-user' -os::cmd::expect_success 'oc login -u test-user -p anything' -os::cmd::try_until_success 'oc project ${default_project}' +os::cmd::expect_success_and_text 'oc get istag/tag:1 -o jsonpath={.image.dockerImageReference}' 'wildfly-centos7.*@sha256:' +tag1=$( oc get istag/wildfly:20.0 -o jsonpath={.image.metadata.name} ) +os::cmd::expect_success_and_text 'oc get istag/tag-b:1 -o jsonpath={.image.metadata.name}' "${tag1}" +os::cmd::expect_success_and_text 'oc get istag/tag:2 -o jsonpath={.image.dockerImageReference}' 'hello-openshift@sha256:' +tag2=$( oc get istag/tag:2 -o jsonpath={.image.metadata.name} ) +os::cmd::expect_success_and_text "oc get is/tag -o 'jsonpath={.spec.tags[?(@.name==\"3\")].annotations.foo}'" 'bar' +os::cmd::expect_success_and_text 'oc get istag/tag:4 -o jsonpath={.image.metadata.name}' "${tag2}" +os::cmd::expect_success_and_text "oc get is/tag -o 'jsonpath={.spec.tags[?(@.name==\"4\")].from.name}'" '^2$' +os::cmd::expect_success_and_text 'oc get istag/tag:5 -o jsonpath={.image.metadata.name}' "${tag2}" +os::cmd::expect_success_and_text "oc get is/tag -o 'jsonpath={.spec.tags[?(@.name==\"6\")].reference}'" 'true' +os::cmd::expect_success_and_text "oc get is/tag -o 'jsonpath={.spec.tags[?(@.name==\"7\")].referencePolicy}'" 'Local' +os::cmd::expect_success_and_text "oc get is/tag -o 'jsonpath={.spec.tags[?(@.name==\"8\")].importPolicy.insecure}'" 'true' +os::cmd::expect_success_and_text "oc get is/tag -o 'jsonpath={.spec.tags[?(@.name==\"9\")].importPolicy.scheduled}'" 'true' -os::cmd::try_until_success 'oc get imagestreamtags installable:file' -os::cmd::try_until_success 'oc get imagestreamtags installable:token' -os::cmd::try_until_success 'oc get imagestreamtags installable:serviceaccount' -os::cmd::expect_failure 'oc new-app installable:file' -os::cmd::expect_failure_and_text 'oc new-app installable:file' 'requires that you grant the image access' -os::cmd::expect_failure_and_text 'oc new-app installable:serviceaccount' "requires an 'installer' service account with project editor access" -os::cmd::expect_success_and_text 'oc new-app installable:file --grant-install-rights -o yaml' '/var/run/openshift.secret.token' -os::cmd::expect_success_and_text 'oc new-app installable:file --grant-install-rights -o yaml' 'activeDeadlineSeconds: 14400' -os::cmd::expect_success_and_text 'oc new-app installable:file --grant-install-rights -o yaml' 'openshift.io/generated-job: "true"' -os::cmd::expect_success_and_text 'oc new-app installable:file --grant-install-rights -o yaml' 'openshift.io/generated-job.for: installable:file' -os::cmd::expect_success_and_text 'oc new-app installable:token --grant-install-rights -o yaml' 'name: TOKEN_ENV' -os::cmd::expect_success_and_text 'oc new-app installable:token --grant-install-rights -o yaml' 'openshift/origin@sha256:' -os::cmd::expect_success_and_text 'oc new-app installable:serviceaccount --grant-install-rights -o yaml' 'serviceAccountName: installer' -os::cmd::expect_success_and_text 'oc new-app installable:serviceaccount --grant-install-rights -o yaml' 'fieldPath: metadata.namespace' -os::cmd::expect_success_and_text 'oc new-app installable:serviceaccount --grant-install-rights -o yaml A=B' 'name: A' +os::cmd::expect_success 'oc delete imageStreams ruby' +os::cmd::expect_success 'oc delete imageStreams nodejs' +os::cmd::expect_success 'oc delete imageStreams wildfly' +os::cmd::expect_success 'oc delete imageStreams postgresql' +os::cmd::expect_success 'oc delete imageStreams mongodb' +os::cmd::expect_failure 'oc get imageStreams ruby' +os::cmd::expect_failure 'oc get imageStreams nodejs' +os::cmd::expect_failure 'oc get imageStreams postgresql' +os::cmd::expect_failure 'oc get imageStreams mongodb' +os::cmd::expect_failure 'oc get imageStreams wildfly' +os::cmd::try_until_success 'oc get imagestreamTags mysql:5.6' +os::cmd::try_until_success 'oc get imagestreamTags mysql:5.7' +os::cmd::expect_success_and_text "oc get imagestreams mysql --template='{{ index .metadata.annotations \"openshift.io/image.dockerRepositoryCheck\"}}'" '[0-9]{4}\-[0-9]{2}\-[0-9]{2}' # expect a date like YYYY-MM-DD +os::cmd::expect_success 'oc describe istag/mysql:latest' +os::cmd::expect_success_and_text 'oc describe istag/mysql:latest' 'Environment:' +os::cmd::expect_success_and_text 'oc describe istag/mysql:latest' 'Image Created:' +os::cmd::expect_success_and_text 'oc describe istag/mysql:latest' 'Image Name:' +os::cmd::expect_success_and_text 'oc describe istag/mysql:latest' 'Layers:' +name=$(oc get istag/mysql:latest --template='{{ .image.metadata.name }}') +imagename="isimage/mysql@${name:0:15}" +os::cmd::expect_success "oc describe ${imagename}" +os::cmd::expect_success_and_text "oc describe ${imagename}" 'Environment:' +os::cmd::expect_success_and_text "oc describe ${imagename}" 'Image Created:' +os::cmd::expect_success_and_text "oc describe ${imagename}" 'Image Name:' -# Ensure output is valid JSON -os::cmd::expect_success 'oc new-app mongo -o json | python -m json.tool' +# test prefer-os and prefer-arch annotations +os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-multiarch-stream.yaml' +os::cmd::try_until_success 'oc get istag test-multiarch-stream:linux-amd64' +os::cmd::try_until_success 'oc get istag test-multiarch-stream:linux-s390x' +os::cmd::expect_success_and_text 'oc get istag test-multiarch-stream:linux-amd64 --template={{.image.dockerImageMetadata.Architecture}}' 'amd64' +os::cmd::expect_success_and_text 'oc get istag test-multiarch-stream:linux-s390x --template={{.image.dockerImageMetadata.Architecture}}' 's390x' +os::cmd::expect_success 'oc delete is test-multiarch-stream' +echo "imageStreams: ok" +os::test::junit::declare_suite_end -# Ensure custom branch/ref works -os::cmd::expect_success 'oc new-app https://github.com/openshift/ruby-hello-world#beta4' +os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/import-image" +# should follow the latest reference to 5.6 and update that, and leave latest unchanged +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 1).from.kind}}'" 'DockerImage' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 2).from.kind}}'" 'ImageStreamTag' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 2).from.name}}'" '5.7' +# import existing tag (implicit latest) +os::cmd::expect_success_and_text 'oc import-image mysql' 'sha256:' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 1).from.kind}}'" 'DockerImage' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 2).from.kind}}'" 'ImageStreamTag' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 2).from.name}}'" '5.7' +# should prevent changing source +os::cmd::expect_failure_and_text 'oc import-image mysql --from=quay.io/openshifttest/hello-openshift:openshift' "use the 'tag' command if you want to change the source" +os::cmd::expect_success 'oc describe is/mysql' +# import existing tag (explicit) +os::cmd::expect_success_and_text 'oc import-image mysql:5.6' "sha256:" +os::cmd::expect_success_and_text 'oc import-image mysql:latest' "sha256:" +# import existing image stream creating new tag +os::cmd::expect_success_and_text 'oc import-image mysql:external --from=quay.io/openshifttest/hello-openshift:openshift' "sha256:" +os::cmd::expect_success_and_text "oc get istag/mysql:external --template='{{.tag.from.kind}}'" 'DockerImage' +os::cmd::expect_success_and_text "oc get istag/mysql:external --template='{{.tag.from.name}}'" 'quay.io/openshifttest/hello-openshift:openshift' +# import creates new image stream with single tag +os::cmd::expect_failure_and_text 'oc import-image mysql-new-single:latest --from=quay.io/openshifttest/hello-openshift:openshift' '\-\-confirm' +os::cmd::expect_success_and_text 'oc import-image mysql-new-single:latest --from=quay.io/openshifttest/hello-openshift:openshift --confirm' 'sha256:' +os::cmd::expect_success_and_text "oc get is/mysql-new-single --template='{{(len .spec.tags)}}'" '1' +os::cmd::expect_success 'oc delete is/mysql-new-single' +# import creates new image stream with all tags +os::cmd::expect_failure_and_text 'oc import-image mysql-new-all --from=quay.io/openshifttest/hello-openshift --all' '\-\-confirm' +os::cmd::expect_success_and_text 'oc import-image mysql-new-all --from=quay.io/openshifttest/hello-openshift --all --confirm --request-timeout=1m' 'sha256:' +name=$(oc get istag/mysql-new-all:openshift --template='{{ .image.metadata.name }}') +echo "import-image: ok" +os::test::junit::declare_suite_end -# Ensure the resulting BuildConfig doesn't have unexpected sources -os::cmd::expect_success_and_not_text 'oc new-app https://github.com/openshift/ruby-hello-world --output-version=v1 -o=jsonpath="{.items[?(@.kind==\"BuildConfig\")].spec.source}"' 'dockerfile|binary' +os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/tag" +# oc tag +os::cmd::expect_success 'oc tag mysql:latest mysql:tag1 --alias' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 4).from.kind}}'" 'ImageStreamTag' -# We permit running new-app against a remote URL which returns a template -os::cmd::expect_success 'oc new-app https://raw.githubusercontent.com/openshift/origin/master/examples/quickstarts/rails-postgresql.json --dry-run' +os::cmd::expect_success "oc tag mysql@${name} mysql:tag2 --alias" +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 5).from.kind}}'" 'ImageStreamImage' -# ensure that --strategy sets the build strategy -os::cmd::expect_success_and_text 'oc new-build --name sourcetest python~https://github.com/sclorg/django-ex --source-image centos:latest --source-image-path /tmp --strategy source --dry-run -o yaml' 'sourceStrategy' -os::cmd::expect_success_and_text 'oc new-build --name sourcetest python~https://github.com/sclorg/django-ex --source-image centos:latest --source-image-path /tmp --strategy pipeline --dry-run -o yaml' 'jenkinsPipelineStrategy' -os::cmd::expect_success_and_text 'oc new-build --name sourcetest python~https://github.com/sclorg/django-ex --source-image centos:latest --source-image-path /tmp --strategy docker --dry-run -o yaml' 'dockerStrategy' +os::cmd::expect_success 'oc tag mysql:notfound mysql:tag3 --alias' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 6).from.kind}}'" 'ImageStreamTag' -os::cmd::expect_success 'oc create -f examples/image-streams/image-streams-centos7.json' -os::cmd::try_until_success 'oc get imagestreamtags nodejs:latest' -# ensure that a build can be created with just image inputs without the --binary flag -os::cmd::expect_success_and_text 'oc new-build --name sourcetest --source-image centos:latest --source-image-path /tmp --image-stream nodejs --dry-run -o yaml' 'sourceStrategy' -# ensure that using only image inputs and the --binary flag results in an error -os::cmd::expect_failure_and_text 'oc new-build --name sourcetest --source-image centos:latest --source-image-path /tmp --image-stream nodejs --binary --dry-run -o yaml' 'specifying binary builds and source repositories at the same time is not allowed' -os::cmd::expect_success 'oc delete imagestreams --all --ignore-not-found' +os::cmd::expect_success 'oc tag --source=imagestreamtag mysql:latest mysql:tag4 --alias' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 7).from.kind}}'" 'ImageStreamTag' -# new-app different syntax for new-app functionality -os::cmd::expect_success 'oc new-project new-app-syntax' -os::cmd::expect_success 'oc import-image registry.centos.org/centos/ruby-27-centos7:latest --confirm' -os::cmd::expect_success 'oc import-image registry.centos.org/centos/php-70-centos7:latest --confirm' -os::cmd::expect_success 'oc new-app ruby-27-centos7:latest~https://github.com/openshift/ruby-hello-world.git --dry-run' -os::cmd::expect_success 'oc new-app ruby-27-centos7:latest~./test/testdata/testapp --dry-run' -os::cmd::expect_success 'oc new-app -i ruby-27-centos7:latest https://github.com/openshift/ruby-hello-world.git --dry-run' -os::cmd::expect_success 'oc new-app -i ruby-27-centos7:latest ./test/testdata/testapp --dry-run' -os::cmd::expect_success 'oc new-app ruby-27-centos7:latest --code https://github.com/openshift/ruby-hello-world.git --dry-run' -os::cmd::expect_success 'oc new-app ruby-27-centos7:latest --code ./test/testdata/testapp --dry-run' -os::cmd::expect_success 'oc new-app -i ruby-27-centos7:latest --code https://github.com/openshift/ruby-hello-world.git --dry-run' -os::cmd::expect_success 'oc new-app -i ruby-27-centos7:latest --code ./test/testdata/testapp --dry-run' +os::cmd::expect_success 'oc tag --source=istag mysql:latest mysql:tag5 --alias' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 8).from.kind}}'" 'ImageStreamTag' -os::cmd::expect_success 'oc new-app --code ./test/testdata/testapp --name test' -os::cmd::expect_success_and_text 'oc get bc test --template={{.spec.strategy.dockerStrategy.from.name}}' 'ruby-27-centos7:latest' +os::cmd::expect_success "oc tag --source=imagestreamimage mysql@${name} mysql:tag6 --alias" +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 9).from.kind}}'" 'ImageStreamImage' + +os::cmd::expect_success "oc tag --source=isimage mysql@${name} mysql:tag7 --alias" +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 10).from.kind}}'" 'ImageStreamImage' + +os::cmd::expect_success 'oc tag --source=docker mysql:latest mysql:tag8 --alias' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 11).from.kind}}'" 'DockerImage' -os::cmd::expect_success 'oc new-app -i php-55-centos7:latest --code ./test/testdata/testapp --name test2' -os::cmd::expect_success_and_text 'oc get bc test2 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-55-centos7:latest' +os::cmd::expect_success 'oc tag mysql:latest mysql:zzz mysql:yyy --alias' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 12).from.kind}}'" 'ImageStreamTag' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 13).from.kind}}'" 'ImageStreamTag' -os::cmd::expect_success 'oc new-app -i php-55-centos7:latest~https://github.com/openshift/ruby-hello-world.git --name test3' -os::cmd::expect_success_and_text 'oc get bc test3 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-55-centos7:latest' +os::cmd::expect_failure_and_text 'oc tag mysql:latest tagtest:tag1 --alias' 'cannot set alias across' -os::cmd::expect_success 'oc new-app php-55-centos7:latest~https://github.com/openshift/ruby-hello-world.git --name test4' -os::cmd::expect_success_and_text 'oc get bc test4 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-55-centos7:latest' +# label image +imgsha256=$(oc get istag/mysql:latest --template='{{ .image.metadata.name }}') +os::cmd::expect_success "oc label image ${imgsha256} foo=bar || true" +os::cmd::expect_success_and_text "oc get image ${imgsha256} --show-labels" 'foo=bar' -os::cmd::expect_success 'oc new-app -i php-55-centos7:latest https://github.com/openshift/ruby-hello-world.git --name test5' -os::cmd::expect_success_and_text 'oc get bc test5 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-55-centos7:latest' +# tag labeled image +os::cmd::expect_success 'oc label is/mysql labelA=value' +os::cmd::expect_success 'oc tag mysql:latest mysql:labeled' +os::cmd::expect_success_and_text "oc get istag/mysql:labeled -o jsonpath='{.metadata.labels.labelA}'" 'value' +# test copying tags +os::cmd::expect_success 'oc tag quay.io/openshift/origin-cli:4.6 newrepo:latest' +os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .spec.tags 0).from.kind}}'" 'DockerImage' +os::cmd::try_until_success 'oc get istag/mysql:5.6' +# default behavior is to copy the current image, but since this is an external image we preserve the dockerImageReference +os::cmd::expect_success 'oc tag mysql:5.6 newrepo:latest' +os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .spec.tags 0).from.kind}}'" 'ImageStreamImage' +os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .status.tags 0 \"items\" 0).dockerImageReference}}'" '^registry.centos.org/centos/mysql-56-centos7@sha256:' +# when copying a tag that points to the internal registry, update the container image reference +#os::cmd::expect_success "oc tag test:new newrepo:direct" +#os::cmd::expect_success_and_text 'oc get istag/newrepo:direct -o jsonpath={.image.dockerImageReference}' "/$project/newrepo@sha256:" +# test references +os::cmd::expect_success 'oc tag mysql:5.6 reference:latest --reference' +os::cmd::expect_success_and_text "oc get is/reference --template='{{(index .spec.tags 0).from.kind}}'" 'ImageStreamImage' +os::cmd::expect_success_and_text "oc get is/reference --template='{{(index .spec.tags 0).reference}}'" 'true' +# create a second project to test tagging across projects +os::cmd::expect_success 'oc new-project test-cmd-images-2' +os::cmd::expect_success "oc tag $project/mysql:5.6 newrepo:latest" +os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .spec.tags 0).from.kind}}'" 'ImageStreamImage' +os::cmd::expect_success_and_text 'oc get istag/newrepo:latest -o jsonpath={.image.dockerImageReference}' 'registry.centos.org/centos/mysql-56-centos7@sha256:' +# tag across projects without specifying the source's project +os::cmd::expect_success_and_text "oc tag newrepo:latest '${project}/mysql:tag1'" "mysql:tag1 set to" +os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .spec.tags 0).name}}'" "latest" +# tagging an image with a DockerImageReference that points to the internal registry across namespaces updates the reference +#os::cmd::expect_success "oc tag $project/test:new newrepo:direct" +# reference should point to the current repository, and that repository should match the reported dockerImageRepository for pushes +# can't check status since there is no registry running so internalRegistryHostname isn't populated. +#repository="$( oc get is/newrepo -o jsonpath='{.status.dockerImageRepository}' )" +#os::cmd::expect_success_and_text 'oc get istag/newrepo:direct -o jsonpath={.image.dockerImageReference}' "^$repository@sha256:" +#os::cmd::expect_success_and_text 'oc get istag/newrepo:direct -o jsonpath={.image.dockerImageReference}' '/test-cmd-images-2/newrepo@sha256:' +# tagging an image using --reference does not +#os::cmd::expect_success "oc tag $project/test:new newrepo:indirect --reference" +#os::cmd::expect_success_and_text 'oc get istag/newrepo:indirect -o jsonpath={.image.dockerImageReference}' "/$project/test@sha256:" +os::cmd::expect_success "oc project $project" +# test scheduled and insecure tagging +os::cmd::expect_success 'oc tag --source=docker mysql:5.7 newrepo:latest --scheduled' +os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .spec.tags 0).importPolicy.scheduled}}'" 'true' +os::cmd::expect_success_and_text "oc describe is/newrepo" 'updates automatically from registry mysql:5.7' +os::cmd::expect_success 'oc tag --source=docker mysql:5.7 newrepo:latest --insecure' +os::cmd::expect_success_and_text "oc describe is/newrepo" 'will use insecure HTTPS or HTTP connections' +os::cmd::expect_success_and_not_text "oc describe is/newrepo" 'updates automatically from' +os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .spec.tags 0).importPolicy.insecure}}'" 'true' -os::cmd::expect_success 'oc new-app php-55-centos7:latest --code https://github.com/openshift/ruby-hello-world.git --name test6' -os::cmd::expect_success_and_text 'oc get bc test6 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-55-centos7:latest' +# test creating streams that don't exist +os::cmd::expect_failure_and_text 'oc get imageStreams tagtest1' 'not found' +os::cmd::expect_failure_and_text 'oc get imageStreams tagtest2' 'not found' +os::cmd::expect_success 'oc tag mysql:latest tagtest1:latest tagtest2:latest' +os::cmd::expect_success_and_text "oc get is/tagtest1 --template='{{(index .spec.tags 0).from.kind}}'" 'ImageStreamImage' +os::cmd::expect_success_and_text "oc get is/tagtest2 --template='{{(index .spec.tags 0).from.kind}}'" 'ImageStreamImage' +os::cmd::expect_success 'oc delete is/tagtest1 is/tagtest2' +os::cmd::expect_success_and_text 'oc tag mysql:latest tagtest:new1' 'Tag tagtest:new1 set to mysql@sha256:' -os::cmd::expect_success 'oc new-app https://github.com/openshift/ruby-hello-world.git --name test7' -os::cmd::expect_success_and_text 'oc get bc test7 --template={{.spec.strategy.dockerStrategy.from.name}}' 'ruby-27-centos7:latest' +# test deleting a spec tag using oc tag +os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-stream.yaml' +os::cmd::expect_success_and_text 'oc tag test-stream:latest -d' 'Deleted' +os::cmd::expect_success 'oc delete is/test-stream' +echo "tag: ok" +os::test::junit::declare_suite_end -os::cmd::expect_success 'oc new-app php-55-centos7:latest https://github.com/openshift/ruby-hello-world.git --name test8' -os::cmd::expect_success_and_text 'oc get bc test8 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-55-centos7:latest' -os::cmd::expect_success 'oc delete project new-app-syntax' +os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/delete-istag" +# test deleting a tag using oc delete +os::cmd::expect_success_and_text "oc get is perl --template '{{(index .spec.tags 0).name}}'" '5.24' +os::cmd::expect_success_and_text "oc get is perl --template '{{(index .status.tags 0).tag}}'" '5.24' +os::cmd::expect_success_and_text "oc describe is perl | sed -n -e '0,/^Tags:/d' -e '/^\s\+/d' -e '/./p' | head -n 1" 'latest' +os::cmd::expect_success "oc delete istag/perl:5.24 --context='${cluster_admin_context}'" +os::cmd::expect_success_and_not_text 'oc get is/perl --template={{.spec.tags}}' 'version:5.24' +os::cmd::expect_success_and_not_text 'oc get is/perl --template={{.status.tags}}' 'version:5.24' +os::cmd::expect_success 'oc delete all --all' -# new-app docker build strategy with binary input -os::cmd::expect_success 'oc project ${default_project}' -os::cmd::expect_success 'oc delete all,templates --all' -os::cmd::expect_success 'oc create -f examples/image-streams/image-streams-centos7.json' -os::cmd::try_until_success 'oc get imagestreamtags ruby:latest' # need to wait until tags are available!? -os::cmd::expect_failure_and_text 'oc new-app --strategy=docker --name my-docker-app' 'none of the arguments provided could be classified as a source code location' -os::cmd::expect_success_and_text 'oc new-app --strategy=docker --binary --name my-docker-app' 'A binary build was created' -os::cmd::expect_success_and_text 'oc get bc my-docker-app -o yaml' 'type: Binary' -os::cmd::expect_success 'oc delete all -l app=my-docker-app' +echo "delete istag: ok" +os::test::junit::declare_suite_end -# new-app source build strategy with binary input -os::cmd::expect_success_and_text 'oc new-app ruby --binary --name my-imagestream-app' 'A binary build was created' -os::cmd::expect_success_and_text 'oc get bc my-imagestream-app -o yaml' 'type: Binary' -os::cmd::expect_success 'oc delete all -l app=my-imagestream-app' +os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/merge-tags-on-apply" +os::cmd::expect_success 'oc new-project merge-tags' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/image-streams/image-streams-centos7.json' +os::cmd::expect_success_and_text 'oc get is ruby -o jsonpath={.spec.tags[*].name}' '2.7-ubi8 latest' +os::cmd::expect_success 'oc apply -f ${TEST_DATA}/modified-ruby-imagestream.json' +os::cmd::expect_success_and_text 'oc get is ruby -o jsonpath={.spec.tags[*].name}' '2.7-ubi8 latest newtag' +os::cmd::expect_success_and_text 'oc get is ruby -o jsonpath={.spec.tags[0].annotations.version}' '2.7 patched' +os::cmd::expect_success 'oc delete project merge-tags' +echo "apply new imagestream tags: ok" +os::test::junit::declare_suite_end -# new-app with source repository and binary input -os::cmd::expect_failure_and_text 'oc new-app ./test/testdata/testapp --binary' 'error: specifying binary builds and source repositories at the same time is not allowed' +# test importing images with wrong docker secrets +os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/import-public-images-with-fake-secret" +os::cmd::expect_success 'oc new-project import-images' +os::cmd::expect_success 'oc create secret docker-registry dummy-secret1 --docker-server=docker.io --docker-username=dummy1 --docker-password=dummy1 --docker-email==dummy1@example.com' +os::cmd::expect_success 'oc create secret docker-registry dummy-secret2 --docker-server=docker.io --docker-username=dummy2 --docker-password=dummy2 --docker-email==dummy2@example.com' +os::cmd::expect_success_and_text 'oc import-image example --from=openshift/hello-openshift --confirm' 'imagestream.image.openshift.io/example imported' +os::cmd::expect_success 'oc delete project import-images' +echo "import public images with fake secret ok" +os::test::junit::declare_suite_end -echo "new-app: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdNewappShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdNewappSh, nil +func testExtendedTestdataCmdTestCmdImagesShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdImagesSh, nil } -func testExtendedTestdataCmdTestCmdNewappSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdNewappShBytes() +func testExtendedTestdataCmdTestCmdImagesSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdImagesShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/newapp.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/images.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdObserveSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" +var _testExtendedTestdataCmdTestCmdLoginSh = []byte(`#!/bin/bash + +set -o errexit +set -o nounset +set -o pipefail + +OS_ROOT=$(dirname "${BASH_SOURCE}")/../.. +source "${OS_ROOT}/hack/lib/init.sh" +os::log::stacktrace::install trap os::test::junit::reconcile_output EXIT # Cleanup cluster resources created by this test ( set +e + oc delete project project-foo exit 0 ) &>/dev/null -os::test::junit::declare_suite_start "cmd/observe" - -# basic scenarios -os::cmd::expect_failure_and_text 'oc observe' 'you must specify at least one argument containing the resource to observe' -os::cmd::expect_success_and_text 'oc observe serviceaccounts --once' 'Sync ended' -os::cmd::expect_success_and_text 'oc observe daemonsets --once' 'Nothing to sync, exiting immediately' -os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces' 'default kubernetes' -os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces --print-metrics-on-exit' 'observe_counts{type="Sync"}' -os::cmd::expect_failure_and_text 'oc observe services --once --names echo' '\-\-delete and \-\-names must both be specified' -os::cmd::expect_success_and_text 'oc observe services --exit-after=1s' 'Shutting down after 1s ...' -os::cmd::expect_success_and_text 'oc observe services --exit-after=1s --all-namespaces --print-metrics-on-exit' 'observe_counts{type="Sync"}' -os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces' 'default kubernetes' -os::cmd::expect_success_and_text 'oc observe services --once --exit-after=3s --all-namespaces --names echo --names default/notfound --delete echo --delete remove' 'remove default notfound' - -# error counting -os::cmd::expect_failure_and_text 'oc observe services --exit-after=1m --all-namespaces --maximum-errors=1 -- /bin/sh -c "exit 1"' 'reached maximum error limit of 1, exiting' -os::cmd::expect_failure_and_text 'oc observe services --exit-after=1m --all-namespaces --retry-on-exit-code=2 --maximum-errors=1 --loglevel=4 -- /bin/sh -c "exit 2"' 'retrying command: exit status 2' - -# argument templates -os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces -a "{ .spec.clusterIP }"' '172.30.0.1' -os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces -a "{{ .spec.clusterIP }}" --output=gotemplate' '172.30.0.1' -os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces -a "bad{ .missingkey }key"' 'badkey' -os::cmd::expect_failure_and_text 'oc observe services --once --all-namespaces -a "bad{ .missingkey }key" --strict-templates' 'missingkey is not found' -os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces -a "{{ .unknown }}" --output=gotemplate' '""' -os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces -a "bad{{ or (.unknown) \"\" }}key" --output=gotemplate' 'badkey' -# TODO: bring back when oc#472 merges -# os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces -a "bad{{ .unknown }}key" --output=gotemplate --strict-templates' 'map has no entry for key' - -# --type-env-var -os::cmd::expect_success_and_text 'MYENV=should_be_passed oc observe services --once --all-namespaces --type-env-var=EVENT -- /bin/sh -c "echo \$EVENT \$MYENV"' 'Sync should_be_passed' - -echo "observe: ok" -os::test::junit::declare_suite_end -`) +os::test::junit::declare_suite_start "cmd/login" +# This test validates login functionality for the client +# we want this test to run without $KUBECONFIG or $KUBERNETES_MASTER as it tests that functionality +# ` + "`" + `oc` + "`" + ` will use in-cluster config if KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT +# are set, as well as /var/run/secrets/kubernetes.io/serviceaccount/token exists. we +# therefore can be sure that we are picking up no client configuration if we unset these variables +login_kubeconfig="${ARTIFACT_DIR}/login.kubeconfig" +CA_CERT=${MASTER_CONFIG_DIR}/server-ca.crt +cp "${KUBECONFIG}" "${login_kubeconfig}" +unset KUBECONFIG +unset KUBERNETES_MASTER +# test client not configured +os::cmd::expect_failure_and_text "env -u KUBERNETES_SERVICE_HOST oc get services" 'Missing or incomplete configuration info. Please login' +unused_port="33333" +# setting env bypasses the not configured message +os::cmd::expect_failure_and_text "env -u KUBERNETES_SERVICE_HOST KUBERNETES_MASTER=http://${API_HOST}:${unused_port} oc get services" 'did you specify the right host or port' +# setting --server bypasses the not configured message +os::cmd::expect_failure_and_text "env -u KUBERNETES_SERVICE_HOST oc get services --server=http://${API_HOST}:${unused_port}" 'did you specify the right host or port' -func testExtendedTestdataCmdTestCmdObserveShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdObserveSh, nil -} +# Set KUBERNETES_MASTER for oc from now on +export KUBERNETES_MASTER="${API_SCHEME}://${API_HOST}:${API_PORT}" -func testExtendedTestdataCmdTestCmdObserveSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdObserveShBytes() - if err != nil { - return nil, err - } +# Set certificates for oc from now on +if [[ "${API_SCHEME}" == "https" ]]; then + # test bad certificate + os::cmd::expect_failure_and_text "env -u KUBERNETES_SERVICE_HOST oc get services" 'certificate signed by unknown authority' +fi - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/observe.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +# remove self-provisioner role from user and test login prompt before creating any projects +os::cmd::expect_success "oc adm policy remove-cluster-role-from-group self-provisioner system:authenticated:oauth --kubeconfig='${login_kubeconfig}'" +os::cmd::expect_success_and_text "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${CA_CERT}' -u no-project-test-user -p anything" "You don't have any projects. Contact your system administrator to request a project" +# make sure standard login prompt is printed once self-provisioner status is restored +os::cmd::expect_success "oc adm policy add-cluster-role-to-group self-provisioner system:authenticated:oauth --kubeconfig='${login_kubeconfig}'" +os::cmd::try_until_text "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${CA_CERT}' -u no-project-test-user -p anything" "You don't have any projects. You can try to create a new project, by running" $(( 30 * second )) 0.25 +# make sure ` + "`" + `oc login` + "`" + ` fails with unauthorized error +os::cmd::expect_failure_and_text 'oc login <<< \n' 'Login failed \(401 Unauthorized\)' +os::cmd::expect_success 'oc logout' +echo "login and status messages: ok" -var _testExtendedTestdataCmdTestCmdPolicyStorageAdminSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT +# login and logout tests +# bad token should error +os::cmd::expect_failure_and_text "oc login ${KUBERNETES_MASTER} --certificate-authority='${CA_CERT}' --token=badvalue" 'The token provided is invalid or expired' +# --token and --username are mutually exclusive +os::cmd::expect_failure_and_text "oc login ${KUBERNETES_MASTER} -u test-user --token=tmp --insecure-skip-tls-verify" 'mutually exclusive' +# must only accept one arg (server) +os::cmd::expect_failure_and_text "oc login https://server1 https://server2.com" 'Only the server URL may be specified' +# logs in with a valid certificate authority +os::cmd::expect_success "oc login ${KUBERNETES_MASTER} --certificate-authority='${CA_CERT}' -u test-user -p anything" +os::cmd::expect_success_and_text "cat ${HOME}/.kube/config" "v1" +os::cmd::expect_success 'oc logout' +# logs in skipping certificate check +os::cmd::expect_success "oc login ${KUBERNETES_MASTER} --insecure-skip-tls-verify -u test-user -p anything" +# logs in by an existing and valid token +temp_token="$(oc whoami -t)" +os::cmd::expect_success_and_text "oc login --token=${temp_token}" 'using the token provided' +os::cmd::expect_success 'oc logout' +# properly parse server port +os::cmd::expect_failure_and_text 'oc login https://server1:844333' 'Not a valid port' +# properly handle trailing slash +os::cmd::expect_success "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${CA_CERT}' -u test-user -p anything" +# create a new project +os::cmd::expect_success "oc new-project project-foo --display-name='my project' --description='boring project description'" +os::cmd::expect_success_and_text "oc project" 'Using project "project-foo"' +# new user should get default context +os::cmd::expect_success "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${CA_CERT}' -u new-and-unknown-user -p anything" +os::cmd::expect_success_and_text 'oc config view' "current-context.+/${API_HOST}:${API_PORT}/new-and-unknown-user" +# denies access after logging out +os::cmd::expect_success 'oc logout' +os::cmd::expect_failure_and_text 'oc get pods' '"system:anonymous" cannot list resource "pods" in API group ""' -project="$( oc project -q )" +# make sure we report an error if the config file we pass is not writable +# Does not work inside of a container, determine why and reenable +# os::cmd::expect_failure_and_text "oc login '${KUBERNETES_MASTER}' -u test -p test '--kubeconfig=${templocation}/file' --insecure-skip-tls-verify" 'KUBECONFIG is set to a file that cannot be created or modified' +echo "login warnings: ok" -os::test::junit::declare_suite_start "cmd/policy-storage-admin" - -# Test storage-admin role and impersonation -os::cmd::expect_success 'oc adm policy add-cluster-role-to-user storage-admin storage-adm' -os::cmd::expect_success 'oc adm policy add-cluster-role-to-user storage-admin storage-adm2' -os::cmd::expect_success 'oc adm policy add-role-to-user admin storage-adm2' -os::cmd::expect_success_and_text 'oc policy who-can impersonate storage-admin' 'cluster-admin' - -# Test storage-admin role as user level -#os::cmd::expect_success 'oc login -u storage-adm -p pw' -#os::cmd::expect_success_and_text 'oc whoami' "storage-adm" -#os::cmd::expect_failure 'oc whoami --as=basic-user' -#os::cmd::expect_failure 'oc whoami --as=cluster-admin' - -# Test storage-admin can not do normal project scoped tasks -os::cmd::expect_failure_and_text 'oc auth can-i --as=storage-adm create pods --all-namespaces' 'no' -os::cmd::expect_failure_and_text 'oc auth can-i --as=storage-adm create projects' 'no' -os::cmd::expect_failure_and_text 'oc auth can-i --as=storage-adm create pvc' 'no' - -# Test storage-admin can read pvc and pods, and create pv and storageclass -os::cmd::expect_success_and_text 'oc auth can-i --as=storage-adm get pvc --all-namespaces' 'yes' -os::cmd::expect_success_and_text 'oc auth can-i --as=storage-adm get storageclass' 'yes' -os::cmd::expect_success_and_text 'oc auth can-i --as=storage-adm create pv' 'yes' -os::cmd::expect_success_and_text 'oc auth can-i --as=storage-adm create storageclass' 'yes' -os::cmd::expect_success_and_text 'oc auth can-i --as=storage-adm get pods --all-namespaces' 'yes' - -# Test failure to change policy on users for storage-admin -os::cmd::expect_failure_and_text 'oc policy --as=storage-adm add-role-to-user admin storage-adm' ' cannot list resource "rolebindings" in API group "rbac.authorization.k8s.io"' -os::cmd::expect_failure_and_text 'oc policy --as=storage-adm remove-user screeley' ' cannot list resource "rolebindings" in API group "rbac.authorization.k8s.io"' -#os::cmd::expect_success 'oc logout' +# login and create serviceaccount and test login and logout with a service account token +os::cmd::expect_success "oc login ${KUBERNETES_MASTER} --certificate-authority='${CA_CERT}' -u test-user -p anything" +os::cmd::expect_success_and_text "oc create sa testserviceaccount" "serviceaccount/testserviceaccount created" +os::cmd::try_until_success "oc sa get-token testserviceaccount" +os::cmd::expect_success_and_text "oc login --token=$(oc sa get-token testserviceaccount)" "system:serviceaccount:project-foo:testserviceaccount" +# attempt to logout successfully +os::cmd::expect_success_and_text "oc logout" "Logged \"system:serviceaccount:project-foo:testserviceaccount\" out" +# verify that the token is no longer present in our local config +os::cmd::expect_failure_and_text "oc whoami" 'User "system:anonymous" cannot get resource "users" in API group "user.openshift.io"' + +# log in and set project to use from now on +os::cmd::expect_success "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${CA_CERT}' -u test-user -p anything" +os::cmd::expect_success 'oc get projects' +os::cmd::expect_success 'oc project project-foo' +os::cmd::expect_success_and_text 'oc config view' "current-context.+project-foo/${API_HOST}:${API_PORT}/test-user" +os::cmd::expect_success_and_text 'oc whoami' 'test-user' +os::cmd::expect_success_and_text "oc whoami --kubeconfig='${login_kubeconfig}'" 'system:admin' +os::cmd::expect_success_and_text 'oc whoami -t' '.' +os::cmd::expect_success_and_text 'oc whoami -c' '.' -# Test that scoped storage-admin now an admin in project foo -#os::cmd::expect_success 'oc login -u storage-adm2 -p pw' -#os::cmd::expect_success_and_text 'oc whoami' "storage-adm2" -os::cmd::expect_success 'oc new-project --as=storage-adm2 --as-group=system:authenticated:oauth --as-group=system:authenticated policy-can-i' -os::cmd::expect_failure_and_text 'oc auth can-i --as=storage-adm2 create pod --all-namespaces' 'no' -os::cmd::expect_success_and_text 'oc auth can-i --as=storage-adm2 create pod' 'yes' -os::cmd::expect_success_and_text 'oc auth can-i --as=storage-adm2 create pvc' 'yes' -os::cmd::expect_success_and_text 'oc auth can-i --as=storage-adm2 create endpoints' 'yes' -os::cmd::expect_success 'oc delete project policy-can-i' +# test config files from the --kubeconfig flag +os::cmd::expect_success "oc get services --kubeconfig='${login_kubeconfig}'" +# test config files from env vars +os::cmd::expect_success "KUBECONFIG='${login_kubeconfig}' oc get services" +os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdPolicyStorageAdminShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdPolicyStorageAdminSh, nil +func testExtendedTestdataCmdTestCmdLoginShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdLoginSh, nil } -func testExtendedTestdataCmdTestCmdPolicyStorageAdminSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdPolicyStorageAdminShBytes() +func testExtendedTestdataCmdTestCmdLoginSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdLoginShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/policy-storage-admin.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/login.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdPolicySh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdMigrateSh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT -project="$( oc project -q )" -testpod="apiVersion: v1 -kind: Pod -metadata: - name: testpod -spec: - containers: - - image: node - imagePullPolicy: IfNotPresent - name: testpod - volumes: - - emptyDir: {} - name: tmp" - -os::test::junit::declare_suite_start "cmd/policy" -# This test validates user level policy -os::cmd::expect_success_and_text 'oc whoami --as deads' "deads" - -os::cmd::expect_success 'oc adm policy add-cluster-role-to-user sudoer wheel' -os::cmd::try_until_text 'oc policy who-can impersonate users system:admin' "wheel" -os::cmd::try_until_text 'oc policy who-can impersonate groups system:masters' "wheel" -os::cmd::try_until_text 'oc policy who-can impersonate systemusers system:admin' "wheel" -os::cmd::try_until_text 'oc policy who-can impersonate systemgroups system:masters' "wheel" -os::cmd::expect_success 'oc login -u wheel -p pw' -os::cmd::expect_success_and_text 'oc whoami' "wheel" -os::cmd::expect_failure 'oc whoami --as deads' -os::cmd::expect_success_and_text 'oc whoami --as=system:admin' "system:admin" -os::cmd::expect_success_and_text 'oc auth can-i --list --as=system:admin' '.*' - -os::cmd::expect_success 'oc login -u local-admin -p pw' -os::cmd::expect_success 'oc new-project policy-login' -os::cmd::expect_failure 'oc whoami --as=system:admin' -os::cmd::expect_success_and_text 'oc whoami --as=system:serviceaccount:policy-login:default' "system:serviceaccount:policy-login:default" -os::cmd::expect_failure 'oc whoami --as=system:serviceaccount:another:default' -os::cmd::expect_success "oc login -u system:admin -n '${project}'" -os::cmd::expect_success 'oc delete project policy-login' - -# validate --serviceaccount values -os::cmd::expect_success_and_text 'oc policy add-role-to-user admin -z default' 'clusterrole.rbac.authorization.k8s.io/admin added: "default"' -os::cmd::expect_failure_and_text 'oc policy add-role-to-user admin -z system:serviceaccount:test:default' 'should only be used with short\-form serviceaccount names' -os::cmd::expect_failure_and_text 'oc policy add-role-to-user admin -z :invalid' '"\:invalid" is not a valid serviceaccount name' - -# This test validates user level policy -os::cmd::expect_failure_and_text 'oc policy add-role-to-user' 'you must specify a role' -os::cmd::expect_failure_and_text 'oc policy add-role-to-user -z NamespaceWithoutRole' 'you must specify a role' -os::cmd::expect_failure_and_text 'oc policy add-role-to-user view' 'you must specify at least one user or service account' - -os::cmd::expect_success_and_text 'oc policy add-role-to-group cluster-admin --rolebinding-name cluster-admin system:unauthenticated' 'clusterrole.rbac.authorization.k8s.io/cluster-admin added: "system:unauthenticated"' -os::cmd::expect_success_and_text 'oc policy add-role-to-user --rolebinding-name cluster-admin cluster-admin system:no-user' 'clusterrole.rbac.authorization.k8s.io/cluster-admin added: "system:no-user"' -os::cmd::expect_success 'oc get rolebinding/cluster-admin --no-headers' -os::cmd::expect_success_and_text 'oc get rolebinding/cluster-admin --no-headers' 'system:no-user' - -os::cmd::expect_success_and_text 'oc policy add-role-to-user --rolebinding-name cluster-admin cluster-admin -z=one,two --serviceaccount=three,four' 'clusterrole.rbac.authorization.k8s.io/cluster-admin added: \["one" "two" "three" "four"\]' -os::cmd::expect_success 'oc get rolebinding/cluster-admin --no-headers' -os::cmd::expect_success_and_text 'oc get rolebinding/cluster-admin --no-headers' 'one' -os::cmd::expect_success_and_text 'oc get rolebinding/cluster-admin --no-headers' 'four' - -os::cmd::expect_success_and_text 'oc policy remove-role-from-group --rolebinding-name cluster-admin cluster-admin system:unauthenticated' 'clusterrole.rbac.authorization.k8s.io/cluster-admin removed: "system:unauthenticated"' - -os::cmd::expect_success_and_text 'oc policy remove-role-from-user --rolebinding-name cluster-admin cluster-admin system:no-user' 'clusterrole.rbac.authorization.k8s.io/cluster-admin removed: "system:no-user"' -os::cmd::expect_success_and_text 'oc policy remove-role-from-user --rolebinding-name cluster-admin cluster-admin -z=one,two --serviceaccount=three,four' 'clusterrole.rbac.authorization.k8s.io/cluster-admin removed: \["one" "two" "three" "four"\]' -os::cmd::expect_failure_and_text 'oc get rolebinding/cluster-admin --no-headers' 'NotFound' - -os::cmd::expect_success 'oc policy remove-group system:unauthenticated' -os::cmd::expect_success 'oc policy remove-user system:no-user' - -# Test failure to mix and mismatch role/rolebiding removal -os::cmd::expect_success 'oc login -u local-admin -p pw' -os::cmd::expect_success 'oc new-project mismatch-prj' -os::cmd::expect_success 'oc create rolebinding match --clusterrole=admin --user=user' -os::cmd::expect_success 'oc create rolebinding mismatch --clusterrole=edit --user=user' -os::cmd::expect_failure_and_text 'oc policy remove-role-from-user admin user --rolebinding-name mismatch' 'rolebinding mismatch' -os::cmd::expect_success_and_text 'oc policy remove-user user' 'user' -os::cmd::expect_failure_and_text 'oc get rolebinding mismatch --no-headers' 'NotFound' -os::cmd::expect_failure_and_text 'oc get rolebinding match --no-headers' 'NotFound' -os::cmd::expect_success "oc login -u system:admin -n '${project}'" -os::cmd::expect_success 'oc delete project mismatch-prj' - -# check to make sure that our SCC policies don't prevent GC from deleting pods -os::cmd::expect_success 'oc create -f ${OS_ROOT}/test/testdata/privileged-pod.yaml' -os::cmd::expect_success 'oc delete pod/test-build-pod-issue --cascade=false' -os::cmd::try_until_failure 'oc get pods pod/test-build-pod-issue' - - -os::cmd::expect_success_and_text 'oc policy add-role-to-user admin namespaced-user' 'clusterrole.rbac.authorization.k8s.io/admin added: "namespaced-user"' -# Ensure the user has create permissions on builds, but that build strategy permissions are granted through the authenticated users group -os::cmd::try_until_text 'oc adm policy who-can create builds' 'namespaced-user' -os::cmd::expect_success_and_not_text 'oc adm policy who-can create builds/docker' 'namespaced-user' -os::cmd::expect_success_and_not_text 'oc adm policy who-can create builds/custom' 'namespaced-user' -os::cmd::expect_success_and_not_text 'oc adm policy who-can create builds/source' 'namespaced-user' -os::cmd::expect_success_and_not_text 'oc adm policy who-can create builds/jenkinspipeline' 'namespaced-user' -os::cmd::expect_success_and_text 'oc adm policy who-can create builds/docker' 'system:authenticated' -os::cmd::expect_success_and_text 'oc adm policy who-can create builds/source' 'system:authenticated' -os::cmd::expect_success_and_text 'oc adm policy who-can create builds/jenkinspipeline' 'system:authenticated' -# if this method for removing access to docker/custom/source/jenkinspipeline builds changes, docs need to be updated as well -os::cmd::expect_success_and_text 'oc adm policy remove-cluster-role-from-group system:build-strategy-docker system:authenticated' 'clusterrole.rbac.authorization.k8s.io/system:build-strategy-docker removed: "system:authenticated"' -os::cmd::expect_success_and_text 'oc adm policy remove-cluster-role-from-group system:build-strategy-source system:authenticated' 'clusterrole.rbac.authorization.k8s.io/system:build-strategy-source removed: "system:authenticated"' -os::cmd::expect_success_and_text 'oc adm policy remove-cluster-role-from-group system:build-strategy-jenkinspipeline system:authenticated' 'clusterrole.rbac.authorization.k8s.io/system:build-strategy-jenkinspipeline removed: "system:authenticated"' - -# ensure build strategy permissions no longer exist -os::cmd::try_until_failure 'oc adm policy who-can create builds/source | grep system:authenticated' -os::cmd::expect_success_and_not_text 'oc adm policy who-can create builds/docker' 'system:authenticated' -os::cmd::expect_success_and_not_text 'oc adm policy who-can create builds/source' 'system:authenticated' -os::cmd::expect_success_and_not_text 'oc adm policy who-can create builds/jenkinspipeline' 'system:authenticated' - -# validate --output and --dry-run flags for oc-adm-policy sub-commands -os::cmd::expect_success_and_text 'oc adm policy remove-role-from-user admin namespaced-user -o yaml' 'name: admin' -os::cmd::expect_success_and_text 'oc adm policy add-role-to-user admin namespaced-user -o yaml' 'name: namespaced-user' - -os::cmd::expect_success_and_text 'oc adm policy remove-role-from-user admin namespaced-user --dry-run' 'clusterrole.rbac.authorization.k8s.io/admin removed: "namespaced-user" \(dry run\)' -os::cmd::expect_success_and_text 'oc adm policy add-role-to-user admin namespaced-user --dry-run' 'clusterrole.rbac.authorization.k8s.io/admin added: "namespaced-user" \(dry run\)' - -# ensure that running an ` + "`" + `oc adm policy` + "`" + ` sub-command with --output does not actually perform any changes -os::cmd::expect_success_and_text 'oc adm policy who-can create pods -o yaml' '\- namespaced\-user' - -os::cmd::expect_success_and_text 'oc adm policy scc-subject-review -u namespaced-user --output yaml -f - << __EOF__ -$testpod -__EOF__' 'name: testpod' -os::cmd::expect_success_and_text 'oc adm policy scc-subject-review -u namespaced-user --output wide -f - << __EOF__ -$testpod -__EOF__' 'Pod/testpod' - -os::cmd::expect_success_and_text 'oc adm policy scc-review --output yaml -f - << __EOF__ -$testpod -__EOF__' 'allowedServiceAccounts: null' - -os::cmd::expect_success_and_text 'oc adm policy add-role-to-group view testgroup -o yaml' 'name: view' -os::cmd::expect_success_and_text 'oc adm policy add-cluster-role-to-group cluster-reader testgroup -o yaml' 'name: testgroup' -os::cmd::expect_success_and_text 'oc adm policy add-cluster-role-to-user cluster-reader namespaced-user -o yaml' 'name: namespaced\-user' - -os::cmd::expect_success_and_text 'oc adm policy add-role-to-group view testgroup --dry-run' 'rolebinding.rbac.authorization.k8s.io/view added: "testgroup" \(dry run\)' -os::cmd::expect_success_and_text 'oc adm policy add-cluster-role-to-group cluster-reader testgroup --dry-run' 'clusterrolebinding.rbac.authorization.k8s.io/cluster-reader added: "testgroup" \(dry run\)' -os::cmd::expect_success_and_text 'oc adm policy add-cluster-role-to-user cluster-reader namespaced-user --dry-run' 'clusterrolebinding.rbac.authorization.k8s.io/cluster-reader added: "namespaced-user" \(dry run\)' - -os::cmd::expect_success 'oc adm policy add-role-to-group view testgroup' -os::cmd::expect_success 'oc adm policy add-cluster-role-to-group cluster-reader testgroup' -os::cmd::expect_success 'oc adm policy add-cluster-role-to-user cluster-reader namespaced-user' - -# ensure that removing missing target causes error. -os::cmd::expect_failure_and_text 'oc adm policy remove-cluster-role-from-user admin ghost' 'error: unable to find target \[ghost\]' -os::cmd::expect_failure_and_text 'oc adm policy remove-cluster-role-from-user admin -z ghost' 'error: unable to find target \[ghost\]' - -os::cmd::expect_success_and_not_text 'oc adm policy remove-role-from-group view testgroup -o yaml' 'subjects: ' -os::cmd::expect_success_and_text 'oc adm policy remove-cluster-role-from-group cluster-reader testgroup -o yaml' 'name: cluster\-readers' -os::cmd::expect_success_and_text 'oc adm policy remove-cluster-role-from-user cluster-reader namespaced-user -o yaml' 'name: cluster\-reader' - -os::cmd::expect_success_and_text 'oc adm policy remove-role-from-group view testgroup --dry-run' 'clusterrole.rbac.authorization.k8s.io/view removed: "testgroup" \(dry run\)' -os::cmd::expect_success_and_text 'oc adm policy remove-cluster-role-from-group cluster-reader testgroup --dry-run' 'clusterrole.rbac.authorization.k8s.io/cluster-reader removed: "testgroup" \(dry run\)' -os::cmd::expect_success_and_text 'oc adm policy remove-cluster-role-from-user cluster-reader namespaced-user --dry-run' 'clusterrole.rbac.authorization.k8s.io/cluster-reader removed: "namespaced-user" \(dry run\)' - -os::cmd::expect_success_and_text 'oc adm policy remove-user namespaced-user -o yaml' "namespace: ${project}" -os::cmd::expect_success_and_text 'oc adm policy remove-user namespaced-user --dry-run' "Removing admin from users \[namespaced\-user\] in project ${project}" - -os::cmd::expect_success_and_text 'oc adm policy add-scc-to-user anyuid namespaced-user -o yaml' '\- namespaced\-user' -os::cmd::expect_success_and_text 'oc adm policy add-scc-to-user anyuid namespaced-user --dry-run' 'securitycontextconstraints.security.openshift.io/anyuid added to: \["namespaced\-user"\] \(dry run\)' - -os::cmd::expect_success_and_text 'oc adm policy add-scc-to-group anyuid testgroup -o yaml' '\- testgroup' -os::cmd::expect_success_and_text 'oc adm policy add-scc-to-group anyuid testgroup --dry-run' 'securitycontextconstraints.security.openshift.io/anyuid added to groups: \["testgroup"\] \(dry run\)' - -os::cmd::expect_success_and_not_text 'oc adm policy remove-scc-from-user anyuid namespaced-user -o yaml' '\- namespaced\-user' -os::cmd::expect_success_and_text 'oc adm policy remove-scc-from-user anyuid namespaced-user --dry-run' 'securitycontextconstraints.security.openshift.io/anyuid removed from: \["namespaced\-user"\] \(dry run\)' - -os::cmd::expect_success_and_not_text 'oc adm policy remove-scc-from-group anyuid testgroup -o yaml' '\- testgroup' -os::cmd::expect_success_and_text 'oc adm policy remove-scc-from-group anyuid testgroup --dry-run' 'securitycontextconstraints.security.openshift.io/anyuid removed from groups: \["testgroup"\] \(dry run\)' - -# ensure system:authenticated users can not create custom builds by default, but can if explicitly granted access -os::cmd::expect_success_and_not_text 'oc adm policy who-can create builds/custom' 'system:authenticated' -os::cmd::expect_success_and_text 'oc adm policy add-cluster-role-to-group system:build-strategy-custom system:authenticated' 'clusterrole.rbac.authorization.k8s.io/system:build-strategy-custom added: "system:authenticated"' -os::cmd::expect_success_and_text 'oc adm policy who-can create builds/custom' 'system:authenticated' - -os::cmd::expect_success 'oc auth reconcile --remove-extra-permissions --remove-extra-subjects -f "${BASE_RBAC_DATA}"' - -os::cmd::try_until_text 'oc auth can-i --list' 'get update.*imagestreams/layers' -os::cmd::try_until_text 'oc auth can-i create pods --all-namespaces' 'yes' -os::cmd::try_until_text 'oc auth can-i create pods' 'yes' -os::cmd::try_until_text 'oc auth can-i create pods --as harold' 'no' -os::cmd::expect_failure 'oc auth can-i create pods --as harold --user harold' -os::cmd::expect_failure 'oc auth can-i --list --as harold --user harold' -os::cmd::expect_failure 'oc auth can-i create pods --as harold -q' - -os::cmd::expect_success_and_text 'oc auth can-i create pods --user system:admin' 'yes' -os::cmd::expect_success_and_text 'oc auth can-i create pods --groups system:unauthenticated --groups system:masters' 'yes' -os::cmd::expect_success_and_text 'oc auth can-i create pods --groups system:unauthenticated' 'no' -os::cmd::expect_success_and_text 'oc auth can-i create pods --user harold' 'no' - -os::cmd::expect_success_and_text 'oc auth can-i --list --user system:admin' 'get update.*imagestreams/layers' -os::cmd::expect_success_and_text 'oc auth can-i --list --groups system:unauthenticated --groups system:cluster-readers' 'get.*imagestreams/layers' -os::cmd::expect_success_and_not_text 'oc auth can-i --list --groups system:unauthenticated' 'get update.*imagestreams/layers' -os::cmd::expect_success_and_not_text 'oc auth can-i --list --user harold --groups system:authenticated' 'get update.*imagestreams/layers' -os::cmd::expect_success_and_text 'oc auth can-i --list --user harold --groups system:authenticated' 'create get.*buildconfigs/webhooks' +# Cleanup cluster resources created by this test +( + set +e + oc delete all --all + exit 0 +) &>/dev/null -os::cmd::expect_failure 'oc policy scc-subject-review' -os::cmd::expect_failure 'oc policy scc-review' -os::cmd::expect_failure 'oc policy scc-subject-review -u invalid --namespace=noexist' -os::cmd::expect_failure_and_text 'oc policy scc-subject-review -f ${OS_ROOT}/test/testdata/pspreview_unsupported_statefulset.yaml' 'error: StatefulSet "rd" with spec.volumeClaimTemplates currently not supported.' -os::cmd::expect_failure_and_text 'oc policy scc-subject-review -z foo,bar -f ${OS_ROOT}/test/testdata/job.yaml' 'error: only one Service Account is supported' -os::cmd::expect_failure_and_text 'oc policy scc-subject-review -z system:serviceaccount:test:default,system:serviceaccount:test:builder -f ${OS_ROOT}/test/testdata/job.yaml' 'error: only one Service Account is supported' -os::cmd::expect_failure_and_text 'oc policy scc-review -f ${OS_ROOT}/test/testdata/pspreview_unsupported_statefulset.yaml' 'error: StatefulSet "rd" with spec.volumeClaimTemplates currently not supported.' -os::cmd::expect_success_and_text 'oc policy scc-subject-review -f ${OS_ROOT}/test/testdata/job.yaml -o=jsonpath={.status.allowedBy.name}' 'anyuid' -os::cmd::expect_success_and_text 'oc policy scc-subject-review -f ${OS_ROOT}/test/testdata/redis-slave.yaml -o=jsonpath={.status.allowedBy.name}' 'anyuid' -# In the past system:admin only had access to a few SCCs, so the following command resulted in the privileged SCC being used -# Since SCCs are now authorized via RBAC, and system:admin can perform all RBAC actions == system:admin can access all SCCs now -# Thus the following command now results in the use of the hostnetwork SCC which is the most restrictive SCC that still allows the pod to run -os::cmd::expect_success_and_text 'oc policy scc-subject-review -f ${OS_ROOT}/test/testdata/nginx_pod.yaml -o=jsonpath={.status.allowedBy.name}' 'hostnetwork' -# Make sure that the legacy ungroupified objects continue to work by directly doing a create -os::cmd::expect_success_and_text 'oc create -f ${OS_ROOT}/test/testdata/legacy_ungroupified_psp_review.yaml -o=jsonpath={.status.allowedBy.name}' 'restricted' -os::cmd::expect_success "oc login -u bob -p bobpassword" -os::cmd::expect_success_and_text 'oc whoami' 'bob' -os::cmd::expect_success 'oc new-project policy-second' -os::cmd::expect_success_and_text 'oc policy scc-subject-review -f ${OS_ROOT}/test/testdata/job.yaml -o=jsonpath={.status.allowedBy.name}' 'restricted' -os::cmd::expect_success_and_text 'oc policy scc-subject-review -f ${OS_ROOT}/test/testdata/job.yaml --no-headers=true' 'Job/hello restricted' -os::cmd::expect_success_and_text 'oc policy scc-subject-review -f ${OS_ROOT}/test/testdata/two_jobs.yaml -o=jsonpath={.status.allowedBy.name}' 'restrictedrestricted' -os::cmd::expect_success_and_text 'oc policy scc-review -f ${OS_ROOT}/test/testdata/job.yaml -ojsonpath={.status.allowedServiceAccounts}' '' -os::cmd::expect_success_and_text 'oc policy scc-review -f ${OS_ROOT}/test/extended/testdata/deployments/deployment-simple.yaml -ojsonpath={.status.allowedServiceAccounts}' '' -os::cmd::expect_failure 'oc policy scc-subject-review -f ${OS_ROOT}/test/testdata/external-service.yaml' -os::cmd::expect_success "oc login -u system:admin -n '${project}'" -os::cmd::expect_success_and_text 'oc policy scc-subject-review -u bob -g system:authenticated -f ${OS_ROOT}/test/testdata/job.yaml -n policy-second -o=jsonpath={.status.allowedBy.name}' 'restricted' -os::cmd::expect_success_and_text 'oc policy scc-subject-review -u bob -f ${OS_ROOT}/test/testdata/job.yaml -n policy-second --no-headers=true' 'Job/hello ' -os::cmd::expect_success_and_text 'oc policy scc-subject-review -z default -f ${OS_ROOT}/test/testdata/job.yaml' '' -os::cmd::expect_success_and_text 'oc policy scc-subject-review -z default -g system:authenticated -f ${OS_ROOT}/test/testdata/job.yaml' 'restricted' -os::cmd::expect_failure_and_text 'oc policy scc-subject-review -u alice -z default -g system:authenticated -f ${OS_ROOT}/test/testdata/job.yaml' 'error: --user and --serviceaccount are mutually exclusive' -os::cmd::expect_success_and_text 'oc policy scc-subject-review -z system:serviceaccount:alice:default -g system:authenticated -f ${OS_ROOT}/test/testdata/job.yaml' 'restricted' -os::cmd::expect_success_and_text 'oc policy scc-subject-review -u alice -g system:authenticated -f ${OS_ROOT}/test/testdata/job.yaml' 'restricted' -os::cmd::expect_failure_and_text 'oc policy scc-subject-review -u alice -g system:authenticated -n noexist -f ${OS_ROOT}/test/testdata/job.yaml' 'error: unable to compute Pod Security Policy Subject Review for "hello": namespaces "noexist" not found' -os::cmd::expect_success 'oc create -f ${OS_ROOT}/test/testdata/scc_lax.yaml' -os::cmd::expect_success "oc login -u bob -p bobpassword" -os::cmd::expect_success_and_text 'oc policy scc-review -f ${OS_ROOT}/test/testdata/job.yaml --no-headers=true' 'Job/hello default lax' -os::cmd::expect_success_and_text 'oc policy scc-review -z default -f ${OS_ROOT}/test/testdata/job.yaml --no-headers=true' 'Job/hello default lax' -os::cmd::expect_success_and_text 'oc policy scc-review -z system:serviceaccount:policy-second:default -f ${OS_ROOT}/test/testdata/job.yaml --no-headers=true' 'Job/hello default lax' -os::cmd::expect_success_and_text 'oc policy scc-review -f ${OS_ROOT}/test/extended/testdata/deployments/deployment-simple.yaml --no-headers=true' 'DeploymentConfig/deployment-simple default lax' -os::cmd::expect_success_and_text 'oc policy scc-review -f ${OS_ROOT}/test/testdata/nginx_pod.yaml --no-headers=true' '' -os::cmd::expect_failure_and_text 'oc policy scc-review -z default -f ${OS_ROOT}/test/testdata/job.yaml --namespace=no-exist' 'error: unable to compute Pod Security Policy Review for "hello": podsecuritypolicyreviews.security.openshift.io is forbidden: User "bob" cannot create resource "podsecuritypolicyreviews" in API group "security.openshift.io" in the namespace "no-exist"' -os::cmd::expect_failure_and_text 'oc policy scc-review -z default -f ${OS_ROOT}/test/testdata/pspreview_unsupported_statefulset.yaml' 'error: StatefulSet "rd" with spec.volumeClaimTemplates currently not supported.' -os::cmd::expect_failure_and_text 'oc policy scc-review -z no-exist -f ${OS_ROOT}/test/testdata/job.yaml' 'error: unable to compute Pod Security Policy Review for "hello": unable to retrieve ServiceAccount no-exist: serviceaccount "no-exist" not found' -os::cmd::expect_success "oc login -u system:admin -n '${project}'" -os::cmd::expect_success 'oc delete project policy-second' +os::test::junit::declare_suite_start "cmd/migrate" +# This test validates storage migration -# adjust the cluster-admin role to check defaulting and coverage checks -# this is done here instead of an integration test because we need to make sure the actual yaml serializations work -workingdir=$(mktemp -d) -cp ${OS_ROOT}/hack/local-up-master/test-manifests/cluster_admin_1.0.yaml ${workingdir} -os::util::sed "s/RESOURCE_VERSION//g" ${workingdir}/cluster_admin_1.0.yaml -os::cmd::expect_success "oc create -f ${workingdir}/cluster_admin_1.0.yaml" -os::cmd::expect_success 'oc adm policy add-cluster-role-to-user alternate-cluster-admin alternate-cluster-admin-user' +os::cmd::expect_success 'oc login -u system:admin' +# ensure all namespaces have been deleted before attempting to perform global action +os::cmd::try_until_not_text 'oc get ns --template "{{ range .items }}{{ if not (eq .status.phase \"Active\") }}1{{ end }}{{ end }}"' '1' -# switch to test user to be sure that default project admin policy works properly -new_kubeconfig="${workingdir}/tempconfig" -os::cmd::expect_success "oc config view --raw > $new_kubeconfig" -os::cmd::expect_success "oc login -u alternate-cluster-admin-user -p anything --kubeconfig=${new_kubeconfig}" +project="$( oc project -q )" -# alternate-cluster-admin can restrict himself to less groups (no star) -os::cmd::try_until_text "oc policy who-can update clusterrroles" "alternate-cluster-admin-user" -resourceversion=$(oc get clusterrole/alternate-cluster-admin -o=jsonpath="{.metadata.resourceVersion}") -cp ${OS_ROOT}/hack/local-up-master/test-manifests/cluster_admin_without_apigroups.yaml ${workingdir} -os::util::sed "s/RESOURCE_VERSION/${resourceversion}/g" ${workingdir}/cluster_admin_without_apigroups.yaml -os::cmd::expect_success "oc replace --kubeconfig=${new_kubeconfig} clusterrole/alternate-cluster-admin -f ${workingdir}/cluster_admin_without_apigroups.yaml" +os::test::junit::declare_suite_start "cmd/migrate/storage" +os::cmd::expect_success_and_text 'oc adm migrate storage' 'summary' +os::cmd::expect_success_and_text 'oc adm migrate storage --loglevel=2' ": -n ${project} serviceaccounts/deployer" +os::cmd::expect_success_and_not_text 'oc adm migrate storage --loglevel=2 --include=pods' ": -n ${project} serviceaccounts/deployer" +os::cmd::expect_success_and_text 'oc adm migrate storage --loglevel=2 --include=sa --from-key=default/ --to-key=default/\xFF' ": -n default serviceaccounts/deployer" +os::cmd::expect_success_and_not_text 'oc adm migrate storage --loglevel=2 --include=sa --from-key=default/ --to-key=default/deployer' ": -n default serviceaccounts/deployer" +os::cmd::expect_success_and_text 'oc adm migrate storage --loglevel=2' 'unchanged:' +os::cmd::expect_success_and_text 'oc adm migrate storage --bandwidth=20' 'summary:' +os::cmd::expect_success_and_text 'oc adm migrate storage --confirm' 'storage migration does not support dry run, this flag is ignored' +os::cmd::expect_success_and_text 'oc adm migrate storage -o=yaml' 'storage migration does not support dry run, this flag is ignored' +os::test::junit::declare_suite_end -# alternate-cluster-admin should NOT have the power add back star now (anything other than star is considered less so this mimics testing against no groups) -os::cmd::try_until_failure "oc policy who-can update hpa.autoscaling | grep -q alternate-cluster-admin-user" -resourceversion=$(oc get clusterrole/alternate-cluster-admin -o=jsonpath="{.metadata.resourceVersion}") -cp ${OS_ROOT}/vendor/github.com/openshift/openshift-apiserver/test/testdata/bootstrappolicy/alternate_cluster_admin.yaml ${workingdir} -os::util::sed "s/RESOURCE_VERSION/${resourceversion}/g" ${workingdir}/alternate_cluster_admin.yaml -os::cmd::expect_failure_and_text "oc replace --kubeconfig=${new_kubeconfig} clusterrole/alternate-cluster-admin -f ${workingdir}/alternate_cluster_admin.yaml" "attempting to grant RBAC permissions not currently held" +os::test::junit::declare_suite_start "cmd/migrate/storage_oauthclientauthorizations" +# Create valid OAuth client +os::cmd::expect_success_and_text 'oc create -f test/testdata/oauth/client.yaml' 'oauthclient.oauth.openshift.io/test-oauth-client created' +# Create OAuth client authorization for client +os::cmd::expect_success_and_text 'oc create -f test/testdata/oauth/clientauthorization.yaml' 'oauthclientauthorization.oauth.openshift.io/user1:test-oauth-client created' +# Delete client +os::cmd::expect_success_and_text 'oc delete oauthclient test-oauth-client' 'oauthclient.oauth.openshift.io "test-oauth-client" deleted' +# Assert that migration/update still works even though the client authorization is no longer valid +os::cmd::expect_success_and_text 'oc adm migrate storage --loglevel=6 --include=oauthclientauthorizations' 'PUT.*oauthclientauthorizations/user1:test-oauth-client' +os::test::junit::declare_suite_end -# This test validates cluster level policy for serviceaccounts -# ensure service account cannot list pods at the namespace level -os::cmd::expect_success_and_text "oc auth can-i list pods --as=system:serviceaccount:cmd-policy:testserviceaccount" "no" -os::cmd::expect_success_and_text "oc adm policy add-role-to-user view -z=testserviceaccount" 'clusterrole.rbac.authorization.k8s.io/view added: "testserviceaccount"' -# ensure service account can list pods at the namespace level after "view" role is added, but not at the cluster level -os::cmd::try_until_text "oc auth can-i list pods --as=system:serviceaccount:${project}:testserviceaccount" "yes" -os::cmd::try_until_text "oc auth can-i list pods --all-namespaces --as=system:serviceaccount:${project}:testserviceaccount" "no" -# ensure service account can list pods at the cluster level after "cluster-reader" cluster role is added -os::cmd::expect_success_and_text "oc adm policy add-cluster-role-to-user cluster-reader -z=testserviceaccount" 'clusterrole.rbac.authorization.k8s.io/cluster-reader added: "testserviceaccount"' -os::cmd::try_until_text "oc auth can-i list pods --all-namespaces --as=system:serviceaccount:${project}:testserviceaccount" "yes" +os::test::junit::declare_suite_start "cmd/migrate/imagereferences" +# create alternating items in history +os::cmd::expect_success 'oc import-image --from=mysql:latest test:1 --confirm' +os::cmd::expect_success 'oc import-image --from=php:latest test:2 --confirm' +os::cmd::expect_success 'oc tag --source=docker php:latest test:1' +os::cmd::expect_success 'oc tag --source=docker mysql:latest test:1' +os::cmd::expect_success 'oc tag --source=docker mysql:latest test:2' +os::cmd::expect_success 'oc tag --source=docker php:latest test:2' +os::cmd::expect_success 'oc tag --source=docker myregistry.com/php:latest test:3' +# verify error cases +os::cmd::expect_failure_and_text 'oc adm migrate image-references' 'at least one mapping argument must be specified: REGISTRY/NAME=REGISTRY/NAME' +os::cmd::expect_failure_and_text 'oc adm migrate image-references my.docker.io=docker.io/* --loglevel=1' 'all arguments' +os::cmd::expect_failure_and_text 'oc adm migrate image-references my.docker.io/=docker.io/* --loglevel=1' 'not a valid source' +os::cmd::expect_failure_and_text 'oc adm migrate image-references /*=docker.io/* --loglevel=1' 'not a valid source' +os::cmd::expect_failure_and_text 'oc adm migrate image-references my.docker.io/*=docker.io --loglevel=1' 'all arguments' +os::cmd::expect_failure_and_text 'oc adm migrate image-references my.docker.io/*=docker.io/ --loglevel=1' 'not a valid target' +os::cmd::expect_failure_and_text 'oc adm migrate image-references my.docker.io/*=/x --loglevel=1' 'not a valid target' +os::cmd::expect_failure_and_text 'oc adm migrate image-references my.docker.io/*=*/* --loglevel=1' 'at least one change' +os::cmd::expect_failure_and_text 'oc adm migrate image-references a/b=a/b --loglevel=1' 'at least one field' +os::cmd::expect_failure_and_text 'oc adm migrate image-references */*=*/* --loglevel=1' 'at least one change' +# verify dry run +os::cmd::expect_success_and_text 'oc adm migrate image-references my.docker.io/*=docker.io/* --loglevel=1' 'migrated=0' +os::cmd::expect_success_and_text 'oc adm migrate image-references --include=imagestreams docker.io/*=my.docker.io/* --loglevel=1' "migrated \(dry run\): -n ${project} imagestreams.image.openshift.io/test" +os::cmd::expect_success_and_text 'oc adm migrate image-references --include=imagestreams docker.io/mysql=my.docker.io/* --all-namespaces=false --loglevel=1' 'migrated=1' +os::cmd::expect_success_and_text 'oc adm migrate image-references --include=imagestreams docker.io/mysql=my.docker.io/* --all-namespaces=false --loglevel=1 -o yaml' 'dockerImageReference: my.docker.io/mysql@sha256:' +os::cmd::expect_success_and_text 'oc adm migrate image-references --include=imagestreams docker.io/other=my.docker.io/* --all-namespaces=false --loglevel=1' 'migrated=0' +# only mysql references are changed +os::cmd::expect_success_and_text 'oc adm migrate image-references --include=imagestreams docker.io/mysql=my.docker.io/mysql2 --all-namespaces=false --loglevel=1 --confirm' 'migrated=1' +os::cmd::expect_success_and_text 'oc get istag test:1 --template "{{ .image.dockerImageReference }}"' '^my.docker.io/mysql2@sha256:' +os::cmd::expect_success_and_text 'oc get istag test:2 --template "{{ .image.dockerImageReference }}"' '^php@sha256:' +# all items in history are changed +os::cmd::expect_success_and_text 'oc adm migrate image-references --include=imagestreams docker.io/*=my.docker.io/* --all-namespaces=false --loglevel=1 --confirm' 'migrated=1' +os::cmd::expect_success_and_not_text 'oc get is test --template "{{ range .status.tags }}{{ range .items }}{{ .dockerImageReference }}{{ \"\n\" }}{{ end }}{{ end }}"' '^php' +os::cmd::expect_success_and_not_text 'oc get is test --template "{{ range .status.tags }}{{ range .items }}{{ .dockerImageReference }}{{ \"\n\" }}{{ end }}{{ end }}"' '^mysql' +os::test::junit::declare_suite_end -# make sure users can easily create roles for RBAC based SCC access -os::cmd::expect_success_and_text 'oc create role scc-privileged --verb=use --resource=scc --resource-name=privileged' 'role.rbac.authorization.k8s.io/scc-privileged created' -os::cmd::expect_success_and_text 'oc delete role.rbac scc-privileged' 'role.rbac.authorization.k8s.io "scc-privileged" deleted' +os::test::junit::declare_suite_start "cmd/migrate/legacyhpa" +# create a legacy and a normal HPA +os::cmd::expect_success 'oc create -f test/testdata/hpa/legacy-and-normal-hpa.yaml' +# verify dry run +os::cmd::expect_success_and_text 'oc adm migrate legacy-hpa' 'migrated=1' +# confirm... +os::cmd::expect_success_and_text 'oc adm migrate legacy-hpa --confirm' 'migrated=1' +# verify that all HPAs are as they should be +os::cmd::expect_success_and_text 'oc get hpa legacy-hpa -o jsonpath="{.spec.scaleTargetRef.apiVersion}.{.spec.scaleTargetRef.kind} {.spec.scaleTargetRef.name}"' 'apps.openshift.io/v1.DeploymentConfig legacy-target' +os::cmd::expect_success_and_text 'oc get hpa other-hpa -o jsonpath="{.spec.scaleTargetRef.apiVersion}.{.spec.scaleTargetRef.kind} {.spec.scaleTargetRef.name}"' 'apps/v1.Deployment other-target' +os::test::junit::declare_suite_end -echo "policy: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdPolicyShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdPolicySh, nil +func testExtendedTestdataCmdTestCmdMigrateShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdMigrateSh, nil } -func testExtendedTestdataCmdTestCmdPolicySh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdPolicyShBytes() +func testExtendedTestdataCmdTestCmdMigrateSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdMigrateShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/policy.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/migrate.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdPrinterSh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdNewappSh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT -# Test that resource printer includes resource kind on multiple resources -os::test::junit::declare_suite_start "cmd/basicresources/printer" -os::cmd::expect_success 'oc create imagestream test1' -os::cmd::expect_success 'oc new-app node' -os::cmd::expect_success_and_text 'oc get all' 'imagestream.image.openshift.io/test1' -os::cmd::expect_success_and_not_text 'oc get is' 'imagestream.image.openshift.io/test1' +# Cleanup cluster resources created by this test +( + set +e + oc login -u system:admin + oc delete all,templates --all + oc delete all,templates --all -n openshift + oc delete project template-substitute + oc delete project prefix-template-substitute + oc delete project test-imagestreams + oc delete project new-app-syntax + rm -rf ./test/testdata/testapp + exit 0 +) &>/dev/null -# Test that resource printer includes namespaces for buildconfigs with custom strategies -os::cmd::expect_success 'oc create -f ${TEST_DATA}/application-template-custombuild.json' -os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample' 'deployment.*.apps.* "frontend" created' -os::cmd::expect_success_and_text 'oc get all --all-namespaces' 'cmd-printer[\ ]+buildconfig.build.openshift.io\/ruby\-sample\-build' +os::util::environment::setup_time_vars -# Test that infos printer supports all outputFormat options -os::cmd::expect_success_and_text 'oc new-app node --dry-run -o yaml | oc set env --local -f - MYVAR=value' 'deployment.*.apps.*/node updated' -os::cmd::expect_success_and_text 'oc new-app node --dry-run -o yaml | oc set env --local -f - MYVAR=value -o yaml' 'apiVersion: apps.*/v1' -os::cmd::expect_success_and_text 'oc new-app node --dry-run -o yaml | oc set env --local -f - MYVAR=value -o json' '"apiVersion": "apps.*/v1"' -echo "resource printer: ok" -os::test::junit::declare_suite_end -`) +os::test::junit::declare_suite_start "cmd/newapp" -func testExtendedTestdataCmdTestCmdPrinterShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdPrinterSh, nil -} +default_project=$(oc project -q) +#os::cmd::expect_success 'git clone https://github.com/openshift/ruby-hello-world.git ./test/testdata/testapp' -func testExtendedTestdataCmdTestCmdPrinterSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdPrinterShBytes() - if err != nil { - return nil, err - } +# imagestream/tag creation and reuse +os::cmd::expect_success 'oc create -f ${TEST_DATA}/image-streams/image-streams-centos7.json -n openshift' +os::cmd::expect_success 'oc delete istag php:latest -n openshift' +os::cmd::expect_success 'oc new-project test-imagestreams' +os::cmd::try_until_failure 'oc get istag php:latest -n openshift' - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/printer.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +# should fail due to missing php:latest tag +os::cmd::expect_failure 'oc new-app --image-stream=openshift/php https://github.com/sclorg/cakephp-ex' -var _testExtendedTestdataCmdTestCmdProjectsSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT +# should succeed and create the php:latest tag in the current namespace +os::cmd::expect_success 'oc new-app --docker-image=library/php https://github.com/sclorg/cakephp-ex --strategy=source' +os::cmd::try_until_success 'oc get istag php:latest -n test-imagestreams' +os::cmd::expect_success 'oc create istag php:latest --from=openshift/php:7.1 -n openshift' -# Cleanup cluster resources created by this test -( - set +e - oc delete namespace test4 - oc delete namespace test5 - oc delete namespace test6 - oc wait --for=delete namespace test4 --timeout=60s || true - oc wait --for=delete namespace test5 --timeout=60s || true - oc wait --for=delete namespace test6 --timeout=60s || true - exit 0 -) &>/dev/null +# create a new tag for an existing imagestream in the current namespace +os::cmd::expect_success 'oc create istag perl:5.24 --from=openshift/perl:5.24' +os::cmd::expect_success 'oc new-app --docker-image=library/perl https://github.com/sclorg/dancer-ex --strategy=source' +os::cmd::try_until_success 'oc get istag perl:latest -n test-imagestreams' +# remove redundant imagestream tag before creating objects +os::cmd::expect_success_and_text 'oc new-app openshift/ruby-27-centos7 https://github.com/openshift/ruby-hello-world --strategy=docker --loglevel=5' 'Removing duplicate tag from object list' -os::test::junit::declare_suite_start "cmd/projects" +# create imagestream in the correct namespace +os::cmd::expect_success 'oc new-app --name=mytest --image-stream=mysql --env=MYSQL_USER=test --env=MYSQL_PASSWORD=redhat --env=MYSQL_DATABASE=testdb -l app=mytest' +os::cmd::try_until_success 'oc get is mytest -n test-imagestreams' -os::test::junit::declare_suite_start "cmd/projects/lifecycle" -# resourceaccessreview -os::cmd::expect_success 'oc policy who-can get pods -n missing-ns' -# selfsubjectaccessreview -os::cmd::expect_success 'oc auth can-i get pods -n missing-ns' -# selfsubjectrulesreivew -os::cmd::expect_success 'oc auth can-i --list -n missing-ns' -# create bob -os::cmd::expect_success 'oc create user bob' -# subjectaccessreview -os::cmd::expect_failure_and_text 'oc auth can-i get pods --as=bob -n missing-ns' 'no' -# subjectrulesreview -os::cmd::expect_success 'oc auth can-i --list --as=bob -n missing-ns' -echo 'project lifecycle ok' -os::test::junit::declare_suite_end +# don't create an unnecessary imagestream +os::cmd::expect_success 'oc new-app https://github.com/sclorg/nodejs-ex' +os::cmd::expect_failure_and_text 'oc get is nodejs -n test-imagestreams' 'not found' -os::cmd::expect_failure_and_text 'oc projects test_arg' 'no arguments' -# log in as a test user and expect no projects -#os::cmd::expect_success 'oc login -u test -p test' -#os::cmd::expect_success_and_text 'oc projects' 'You are not a member of any projects' -# add a project and expect text for a single project -os::cmd::expect_success_and_text 'oc new-project test4' 'Now using project "test4" on server ' -os::cmd::try_until_text 'oc projects' 'Using project "test4" on server' -os::cmd::expect_success_and_text 'oc new-project test5' 'Now using project "test5" on server ' -os::cmd::try_until_text 'oc projects' 'You have access to the following projects and can switch between them with ' -# HA masters means that you may have to wait for the lists to settle, so you allow for that by waiting -os::cmd::try_until_text 'oc projects' 'test4' -os::cmd::try_until_text 'oc projects' 'test5' -# test --skip-config-write -os::cmd::expect_success_and_text 'oc new-project test6 --skip-config-write' 'To switch to this project and start adding applications, use' -os::cmd::expect_success_and_not_text 'oc config view -o jsonpath="{.contexts[*].context.namespace}"' '\btest6\b' -os::cmd::try_until_text 'oc projects' 'test6' -os::cmd::expect_success_and_text 'oc project test6' 'Now using project "test6"' -os::cmd::expect_success_and_text 'oc config view -o jsonpath="{.contexts[*].context.namespace}"' '\btest6\b' -echo 'projects command ok' +# check reuse imagestreams +os::cmd::expect_success "oc new-build -D $'FROM node:8\nRUN echo \"Test\"' --name=node8" +os::cmd::try_until_success 'oc get istag node:8' +os::cmd::expect_success "oc new-build -D $'FROM node:10\nRUN echo \"Test\"' --name=node10" +os::cmd::try_until_success 'oc get istag node:10' +# cleanup and reset to default namespace +os::cmd::expect_success 'oc delete is --all -n openshift' +os::cmd::expect_success 'oc delete project test-imagestreams' -os::test::junit::declare_suite_end -`) +# This test validates the new-app command +os::cmd::expect_success 'oc project ${default_project}' +os::cmd::expect_success_and_text 'oc new-app library/php mysql -o yaml' '3306' +os::cmd::expect_success_and_text 'oc new-app library/php mysql --dry-run' "Image \"library/php\" runs as the 'root' user which may not be permitted by your cluster administrator" +os::cmd::expect_failure 'oc new-app unknownhubimage -o yaml' +os::cmd::expect_failure_and_text 'oc new-app docker.io/node~https://github.com/sclorg/nodejs-ex' 'the image match \"docker.io/node\" for source repository \"https://github.com/sclorg/nodejs-ex\" does not appear to be a source-to-image builder.' +os::cmd::expect_failure_and_text 'oc new-app https://github.com/sclorg/rails-ex' 'the image match \"ruby\" for source repository \"https://github.com/sclorg/rails-ex\" does not appear to be a source-to-image builder.' +os::cmd::expect_success 'oc new-app https://github.com/sclorg/rails-ex --strategy=source --dry-run' +# verify we can generate a container image based component "mongodb" directly +os::cmd::expect_success_and_text 'oc new-app mongo -o yaml' 'image:\s*mongo' +# the local image repository takes precedence over the Docker Hub "mysql" image +os::cmd::expect_success 'oc create -f ${TEST_DATA}/image-streams/image-streams-centos7.json' +os::cmd::try_until_success 'oc get imagestreamtags mysql:latest' $((2*TIME_MIN)) +os::cmd::try_until_success 'oc get imagestreamtags mysql:5.6' $((2*TIME_MIN)) +os::cmd::try_until_success 'oc get imagestreamtags mysql:5.7' $((2*TIME_MIN)) +os::cmd::expect_success_and_not_text 'oc new-app mysql -o yaml' 'image:\s*mysql' +os::cmd::expect_success_and_not_text 'oc new-app mysql --dry-run' "runs as the 'root' user which may not be permitted by your cluster administrator" +# trigger and output should say 5.6 +os::cmd::expect_success_and_text 'oc new-app mysql -o yaml' 'mysql:5.7' +os::cmd::expect_success_and_text 'oc new-app mysql --dry-run' 'tag "5.7" for "mysql"' +# test deployments are created with the boolean flag and printed in the UI +os::cmd::expect_success_and_text 'oc new-app mysql --dry-run --as-test' 'This image will be test deployed' +os::cmd::expect_success_and_text 'oc new-app mysql -o yaml --as-test' 'test: true' +os::cmd::expect_success_and_text 'oc new-app ${TEST_DATA}/new-app/template-minimal-expose.json --as-test' 'Access your application via route' +os::cmd::expect_success 'oc delete all -l app=expose-output' +os::cmd::expect_success_and_text 'oc new-app mysql --as-test' 'Application is not exposed' +os::cmd::expect_success 'oc delete all -l app=mysql' -func testExtendedTestdataCmdTestCmdProjectsShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdProjectsSh, nil -} +# ensure that oc new-app does not emit a BuildConfigInstantiateFailed event when creating a new application +os::cmd::expect_success 'oc new-app https://github.com/sclorg/ruby-ex' +os::cmd::expect_success_and_not_text 'oc describe bc/ruby-ex' 'BuildConfigInstantiateFailed' +os::cmd::expect_success 'oc delete all -l app=ruby-ex' -func testExtendedTestdataCmdTestCmdProjectsSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdProjectsShBytes() - if err != nil { - return nil, err - } +# Ensure that an invalid build strategy in a template does not throw a segmentation fault +os::cmd::expect_success_and_not_text 'oc new-app --file ${TEST_DATA}/new-app/invalid-build-strategy.yaml --dry-run' 'invalid memory address or nil pointer dereference' - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/projects.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +# test that imagestream references across imagestreams do not cause an error +os::cmd::try_until_success 'oc get imagestreamtags ruby:2.7' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/new-app/imagestream-ref.yaml' +os::cmd::try_until_success 'oc get imagestreamtags myruby:latest' +os::cmd::expect_success 'oc new-app myruby~https://github.com/openshift/ruby-hello-world.git --dry-run' +os::cmd::expect_success 'oc delete is myruby' -var _testExtendedTestdataCmdTestCmdQuotaSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT +# Ensure clear error message wrt templates container CRDs and new-app appears +os::cmd::expect_failure_and_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-crd.yaml' 'error: The template contained an object type unknown to ' -os::test::junit::declare_suite_start "cmd/quota" +# docker strategy with repo that has no dockerfile +os::cmd::expect_failure_and_text 'oc new-app https://github.com/sclorg/nodejs-ex --strategy=docker' 'No Dockerfile was found' -# Cleanup cluster resources created by this test suite -( - set +e - oc delete namespace quota-{foo,bar,asmail,images} - oc wait --for=delete namespace quota-{foo,bar,asmail,images} --timeout=60s || true - oc delete clusterresourcequotas.quota.openshift.io "for-deads" - oc delete clusterresourcequotas.quota.openshift.io "for-deads-by-annotation" - oc delete clusterresourcequotas.quota.openshift.io "for-deads-email-by-annotation" - oc delete clusterresourcequotas.quota.openshift.io "annotation-value-with-commas" - exit 0 -) &>/dev/null +# repo related error message validation +os::cmd::expect_success 'oc create -f examples/db-templates/mysql-persistent-template.json' +os::cmd::expect_failure_and_text 'oc new-app mysql-persisten mysql' 'only a partial match was found for' +os::cmd::expect_success 'oc delete template/mysql-persistent' +os::cmd::expect_failure_and_text 'oc new-app --strategy=docker https://192.30.253.113/openshift/ruby-hello-world.git' 'none of the arguments provided could be classified as a source code location' +os::cmd::expect_failure_and_text 'oc new-app https://www.google.com/openshift/nodejs-e' 'unable to load template file' +os::cmd::expect_failure_and_text 'oc new-app https://www.google.com/openshift/nodejs-e' 'unable to locate any' +os::cmd::expect_failure_and_text 'oc new-app https://www.google.com/openshift/nodejs-e' 'was classified as an image, image~source, or loaded template reference.' +os::cmd::expect_failure_and_text 'oc new-app https://examplegit.com/openshift/nodejs-e' 'unable to load template file' +os::cmd::expect_failure_and_text 'oc new-app https://examplegit.com/openshift/nodejs-e' 'unable to locate any' +os::cmd::expect_failure_and_text 'oc new-app https://examplegit.com/openshift/nodejs-e' 'was classified as an image, image~source, or loaded template reference.' +os::cmd::expect_failure_and_text 'oc new-build --strategy=docker https://192.30.253.113/openshift/ruby-hello-world.git' 'none of the arguments provided could be classified as a source code location' +os::cmd::expect_failure_and_text 'oc new-build https://www.google.com/openshift/nodejs-e' 'unable to load template file' +os::cmd::expect_failure_and_text 'oc new-build https://www.google.com/openshift/nodejs-e' 'unable to locate any' +os::cmd::expect_failure_and_text 'oc new-build https://www.google.com/openshift/nodejs-e' 'was classified as an image, image~source, or loaded template reference.' +os::cmd::expect_failure_and_text 'oc new-build https://examplegit.com/openshift/nodejs-e' 'unable to load template file' +os::cmd::expect_failure_and_text 'oc new-build https://examplegit.com/openshift/nodejs-e' 'unable to locate any' +os::cmd::expect_failure_and_text 'oc new-build https://examplegit.com/openshift/nodejs-e' 'was classified as an image, image~source, or loaded template reference.' +os::cmd::expect_failure_and_text 'oc new-build --name imagesourcetest python~https://github.com/openshift-katacoda/blog-django-py --source-image xxx --source-image-path=yyy --dry-run' 'unable to locate any ' +os::cmd::expect_failure_and_text 'oc new-app ~java' 'you must specify a image name' -os::test::junit::declare_suite_start "cmd/quota/clusterquota" +# setting source secret via the --source-secret flag +os::cmd::expect_success_and_text 'oc new-app https://github.com/sclorg/cakephp-ex --source-secret=mysecret -o yaml' 'name: mysecret' +os::cmd::expect_success_and_text 'oc new-build https://github.com/sclorg/cakephp-ex --source-secret=mynewsecret -o yaml' 'name: mynewsecret' +os::cmd::expect_failure_and_text 'oc new-app https://github.com/sclorg/cakephp-ex --source-secret=InvalidSecretName -o yaml' 'error: source secret name "InvalidSecretName" is invalid' +os::cmd::expect_success_and_text 'oc new-app -f examples/quickstarts/cakephp-mysql.json --source-secret=mysecret -o yaml' 'name: mysecret' +os::cmd::expect_success 'oc new-app https://github.com/sclorg/cakephp-ex --source-secret=mysecret' +os::cmd::expect_success 'oc delete all --selector="label=cakephp-ex"' +# setting push secret via the --push-secret flag +os::cmd::expect_success_and_text 'oc new-build https://github.com/sclorg/cakephp-ex --push-secret=mynewsecret -o yaml' 'name: mynewsecret' +os::cmd::expect_failure_and_text 'oc new-build https://github.com/sclorg/cakephp-ex --push-secret=InvalidSecretName -o yaml' 'error: push secret name "InvalidSecretName" is invalid' -# This tests creating a clusterresourcequota against an existing namespace with a known number of resources -os::cmd::expect_success 'oc new-project quota-foo --as=deads --as-group=system:authenticated --as-group=system:authenticated:oauth' -os::cmd::expect_success 'oc label namespace/quota-foo owner=deads' -os::cmd::try_until_text 'oc get secrets -o name -n quota-foo | wc -l' '9' -os::cmd::expect_success 'oc create clusterquota for-deads --project-label-selector=owner=deads --hard=secrets=10' -os::cmd::try_until_text 'oc get appliedclusterresourcequota -n quota-foo --as deads -o name' "for-deads" -os::cmd::try_until_text 'oc get secrets --all-namespaces; oc get appliedclusterresourcequota/for-deads -n quota-foo --as deads -o jsonpath=used={.status.total.used.secrets}' "used=9" -os::cmd::expect_failure_and_text 'oc create clusterquota for-deads-malformed --project-annotation-selector="openshift.#$%/requester=deads"' "prefix part a DNS-1123 subdomain must consist of lower case alphanumeric characters" -os::cmd::expect_failure_and_text 'oc create clusterquota for-deads-malformed --project-annotation-selector=openshift.io/requester=deads,openshift.io/novalue' "Malformed annotation selector" -os::cmd::expect_success 'oc create clusterquota for-deads-by-annotation --project-annotation-selector=openshift.io/requester=deads --hard=secrets=50' -os::cmd::expect_success 'oc create clusterquota for-deads-email-by-annotation --project-annotation-selector=openshift.io/requester=deads@deads.io --hard=secrets=50' -os::cmd::expect_success 'oc create clusterresourcequota annotation-value-with-commas --project-annotation-selector="openshift.io/requester=deads,\"openshift.io/withcomma=yes,true,1\"" --hard=pods=10' -os::cmd::expect_success 'oc new-project quota-bar --as=deads --as-group=system:authenticated --as-group=system:authenticated:oauth' -os::cmd::expect_success 'oc new-project quota-asmail --as=deads@deads.io --as-group=system:authenticated --as-group=system:authenticated:oauth' -os::cmd::try_until_text 'oc get appliedclusterresourcequota -n quota-bar --as deads -o name' "for-deads-by-annotation" -os::cmd::try_until_text 'oc get appliedclusterresourcequota -n quota-foo --as deads -o name' "for-deads-by-annotation" -os::cmd::try_until_text 'oc get appliedclusterresourcequota -n quota-asmail --as deads@deads.io -o name' "for-deads-email-by-annotation" -# the point of the test is to make sure that clusterquota is counting correct and secrets are auto-created and countable -# the create_dockercfg controller can issue multiple creates if the token controller doesn't fill them in, but the creates are duplicates -# since an annotation tracks the intended secrets to be created. That results in multi-counting quota until reconciliation runs -# do not go past 26. If you get to 27, you might be selecting an extra namespace. -os::cmd::try_until_text 'oc get secrets --all-namespaces; oc get appliedclusterresourcequota/for-deads-by-annotation -n quota-bar --as deads -o jsonpath=used={.status.total.used.secrets}' "used=(1[0-9]|20|21|22|23|24|25|26)" -os::cmd::expect_success 'oc delete project quota-foo' -os::cmd::try_until_not_text 'oc get clusterresourcequota/for-deads-by-annotation -o jsonpath="{.status.namespaces[*].namespace}"' 'quota-foo' -os::cmd::expect_success 'oc delete project quota-bar' -os::cmd::expect_success 'oc delete project quota-asmail' +# check label creation +os::cmd::try_until_success 'oc get imagestreamtags php:latest' +os::cmd::try_until_success 'oc get imagestreamtags php:5.5' +os::cmd::try_until_success 'oc get imagestreamtags php:5.6' +os::cmd::expect_success 'oc new-app php mysql -l no-source=php-mysql' +os::cmd::expect_success 'oc delete all -l no-source=php-mysql' +os::cmd::expect_success 'oc new-app php mysql' +os::cmd::expect_success 'oc delete all -l app=php' +os::cmd::expect_failure 'oc get dc/mysql' +os::cmd::expect_failure 'oc get dc/php' +os::cmd::expect_success_and_text 'oc new-app -f ${TEST_DATA}/new-app/template-without-app-label.json -o yaml' 'app: ruby-helloworld-sample' -echo "clusterquota: ok" -os::test::junit::declare_suite_end +# check object namespace handling +# hardcoded values should be stripped +os::cmd::expect_success_and_not_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-namespaces.json -o jsonpath="{.items[?(@.metadata.name==\"stripped\")].metadata.namespace}"' 'STRIPPED' +# normal parameterized values should be substituted and retained +os::cmd::expect_success_and_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-namespaces.json -o jsonpath="{.items[?(@.metadata.name==\"route-edge-substituted\")].metadata.namespace}"' 'substituted' +os::cmd::expect_success_and_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-namespaces.json -o jsonpath="{.items[?(@.metadata.name==\"route-edge-prefix-substituted\")].metadata.namespace}"' 'prefix-substituted' +# non-string parameterized values should be stripped +os::cmd::expect_failure_and_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-namespaces.json -o jsonpath="{.items[?(@.metadata.name==\"route-edge-refstripped\")].metadata.namespace}"' 'namespace is not found' +os::cmd::expect_failure_and_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-namespaces.json -o jsonpath="{.items[?(@.metadata.name==\"route-edge-prefix-refstripped\")].metadata.namespace}"' 'namespace is not found' +# ensure --build-env environment variables get added to the buildconfig +os::cmd::expect_success_and_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-app-label.json --build-env FOO=bar -o yaml' 'FOO' +# ensure the objects can actually get created with a namespace specified +os::cmd::expect_success 'oc new-project template-substitute' +os::cmd::expect_success 'oc new-project prefix-template-substitute' +os::cmd::expect_success 'oc project ${default_project}' +os::cmd::expect_success 'oc new-app -f ${TEST_DATA}/new-app/template-with-namespaces.json -p SUBSTITUTED=template-substitute' +os::cmd::expect_success 'oc delete all -l app=ruby-helloworld-sample' -os::test::junit::declare_suite_start "cmd/quota/imagestreams" +# ensure non-duplicate invalid label errors show up +os::cmd::expect_failure_and_text 'oc new-app docker.io/library/wordpress -l qwer1345%$$#=self' 'error: ImageStream.image.openshift.io "wordpress" is invalid' +os::cmd::expect_failure_and_text 'oc new-app docker.io/library/wordpress -l qwer1345%$$#=self' 'DeploymentConfig.apps.openshift.io "wordpress" is invalid' +os::cmd::expect_failure_and_text 'oc new-app docker.io/library/wordpress -l qwer1345%$$#=self' 'Service "wordpress" is invalid' + +# check if we can create from a stored template +os::cmd::expect_success 'oc create -f examples/sample-app/application-template-stibuild.json' +os::cmd::expect_success 'oc get template ruby-helloworld-sample' +os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample -o yaml' 'MYSQL_USER' +os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample -o yaml' 'MYSQL_PASSWORD' +os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample --param MYSQL_PASSWORD=hello -o yaml' 'hello' +os::cmd::expect_success_and_text 'oc new-app -e FOO=BAR -f examples/jenkins/jenkins-ephemeral-template.json -o jsonpath="{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"FOO\")].value}" ' '^BAR$' +os::cmd::expect_success_and_text 'oc new-app -e OPENSHIFT_ENABLE_OAUTH=false -f examples/jenkins/jenkins-ephemeral-template.json -o jsonpath="{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"OPENSHIFT_ENABLE_OAUTH\")].value}" ' 'false' + +# check that multiple resource groups are printed with their respective external version +os::cmd::expect_success_and_text 'oc new-app -f ${TEST_DATA}/new-app/template_multiple_resource_gvs.yaml -o yaml' 'apiVersion: apps/v1' + +# check that an error is produced when using --context-dir with a template +os::cmd::expect_failure_and_text 'oc new-app -f examples/sample-app/application-template-stibuild.json --context-dir=example' '\-\-context-dir is not supported when using a template' + +# check that values are not split on commas +os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample --param MYSQL_DATABASE=hello,MYSQL_USER=fail -o yaml' 'value: hello,MYSQL_USER=fail' +# check that warning is printed when --param PARAM1=VAL1,PARAM2=VAL2 is used +os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample --param MYSQL_DATABASE=hello,MYSQL_USER=fail -o yaml' 'no longer accepts comma-separated list' +# check that env vars are not split on commas +os::cmd::expect_success_and_text 'oc new-app php --env PASS=one,two=three -o yaml' 'value: one,two=three' +# check that warning is printed when --env PARAM1=VAL1,PARAM2=VAL2 is used +os::cmd::expect_success_and_text 'oc new-app php --env PASS=one,two=three -o yaml' 'no longer accepts comma-separated list' +# check that warning is not printed when --param/env doesn't contain two k-v pairs +os::cmd::expect_success_and_not_text 'oc new-app php --env DEBUG=disabled -o yaml' 'no longer accepts comma-separated list' +os::cmd::expect_success_and_not_text 'oc new-app php --env LEVELS=INFO,WARNING -o yaml' 'no longer accepts comma-separated list' +os::cmd::expect_success_and_not_text 'oc new-app ruby-helloworld-sample --param MYSQL_USER=mysql -o yaml' 'no longer accepts comma-separated list' +os::cmd::expect_success_and_not_text 'oc new-app ruby-helloworld-sample --param MYSQL_PASSWORD=com,ma -o yaml' 'no longer accepts comma-separated list' +# check that warning is not printed when env vars are passed positionally +os::cmd::expect_success_and_text 'oc new-app php PASS=one,two=three -o yaml' 'value: one,two=three' +os::cmd::expect_success_and_not_text 'oc new-app php PASS=one,two=three -o yaml' 'no longer accepts comma-separated list' + +# check that we can populate template parameters from file +param_file="${TEST_DATA}/new-app/test-cmd-newapp-params.env" +os::cmd::expect_success_and_text "oc new-app ruby-helloworld-sample --param-file ${param_file} -o jsonpath='{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"MYSQL_DATABASE\")].value}'" 'thisisadatabase' +os::cmd::expect_success_and_text "oc new-app ruby-helloworld-sample --param-file ${param_file} --param MYSQL_DATABASE=otherdatabase -o jsonpath='{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"MYSQL_DATABASE\")].value}'" 'otherdatabase' +os::cmd::expect_success_and_text "oc new-app ruby-helloworld-sample --param-file ${param_file} --param MYSQL_DATABASE=otherdatabase -o yaml" 'ignoring value from file' +os::cmd::expect_success_and_text "cat ${param_file} | oc new-app ruby-helloworld-sample --param-file - -o jsonpath='{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"MYSQL_DATABASE\")].value}'" 'thisisadatabase' + +os::cmd::expect_failure_and_text "oc new-app ruby-helloworld-sample --param-file does/not/exist" 'no such file or directory' +os::cmd::expect_failure_and_text "oc new-app ruby-helloworld-sample --param-file ${TEST_DATA}" 'is a directory' +os::cmd::expect_success "oc new-app ruby-helloworld-sample --param-file /dev/null -o yaml" +os::cmd::expect_success "oc new-app ruby-helloworld-sample --param-file /dev/null --param-file ${param_file} -o yaml" +os::cmd::expect_failure_and_text "echo 'fo%(o=bar' | oc new-app ruby-helloworld-sample --param-file -" 'invalid parameter assignment' +os::cmd::expect_failure_and_text "echo 'S P A C E S=test' | oc new-app ruby-helloworld-sample --param-file -" 'invalid parameter assignment' + +os::cmd::expect_failure_and_text 'oc new-app ruby-helloworld-sample --param ABSENT_PARAMETER=absent -o yaml' 'unexpected parameter name' +os::cmd::expect_success 'oc new-app ruby-helloworld-sample --param ABSENT_PARAMETER=absent -o yaml --ignore-unknown-parameters' + +# check that we can set environment variables from env file +env_file="${TEST_DATA}/new-app/test-cmd-newapp-env.env" +os::cmd::expect_success_and_text "oc new-app php --env-file ${env_file} -o jsonpath='{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"SOME_VAR\")].value}'" 'envvarfromfile' +os::cmd::expect_success_and_text "oc new-app php --env-file ${env_file} --env SOME_VAR=fromcmdline -o jsonpath='{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"SOME_VAR\")].value}'" 'fromcmdline' +os::cmd::expect_success_and_text "oc new-app php --env-file ${env_file} --env SOME_VAR=fromcmdline -o yaml" 'ignoring value from file' +os::cmd::expect_success_and_text "cat ${env_file} | oc new-app php --env-file - -o jsonpath='{.items[?(@.kind==\"DeploymentConfig\")].spec.template.spec.containers[0].env[?(@.name==\"SOME_VAR\")].value}'" 'envvarfromfile' + +os::cmd::expect_failure_and_text "oc new-app php --env-file does/not/exist" 'no such file or directory' +os::cmd::expect_failure_and_text "oc new-app php --env-file ${TEST_DATA}/new-app" 'is a directory' +os::cmd::expect_success "oc new-app php --env-file /dev/null -o yaml" +os::cmd::expect_success "oc new-app php --env-file /dev/null --env-file ${env_file} -o yaml" +os::cmd::expect_failure_and_text "echo 'fo%(o=bar' | oc new-app php --env-file -" 'invalid parameter assignment' +os::cmd::expect_failure_and_text "echo 'S P A C E S=test' | oc new-app php --env-file -" 'invalid parameter assignment' + +# new-build +# check that env vars are not split on commas and warning is printed where they previously have +os::cmd::expect_success_and_text 'oc new-build --binary php --env X=Y,Z=W -o yaml' 'value: Y,Z=W' +os::cmd::expect_success_and_text 'oc new-build --binary php --env X=Y,Z=W -o yaml' 'no longer accepts comma-separated list' +os::cmd::expect_success_and_text 'oc new-build --binary php --env X=Y,Z,W -o yaml' 'value: Y,Z,W' +os::cmd::expect_success_and_not_text 'oc new-build --binary php --env X=Y,Z,W -o yaml' 'no longer accepts comma-separated list' +os::cmd::expect_success_and_not_text 'oc new-build --binary php --env X=Y -o yaml' 'no longer accepts comma-separated list' + +# new-build - load envvars from file +os::cmd::expect_success_and_text "oc new-build --binary php --env-file ${env_file} -o jsonpath='{.items[?(@.kind==\"BuildConfig\")].spec.strategy.sourceStrategy.env[?(@.name==\"SOME_VAR\")].value}'" 'envvarfromfile' +os::cmd::expect_success_and_text "oc new-build --binary php --env-file ${env_file} --env SOME_VAR=fromcmdline -o jsonpath='{.items[?(@.kind==\"BuildConfig\")].spec.strategy.sourceStrategy.env[?(@.name==\"SOME_VAR\")].value}'" 'fromcmdline' +os::cmd::expect_success_and_text "oc new-build --binary php --env-file ${env_file} --env SOME_VAR=fromcmdline -o yaml" 'ignoring value from file' +os::cmd::expect_success_and_text "cat ${env_file} | oc new-build --binary php --env-file ${env_file} -o jsonpath='{.items[?(@.kind==\"BuildConfig\")].spec.strategy.sourceStrategy.env[?(@.name==\"SOME_VAR\")].value}'" 'envvarfromfile' + +os::cmd::expect_failure_and_text "oc new-build --binary php --env-file does/not/exist" 'no such file or directory' +os::cmd::expect_failure_and_text "oc new-build --binary php --env-file ${TEST_DATA}/new-app" 'is a directory' +os::cmd::expect_success "oc new-build --binary php --env-file /dev/null -o yaml" +os::cmd::expect_success "oc new-build --binary php --env-file /dev/null --env-file ${env_file} -o yaml" +os::cmd::expect_failure_and_text "echo 'fo%(o=bar' | oc new-build --binary php --env-file -" 'invalid parameter assignment' +os::cmd::expect_failure_and_text "echo 'S P A C E S=test' | oc new-build --binary php --env-file -" 'invalid parameter assignment' + +# check that we can set environment variables from build-env file +build_env_file="${TEST_DATA}/new-app/test-cmd-newapp-build-env.env" + +os::cmd::expect_failure_and_text "oc new-app php --build-env-file does/not/exist" 'no such file or directory' +os::cmd::expect_failure_and_text "oc new-app php --build-env-file ${TEST_DATA}/new-app" 'is a directory' +os::cmd::expect_success "oc new-app php --build-env-file /dev/null -o yaml" +os::cmd::expect_success "oc new-app php --build-env-file /dev/null --build-env-file ${build_env_file} -o yaml" +os::cmd::expect_failure_and_text "echo 'fo%(o=bar' | oc new-app php --build-env-file -" 'invalid parameter assignment' +os::cmd::expect_failure_and_text "echo 'S P A C E S=test' | oc new-app php --build-env-file -" 'invalid parameter assignment' + +# new-build +# check that build env vars are not split on commas and warning is printed where they previously have +os::cmd::expect_success_and_text 'oc new-build --binary php --build-env X=Y,Z=W -o yaml' 'value: Y,Z=W' +os::cmd::expect_success_and_text 'oc new-build --binary php --build-env X=Y,Z=W -o yaml' 'no longer accepts comma-separated list' +os::cmd::expect_success_and_text 'oc new-build --binary php --build-env X=Y,Z,W -o yaml' 'value: Y,Z,W' +os::cmd::expect_success_and_not_text 'oc new-build --binary php --build-env X=Y,Z,W -o yaml' 'no longer accepts comma-separated list' +os::cmd::expect_success_and_not_text 'oc new-build --binary php --build-env X=Y -o yaml' 'no longer accepts comma-separated list' + +# new-build - load build env vars from file +os::cmd::expect_success_and_text "oc new-build --binary php --build-env-file ${build_env_file} -o jsonpath='{.items[?(@.kind==\"BuildConfig\")].spec.strategy.sourceStrategy.env[?(@.name==\"SOME_VAR\")].value}'" 'buildenvvarfromfile' +os::cmd::expect_success_and_text "oc new-build --binary php --build-env-file ${build_env_file} --env SOME_VAR=fromcmdline -o jsonpath='{.items[?(@.kind==\"BuildConfig\")].spec.strategy.sourceStrategy.env[?(@.name==\"SOME_VAR\")].value}'" 'fromcmdline' +os::cmd::expect_success_and_text "oc new-build --binary php --build-env-file ${build_env_file} --env SOME_VAR=fromcmdline -o yaml" 'ignoring value from file' +os::cmd::expect_success_and_text "cat ${build_env_file} | oc new-build --binary php --build-env-file - -o jsonpath='{.items[?(@.kind==\"BuildConfig\")].spec.strategy.sourceStrategy.env[?(@.name==\"SOME_VAR\")].value}'" 'buildenvvarfromfile' + +os::cmd::expect_failure_and_text "oc new-build --binary php --build-env-file does/not/exist" 'no such file or directory' +os::cmd::expect_failure_and_text "oc new-build --binary php --build-env-file ${TEST_DATA}/new-app" 'is a directory' +os::cmd::expect_success "oc new-build --binary php --build-env-file /dev/null -o yaml" +os::cmd::expect_success "oc new-build --binary php --build-env-file /dev/null --env-file ${build_env_file} -o yaml" +os::cmd::expect_failure_and_text "echo 'fo%(o=bar' | oc new-build --binary php --build-env-file -" 'invalid parameter assignment' +os::cmd::expect_failure_and_text "echo 'S P A C E S=test' | oc new-build --binary php --build-env-file -" 'invalid parameter assignment' + +# new-build - check that we can set build args in DockerStrategy +os::cmd::expect_success_and_text "oc new-build ${TEST_DATA}/new-app/build-arg-dockerfile --build-arg 'foo=bar' --to 'test' -o jsonpath='{.items[?(@.kind==\"BuildConfig\")].spec.strategy.dockerStrategy.buildArgs[?(@.name==\"foo\")].value}'" 'bar' + +# check that we cannot set build args in a non-DockerStrategy build +os::cmd::expect_failure_and_text "oc new-build https://github.com/openshift/ruby-hello-world --strategy=source --build-arg 'foo=bar'" "error: Cannot use '--build-arg' without a Docker build" +os::cmd::expect_failure_and_text "oc new-build https://github.com/sclorg/ruby-ex --build-arg 'foo=bar'" "error: Cannot use '--build-arg' without a Docker build" + +# +# verify we can create from a template when some objects in the template declare an app label +# the app label will not be applied to any objects in the template. +os::cmd::expect_success_and_not_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-app-label.json -o yaml' 'app: ruby-helloworld-sample' +# verify the existing app label on an object is not overridden by new-app +os::cmd::expect_success_and_text 'oc new-app -f ${TEST_DATA}/new-app/template-with-app-label.json -o yaml' 'app: myapp' + +# verify that a template can be passed in stdin +os::cmd::expect_success 'cat ${TEST_DATA}/application-template-stibuild.json | oc new-app -o yaml -f -' + +# check search +os::cmd::expect_success_and_text 'oc new-app --search mysql' "Tags:\s+5.7, latest" +os::cmd::expect_success_and_text 'oc new-app --search ruby-helloworld-sample' 'ruby-helloworld-sample' +# check search - partial matches +os::cmd::expect_success_and_text 'oc new-app --search ruby-hellow' 'ruby-helloworld-sample' +os::cmd::expect_success_and_text 'oc new-app --search --template=ruby-hel' 'ruby-helloworld-sample' +os::cmd::expect_success_and_text 'oc new-app --search --template=ruby-helloworld-sam -o yaml' 'ruby-helloworld-sample' +os::cmd::expect_success_and_text 'oc new-app --search rub' "Tags:\s+2.3, 2.4, 2.5, latest" +os::cmd::expect_success_and_text 'oc new-app --search --image-stream=rub' "Tags:\s+2.5, latest" +# check search - check correct usage of filters +os::cmd::expect_failure_and_not_text 'oc new-app --search --image-stream=ruby-heloworld-sample' 'application-template-stibuild' +os::cmd::expect_failure 'oc new-app --search --template=php' +os::cmd::expect_failure 'oc new-app -S --template=nodejs' +os::cmd::expect_failure 'oc new-app -S --template=perl' +# check search - filtered, exact matches +# make sure the imagestreams are imported first. +os::cmd::try_until_success 'oc get imagestreamtags mariadb:latest' +os::cmd::try_until_success 'oc get imagestreamtags mariadb:10.1' +os::cmd::try_until_success 'oc get imagestreamtags mariadb:10.2' +os::cmd::try_until_success 'oc get imagestreamtags mongodb:latest' +os::cmd::try_until_success 'oc get imagestreamtags mongodb:2.6' +os::cmd::try_until_success 'oc get imagestreamtags mongodb:3.2' +os::cmd::try_until_success 'oc get imagestreamtags mongodb:3.4' +os::cmd::try_until_success 'oc get imagestreamtags mysql:latest' +os::cmd::try_until_success 'oc get imagestreamtags mysql:5.6' +os::cmd::try_until_success 'oc get imagestreamtags mysql:5.7' +os::cmd::try_until_success 'oc get imagestreamtags nginx:latest' +os::cmd::try_until_success 'oc get imagestreamtags nginx:1.14' +os::cmd::try_until_success 'oc get imagestreamtags nginx:1.16' +os::cmd::try_until_success 'oc get imagestreamtags nodejs:latest' +os::cmd::try_until_success 'oc get imagestreamtags nodejs:10' +os::cmd::try_until_success 'oc get imagestreamtags nodejs:12' +os::cmd::try_until_success 'oc get imagestreamtags perl:latest' +os::cmd::try_until_success 'oc get imagestreamtags perl:5.24' +os::cmd::try_until_success 'oc get imagestreamtags perl:5.26' +os::cmd::try_until_success 'oc get imagestreamtags php:latest' +os::cmd::try_until_success 'oc get imagestreamtags php:7.0' +os::cmd::try_until_success 'oc get imagestreamtags php:7.1' +os::cmd::try_until_success 'oc get imagestreamtags postgresql:latest' +os::cmd::try_until_success 'oc get imagestreamtags postgresql:9.5' +os::cmd::try_until_success 'oc get imagestreamtags postgresql:9.6' +os::cmd::try_until_success 'oc get imagestreamtags python:latest' +os::cmd::try_until_success 'oc get imagestreamtags python:2.7' +os::cmd::try_until_success 'oc get imagestreamtags python:3.6' +os::cmd::try_until_success 'oc get imagestreamtags ruby:latest' +os::cmd::try_until_success 'oc get imagestreamtags ruby:2.7' +os::cmd::try_until_success 'oc get imagestreamtags wildfly:latest' +os::cmd::try_until_success 'oc get imagestreamtags wildfly:20.0' +os::cmd::try_until_success 'oc get imagestreamtags wildfly:21.0' + +os::cmd::expect_success_and_text 'oc new-app --search --image-stream=mariadb' "Tags:\s+10.1, 10.2, latest" +os::cmd::expect_success_and_text 'oc new-app --search --image-stream=mongodb' "Tags:\s+3.2, 3.4, latest" +os::cmd::expect_success_and_text 'oc new-app --search --image-stream=mysql' "Tags:\s+5.7, latest" +os::cmd::expect_success_and_text 'oc new-app --search --image-stream=nginx' "Tags:\s+1.14, 1.16, latest" +os::cmd::expect_success_and_text 'oc new-app --search --image-stream=nodejs' "Tags:\s+10, 12, latest" +os::cmd::expect_success_and_text 'oc new-app --search --image-stream=perl' "Tags:\s+5.24, 5.26, latest" +os::cmd::expect_success_and_text 'oc new-app --search --image-stream=php' "Tags:\s+7.0, 7.1, latest" +os::cmd::expect_success_and_text 'oc new-app --search --image-stream=postgresql' "Tags:\s+9.5, 9.6, latest" +os::cmd::expect_success_and_text 'oc new-app -S --image-stream=python' "Tags:\s+2.7, 3.6, latest" +os::cmd::expect_success_and_text 'oc new-app -S --image-stream=ruby' "Tags:\s+2.6, 2.7, latest" +os::cmd::expect_success_and_text 'oc new-app -S --image-stream=wildfly' "Tags:\s+20.0, 21.0, latest" +os::cmd::expect_success_and_text 'oc new-app --search --template=ruby-helloworld-sample' 'ruby-helloworld-sample' +# check search - no matches +os::cmd::expect_failure_and_text 'oc new-app -S foo-the-bar' 'no matches found' +os::cmd::expect_failure_and_text 'oc new-app --search winter-is-coming' 'no matches found' +# check search - mutually exclusive flags +os::cmd::expect_failure_and_text 'oc new-app -S mysql --env=FOO=BAR' "can't be used" +os::cmd::expect_failure_and_text 'oc new-app --search mysql --code=https://github.com/openshift/ruby-hello-world' "can't be used" +os::cmd::expect_failure_and_text 'oc new-app --search mysql --param=FOO=BAR' "can't be used" +# check specifying a non-existent template does not cause an index out of range error +os::cmd::expect_failure_and_not_text 'oc new-app --template foo' 'index out of range' -os::cmd::expect_success 'oc new-project quota-images --as=deads --as-group=system:authenticated --as-group=system:authenticated:oauth' -os::cmd::expect_success 'oc create quota -n quota-images is-quota --hard openshift.io/imagestreams=1' -os::cmd::try_until_success 'oc tag -n quota-images openshift/hello-openshift myis2:v2' -os::cmd::expect_failure_and_text 'oc tag -n quota-images busybox mybox:v1' "exceeded quota" -os::cmd::expect_failure_and_text 'oc import-image centos -n quota-images --from=docker.io/centos:latest --confirm=true' "exceeded quota" -os::cmd::expect_success 'oc delete project quota-images' +# set context-dir +os::cmd::expect_success_and_text 'oc new-app https://github.com/sclorg/s2i-ruby-container.git --context-dir="2.5/test/puma-test-app" -o yaml' 'contextDir: 2.5/test/puma-test-app' +os::cmd::expect_success_and_text 'oc new-app ruby~https://github.com/sclorg/s2i-ruby-container.git --context-dir="2.5/test/puma-test-app" -o yaml' 'contextDir: 2.5/test/puma-test-app' -echo "imagestreams: ok" -os::test::junit::declare_suite_end +# set strategy +os::cmd::expect_success_and_text 'oc new-app ruby~https://github.com/openshift/ruby-hello-world.git --strategy=docker -o yaml' 'dockerStrategy' +os::cmd::expect_success_and_text 'oc new-app https://github.com/openshift/ruby-hello-world.git --strategy=source -o yaml' 'sourceStrategy' -os::test::junit::declare_suite_end -`) +# prints root user info +os::cmd::expect_success_and_not_text 'oc new-app --dry-run mysql' "runs as the 'root' user" +os::cmd::expect_success_and_text 'oc new-app --dry-run --docker-image=mysql' "WARNING: Image \"mysql\" runs as the 'root' user" -func testExtendedTestdataCmdTestCmdQuotaShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdQuotaSh, nil -} +# verify multiple errors are displayed together, a nested error is returned, and that the usage message is displayed +os::cmd::expect_failure_and_text 'oc new-app --dry-run __template_fail __templatefile_fail' 'error: unable to locate any' +os::cmd::expect_failure_and_text 'oc new-app --dry-run __template_fail __templatefile_fail' 'with name "__templatefile_fail"' +os::cmd::expect_failure_and_text 'oc new-app --dry-run __template_fail __templatefile_fail' 'error: unable to find the specified template file' +os::cmd::expect_failure_and_text 'oc new-app --dry-run __template_fail __templatefile_fail' "The 'oc new-app' command will match arguments" -func testExtendedTestdataCmdTestCmdQuotaSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdQuotaShBytes() - if err != nil { - return nil, err - } +# verify partial match error +os::cmd::expect_failure_and_text 'oc new-app --dry-run mysq' 'error: only a partial match was found for "mysq"' +os::cmd::expect_failure_and_text 'oc new-app --dry-run mysq' 'The argument "mysq" only partially matched' +os::cmd::expect_failure_and_text 'oc new-app --dry-run mysq' "Image stream \"mysql\" \\(tag \"5.7\"\\) in project" - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/quota.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +# ensure new-app with pr ref does not fail +os::cmd::expect_success 'oc new-app https://github.com/openshift/ruby-hello-world#refs/pull/58/head --dry-run' -var _testExtendedTestdataCmdTestCmdRegistrySh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT +# verify image streams with no tags are reported correctly and that --allow-missing-imagestream-tags works +# new-app +os::cmd::expect_success 'printf "apiVersion: v1\nkind: ImageStream\nmetadata:\n name: emptystream\n" | oc create -f -' +os::cmd::expect_failure_and_text 'oc new-app --dry-run emptystream' 'error: no tags found on matching image stream' +os::cmd::expect_success 'oc new-app --dry-run emptystream --allow-missing-imagestream-tags' +# new-build +os::cmd::expect_failure_and_text 'oc new-build --dry-run emptystream~https://github.com/sclorg/ruby-ex' 'error: no tags found on matching image stream' +os::cmd::expect_success 'oc new-build --dry-run emptystream~https://github.com/sclorg/ruby-ex --allow-missing-imagestream-tags --strategy=source' -# Cleanup cluster resources created by this test -( - set +e - oc delete all --all - exit 0 -) &>/dev/null +# Allow setting --name when specifying grouping +os::cmd::expect_success "oc new-app mysql+ruby~https://github.com/sclorg/ruby-ex --name foo -o yaml" +# but not with multiple components +os::cmd::expect_failure_and_text "oc new-app mysql ruby~https://github.com/sclorg/ruby-ex --name foo -o yaml" "error: only one component or source repository can be used when specifying a name" +# do not allow specifying output image when specifying multiple input repos +os::cmd::expect_failure_and_text 'oc new-build https://github.com/sclorg/nodejs-ex https://github.com/sclorg/ruby-ex --to foo' 'error: only one component with source can be used when specifying an output image reference' +# but succeed with multiple input repos and no output image specified +os::cmd::expect_success 'oc new-build https://github.com/sclorg/nodejs-ex https://github.com/sclorg/ruby-ex -o yaml' +# check that binary build with a builder image results in a source type build +os::cmd::expect_success_and_text 'oc new-build --binary --image-stream=ruby -o yaml' 'type: Source' +# check that binary build with a specific strategy uses that strategy regardless of the image type +os::cmd::expect_success_and_text 'oc new-build --binary --image=ruby --strategy=docker -o yaml' 'type: Docker' +# When only a single imagestreamtag exists, and it does not match the implicit default +# latest tag, new-app should fail. +# when latest exists, we default to it and match it. +os::cmd::expect_success 'oc new-app --image-stream ruby https://github.com/sclorg/rails-ex --dry-run' +# when latest does not exist, there are multiple partial matches (2.5, 2.6) +os::cmd::expect_success 'oc delete imagestreamtag ruby:latest' +os::cmd::expect_failure_and_text 'oc new-app --image-stream ruby https://github.com/sclorg/rails-ex --dry-run' 'error: multiple images or templates matched \"ruby\"' +# when only 2.6 exists, there is a single partial match (2.6) +os::cmd::expect_success 'oc delete imagestreamtag ruby:2.7' +os::cmd::expect_failure_and_text 'oc new-app --image-stream ruby https://github.com/sclorg/rails-ex --dry-run' 'error: only a partial match was found for \"ruby\":' +# when the tag is specified explicitly, the operation is successful +os::cmd::expect_success 'oc new-app --image-stream ruby:2.7 https://github.com/sclorg/rails-ex --dry-run' +os::cmd::expect_success 'oc delete imagestreams --all' -os::test::junit::declare_suite_start "cmd/registry/login" -# TODO - re-enable these tests on a real cluster -#os::cmd::expect_success_and_text "oc registry login -z 'default' --registry=localhost:5000 --to=- --skip-check" "auth" -#os::cmd::expect_failure_and_text "oc registry login -z 'default' --registry=localhost2 --to=- 2>&1" "unable to check your credentials" -#os::cmd::expect_success_and_text "oc registry login -z 'default' --registry=localhost2 --to=/tmp/test --skip-check && cat /tmp/test" "localhost2" -os::test::junit::declare_suite_end +# newapp does not attempt to create an imagestream that already exists for a container image +os::cmd::expect_success_and_text 'oc new-app docker.io/ruby:latest~https://github.com/sclorg/ruby-ex.git --name=testapp1 --strategy=docker' 'imagestream.image.openshift.io "ruby" created' +# make sure the ruby:latest tag is imported before we run new-app again +os::cmd::try_until_success 'oc get imagestreamtags ruby:latest' +os::cmd::expect_success_and_not_text 'oc new-app docker.io/ruby:latest~https://github.com/sclorg/ruby-ex.git --name=testapp2 --strategy=docker' '"ruby:latest" already exists' +os::cmd::expect_success 'oc delete all -l app=testapp2' +os::cmd::expect_success 'oc delete all -l app=testapp1' +os::cmd::expect_success 'oc delete all -l app=ruby --ignore-not-found' +os::cmd::expect_success 'oc delete imagestreams --all --ignore-not-found' +# newapp does not attempt to create an imagestream that already exists for a container image +os::cmd::expect_success 'oc new-app docker.io/ruby:2.7' +# the next one technically fails cause the DC is already created, but we should still see the ist created +os::cmd::expect_failure_and_text 'oc new-app docker.io/ruby:2.7' 'imagestreamtag.image.openshift.io "ruby:2.7" created' +os::cmd::expect_success 'oc delete imagestreams --all --ignore-not-found' -os::test::junit::declare_suite_start "cmd/registry/info" -# TODO - re-enable these tests on a real cluster -#os::cmd::expect_success 'oc tag --source=docker openshift/origin-control-plane:latest newrepo:latest' -#os::cmd::expect_success "oc registry info" -#os::cmd::expect_failure_and_text "oc registry info --internal --public" "only one of --internal or --public" -os::test::junit::declare_suite_end -`) +# check that we can create from the template without errors +os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample -l app=helloworld' 'service "frontend" created' +os::cmd::expect_success 'oc delete all -l app=helloworld' +os::cmd::expect_success 'oc delete secret dbsecret' +os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample -l app=helloworld -o name' 'service/frontend' +os::cmd::expect_success 'oc delete all -l app=helloworld' +os::cmd::expect_success 'oc delete secret dbsecret' +os::cmd::expect_success 'oc delete template ruby-helloworld-sample' +# override component names +os::cmd::expect_success_and_text 'oc new-app mysql --name=db' 'db' +os::cmd::expect_success 'oc new-app https://github.com/openshift/ruby-hello-world -l app=ruby' +os::cmd::expect_success 'oc delete all -l app=ruby' +# check for error when template JSON file has errors +jsonfile="${TEST_DATA}/new-app/invalid.json" +os::cmd::expect_failure_and_text "oc new-app '${jsonfile}'" "error: unable to load template file \"${jsonfile}\": error parsing ${jsonfile}: json: line 0: invalid character '}' after object key" -func testExtendedTestdataCmdTestCmdRegistryShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdRegistrySh, nil -} +# check new-build +os::cmd::expect_failure_and_text 'oc new-build mysql -o yaml' 'you must specify at least one source repository URL' +os::cmd::expect_success_and_text 'oc new-build mysql --binary -o yaml --to mysql:bin' 'type: Binary' +os::cmd::expect_success_and_text 'oc new-build mysql https://github.com/openshift/ruby-hello-world --strategy=docker -o yaml' 'type: Docker' +os::cmd::expect_failure_and_text 'oc new-build mysql https://github.com/openshift/ruby-hello-world --binary' 'specifying binary builds and source repositories at the same time is not allowed' +# binary builds cannot be created unless a builder image is specified. +os::cmd::expect_failure_and_text 'oc new-build --name mybuild --binary --strategy=source -o yaml' 'you must provide a builder image when using the source strategy with a binary build' +os::cmd::expect_success_and_text 'oc new-build --name mybuild registry.centos.org/centos/ruby-27-centos7 --binary --strategy=source -o yaml' 'name: ruby-27-centos7:latest' +# binary builds can be created with no builder image if no strategy or docker strategy is specified +os::cmd::expect_success_and_text 'oc new-build --name mybuild --binary -o yaml' 'type: Binary' +os::cmd::expect_success_and_text 'oc new-build --name mybuild --binary --strategy=docker -o yaml' 'type: Binary' -func testExtendedTestdataCmdTestCmdRegistrySh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdRegistryShBytes() - if err != nil { - return nil, err - } +# new-build image source tests +os::cmd::expect_failure_and_text 'oc new-build mysql --source-image centos' 'error: --source-image-path must be specified when --source-image is specified.' +os::cmd::expect_failure_and_text 'oc new-build mysql --source-image-path foo' 'error: --source-image must be specified when --source-image-path is specified.' - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/registry.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +# ensure circular ref flagged but allowed for template +os::cmd::expect_success 'oc create -f ${TEST_DATA}/new-app/circular-is.yaml' +os::cmd::expect_success_and_text 'oc new-app -f ${TEST_DATA}/new-app/circular.yaml' 'should be different than input' +# ensure circular does not choke on image stream image +os::cmd::expect_success_and_not_text 'oc new-app -f ${TEST_DATA}/new-app/bc-from-imagestreamimage.json --dry-run' 'Unable to follow reference type' -var _testExtendedTestdataCmdTestCmdRoutesSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT +# do not allow use of non-existent image (should fail) +os::cmd::expect_failure_and_text 'oc new-app openshift/bogusimage https://github.com/openshift/ruby-hello-world.git -o yaml' "unable to locate any" +# allow use of non-existent image (should succeed) +os::cmd::expect_success 'oc new-app openshift/bogusimage https://github.com/openshift/ruby-hello-world.git -o yaml --allow-missing-images' -# Cleanup cluster resources created by this test -( - set +e - oc delete route foo bar testroute test-route new-route - exit 0 -) &>/dev/null +os::cmd::expect_success 'oc create -f ${TEST_DATA}/new-app/installable-stream.yaml' +os::cmd::expect_success 'oc policy add-role-to-user edit test-user' +os::cmd::expect_success 'oc login -u test-user -p anything' +os::cmd::try_until_success 'oc project ${default_project}' -os::test::junit::declare_suite_start "cmd/routes" +os::cmd::try_until_success 'oc get imagestreamtags installable:file' +os::cmd::try_until_success 'oc get imagestreamtags installable:token' +os::cmd::try_until_success 'oc get imagestreamtags installable:serviceaccount' +os::cmd::expect_failure 'oc new-app installable:file' +os::cmd::expect_failure_and_text 'oc new-app installable:file' 'requires that you grant the image access' +os::cmd::expect_failure_and_text 'oc new-app installable:serviceaccount' "requires an 'installer' service account with project editor access" +os::cmd::expect_success_and_text 'oc new-app installable:file --grant-install-rights -o yaml' '/var/run/openshift.secret.token' +os::cmd::expect_success_and_text 'oc new-app installable:file --grant-install-rights -o yaml' 'activeDeadlineSeconds: 14400' +os::cmd::expect_success_and_text 'oc new-app installable:file --grant-install-rights -o yaml' 'openshift.io/generated-job: "true"' +os::cmd::expect_success_and_text 'oc new-app installable:file --grant-install-rights -o yaml' 'openshift.io/generated-job.for: installable:file' +os::cmd::expect_success_and_text 'oc new-app installable:token --grant-install-rights -o yaml' 'name: TOKEN_ENV' +os::cmd::expect_success_and_text 'oc new-app installable:token --grant-install-rights -o yaml' 'openshift/origin@sha256:' +os::cmd::expect_success_and_text 'oc new-app installable:serviceaccount --grant-install-rights -o yaml' 'serviceAccountName: installer' +os::cmd::expect_success_and_text 'oc new-app installable:serviceaccount --grant-install-rights -o yaml' 'fieldPath: metadata.namespace' +os::cmd::expect_success_and_text 'oc new-app installable:serviceaccount --grant-install-rights -o yaml A=B' 'name: A' -os::cmd::expect_success 'oc get routes' -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-route.json' -os::cmd::expect_success_and_text 'oc get routes testroute --show-labels' 'rtlabel1' -os::cmd::expect_success 'oc delete routes testroute' -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-service.json' -os::cmd::expect_success 'oc create route passthrough --service=svc/frontend' -os::cmd::expect_success 'oc delete routes frontend' -os::cmd::expect_success 'oc create route edge --path /test --service=services/non-existent --port=80' -os::cmd::expect_success 'oc delete routes non-existent' -os::cmd::expect_success 'oc create route edge test-route --service=frontend' -os::cmd::expect_success 'oc delete routes test-route' -os::cmd::expect_failure 'oc create route edge new-route' -os::cmd::expect_success 'oc delete services frontend' -os::cmd::expect_success 'oc create route edge --insecure-policy=Allow --service=foo --port=80' -os::cmd::expect_success_and_text 'oc get route foo -o jsonpath="{.spec.tls.insecureEdgeTerminationPolicy}"' 'Allow' -os::cmd::expect_success 'oc delete routes foo' +# Ensure output is valid JSON +os::cmd::expect_success 'oc new-app mongo -o json | python -m json.tool' -os::cmd::expect_success_and_text 'oc create route edge --service foo --port=8080' 'created' -os::cmd::expect_success_and_text 'oc create route edge --service bar --port=9090' 'created' +# Ensure custom branch/ref works +os::cmd::expect_success 'oc new-app https://github.com/openshift/ruby-hello-world#beta4' -# verify that reencrypt routes with no destination CA return the stub PEM block on the old API -project="$(oc project -q)" -os::cmd::expect_success_and_text 'oc create route reencrypt --service baz --port=9090' 'created' -os::cmd::expect_success_and_not_text 'oc get --raw /apis/route.openshift.io/v1/namespaces/${project}/routes/baz' 'This is an empty PEM file' +# Ensure the resulting BuildConfig doesn't have unexpected sources +os::cmd::expect_success_and_not_text 'oc new-app https://github.com/openshift/ruby-hello-world --output-version=v1 -o=jsonpath="{.items[?(@.kind==\"BuildConfig\")].spec.source}"' 'dockerfile|binary' -os::cmd::expect_success_and_text 'oc set route-backends foo' 'routes/foo' -os::cmd::expect_success_and_text 'oc set route-backends foo' 'Service' -os::cmd::expect_success_and_text 'oc set route-backends foo' '100' -os::cmd::expect_failure_and_text 'oc set route-backends foo --zero --equal' 'error: --zero and --equal may not be specified together' -os::cmd::expect_failure_and_text 'oc set route-backends foo --zero --adjust' 'error: --adjust and --zero may not be specified together' -os::cmd::expect_failure_and_text 'oc set route-backends foo a=' 'expected NAME=WEIGHT' -os::cmd::expect_failure_and_text 'oc set route-backends foo =10' 'expected NAME=WEIGHT' -os::cmd::expect_failure_and_text 'oc set route-backends foo a=a' 'WEIGHT must be a number' -os::cmd::expect_success_and_text 'oc set route-backends foo a=10' 'updated' -os::cmd::expect_success_and_text 'oc set route-backends foo a=100' 'updated' -os::cmd::expect_success_and_text 'oc set route-backends foo a=0' 'updated' -os::cmd::expect_success_and_text 'oc set route-backends foo' '0' -os::cmd::expect_success_and_text 'oc get routes foo' 'a' -os::cmd::expect_success_and_text 'oc set route-backends foo a1=0 b2=0' 'updated' -os::cmd::expect_success_and_text 'oc set route-backends foo' 'a1' -os::cmd::expect_success_and_text 'oc set route-backends foo' 'b2' -os::cmd::expect_success_and_text 'oc set route-backends foo a1=100 b2=50 c3=0' 'updated' -os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(66%\),b2\(33%\),c3\(0%\)' -os::cmd::expect_success_and_text 'oc set route-backends foo a1=100 b2=0 c3=0' 'updated' -os::cmd::expect_success_and_text 'oc set route-backends foo --adjust b2=+10%' 'updated' -os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(90%\),b2\(10%\),c3\(0%\)' -os::cmd::expect_success_and_text 'oc set route-backends foo --adjust b2=+25%' 'updated' -os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(65%\),b2\(35%\),c3\(0%\)' -os::cmd::expect_success_and_text 'oc set route-backends foo --adjust b2=+99%' 'updated' -os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(0%\),b2\(100%\),c3\(0%\)' -os::cmd::expect_success_and_text 'oc set route-backends foo --adjust b2=-51%' 'updated' -os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(51%\),b2\(49%\),c3\(0%\)' -os::cmd::expect_success_and_text 'oc set route-backends foo --adjust a1=20%' 'updated' -os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(20%\),b2\(80%\),c3\(0%\)' -os::cmd::expect_success_and_text 'oc set route-backends foo --adjust c3=50%' 'updated' -os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(10%\),b2\(80%\),c3\(10%\)' -os::cmd::expect_success_and_text 'oc describe routes foo' '25 \(10%\)' -os::cmd::expect_success_and_text 'oc describe routes foo' '200 \(80%\)' -os::cmd::expect_success_and_text 'oc describe routes foo' '25 \(10%\)' -os::cmd::expect_success_and_text 'oc describe routes foo' '' -os::cmd::expect_success_and_text 'oc set route-backends foo --adjust c3=1' 'updated' -os::cmd::expect_success_and_text 'oc describe routes foo' '1 \(0%\)' -os::cmd::expect_success_and_text 'oc set route-backends foo --equal' 'updated' -os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(33%\),b2\(33%\),c3\(33%\)' -os::cmd::expect_success_and_text 'oc describe routes foo' '100 \(33%\)' -os::cmd::expect_success_and_text 'oc set route-backends foo --zero' 'updated' -os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(0%\),b2\(0%\),c3\(0%\)' -os::cmd::expect_success_and_text 'oc describe routes foo' '0' +# We permit running new-app against a remote URL which returns a template +os::cmd::expect_success 'oc new-app https://raw.githubusercontent.com/openshift/origin/master/examples/quickstarts/rails-postgresql.json --dry-run' -os::test::junit::declare_suite_end -`) +# ensure that --strategy sets the build strategy +os::cmd::expect_success_and_text 'oc new-build --name sourcetest python~https://github.com/sclorg/django-ex --source-image registry.centos.org/centos/centos:latest --source-image-path /tmp --strategy source --dry-run -o yaml' 'sourceStrategy' +os::cmd::expect_success_and_text 'oc new-build --name sourcetest python~https://github.com/sclorg/django-ex --source-image registry.centos.org/centos/centos:latest --source-image-path /tmp --strategy pipeline --dry-run -o yaml' 'jenkinsPipelineStrategy' +os::cmd::expect_success_and_text 'oc new-build --name sourcetest python~https://github.com/sclorg/django-ex --source-image registry.centos.org/centos/centos:latest --source-image-path /tmp --strategy docker --dry-run -o yaml' 'dockerStrategy' -func testExtendedTestdataCmdTestCmdRoutesShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdRoutesSh, nil -} +os::cmd::expect_success 'oc create -f ${TEST_DATA}/image-streams/image-streams-centos7.json' +os::cmd::try_until_success 'oc get imagestreamtags nodejs:latest' +# ensure that a build can be created with just image inputs without the --binary flag +os::cmd::expect_success_and_text 'oc new-build --name sourcetest --source-image registry.centos.org/centos/centos:latest --source-image-path /tmp --image-stream nodejs --dry-run -o yaml' 'sourceStrategy' +# ensure that using only image inputs and the --binary flag results in an error +os::cmd::expect_failure_and_text 'oc new-build --name sourcetest --source-image registry.centos.org/centos/centos:latest --source-image-path /tmp --image-stream nodejs --binary --dry-run -o yaml' 'specifying binary builds and source repositories at the same time is not allowed' +os::cmd::expect_success 'oc delete imagestreams --all --ignore-not-found' -func testExtendedTestdataCmdTestCmdRoutesSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdRoutesShBytes() - if err != nil { - return nil, err - } +# new-app different syntax for new-app functionality +os::cmd::expect_success 'oc new-project new-app-syntax' +os::cmd::expect_success 'oc import-image registry.centos.org/centos/ruby-27-centos7:latest --confirm' +os::cmd::expect_success 'oc import-image registry.centos.org/centos/php-70-centos7:latest --confirm' +os::cmd::expect_success 'oc new-app ruby-27-centos7:latest~https://github.com/openshift/ruby-hello-world.git --dry-run' +os::cmd::expect_success 'oc new-app ruby-27-centos7:latest~./test/testdata/testapp --dry-run' +os::cmd::expect_success 'oc new-app -i ruby-27-centos7:latest https://github.com/openshift/ruby-hello-world.git --dry-run' +os::cmd::expect_success 'oc new-app -i ruby-27-centos7:latest ./test/testdata/testapp --dry-run' +os::cmd::expect_success 'oc new-app ruby-27-centos7:latest --code https://github.com/openshift/ruby-hello-world.git --dry-run' +os::cmd::expect_success 'oc new-app ruby-27-centos7:latest --code ./test/testdata/testapp --dry-run' +os::cmd::expect_success 'oc new-app -i ruby-27-centos7:latest --code https://github.com/openshift/ruby-hello-world.git --dry-run' +os::cmd::expect_success 'oc new-app -i ruby-27-centos7:latest --code ./test/testdata/testapp --dry-run' - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/routes.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +os::cmd::expect_success 'oc new-app --code ./test/testdata/testapp --name test' +os::cmd::expect_success_and_text 'oc get bc test --template={{.spec.strategy.dockerStrategy.from.name}}' 'ruby-27-centos7:latest' -var _testExtendedTestdataCmdTestCmdRsyncSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT +os::cmd::expect_success 'oc new-app -i php-70-centos7:latest --code ./test/testdata/testapp --name test2' +os::cmd::expect_success_and_text 'oc get bc test2 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-70-centos7:latest' -# Cleanup cluster resources created by this test -( - set +e - oc delete all --all - exit 0 -) &>/dev/null +os::cmd::expect_success 'oc new-app -i php-70-centos7:latest~https://github.com/openshift/ruby-hello-world.git --name test3' +os::cmd::expect_success_and_text 'oc get bc test3 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-70-centos7:latest' -os::test::junit::declare_suite_start "cmd/rsync" -# This test validates the rsync command -os::cmd::expect_success 'oc create -f - << __EOF__ -apiVersion: v1 -kind: Pod -metadata: - name: valid-pod - labels: - name: valid-pod -spec: - containers: - - name: kubernetes-serve-hostname - image: k8s.gcr.io/serve_hostname - resources: - limits: - cpu: "1" - memory: 512Mi -__EOF__' +os::cmd::expect_success 'oc new-app php-70-centos7:latest~https://github.com/openshift/ruby-hello-world.git --name test4' +os::cmd::expect_success_and_text 'oc get bc test4 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-70-centos7:latest' -temp_dir=$(mktemp -d) -include_file=$(mktemp -p $temp_dir) -exclude_file=$(mktemp -p $temp_dir) +os::cmd::expect_success 'oc new-app -i php-70-centos7:latest https://github.com/openshift/ruby-hello-world.git --name test5' +os::cmd::expect_success_and_text 'oc get bc test5 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-70-centos7:latest' -# we don't actually have a kubelet running, so no "tar" binary will be available in container because there will be no container. -# instead, ensure that the tar command to be executed is formatted correctly based on our --include and --exclude values -os::cmd::expect_failure_and_text "oc rsync --strategy=tar --include=$include_file --exclude=$exclude_file $temp_dir valid-pod:/tmp --loglevel 4" "running command: tar.*\*\*\/$include_file.*--exclude=$exclude_file" +os::cmd::expect_success 'oc new-app php-70-centos7:latest --code https://github.com/openshift/ruby-hello-world.git --name test6' +os::cmd::expect_success_and_text 'oc get bc test6 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-70-centos7:latest' -echo "rsync: ok" -os::test::junit::declare_suite_end -`) +os::cmd::expect_success 'oc new-app https://github.com/openshift/ruby-hello-world.git --name test7' +os::cmd::expect_success_and_text 'oc get bc test7 --template={{.spec.strategy.dockerStrategy.from.name}}' 'ruby-27-centos7:latest' -func testExtendedTestdataCmdTestCmdRsyncShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdRsyncSh, nil -} +os::cmd::expect_success 'oc new-app php-70-centos7:latest https://github.com/openshift/ruby-hello-world.git --name test8' +os::cmd::expect_success_and_text 'oc get bc test8 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-70-centos7:latest' +os::cmd::expect_success 'oc delete project new-app-syntax' -func testExtendedTestdataCmdTestCmdRsyncSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdRsyncShBytes() - if err != nil { - return nil, err - } +# new-app docker build strategy with binary input +os::cmd::expect_success 'oc project ${default_project}' +os::cmd::expect_success 'oc delete all,templates --all' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/image-streams/image-streams-centos7.json' +os::cmd::try_until_success 'oc get imagestreamtags ruby:latest' # need to wait until tags are available!? +os::cmd::expect_failure_and_text 'oc new-app --strategy=docker --name my-docker-app' 'none of the arguments provided could be classified as a source code location' +os::cmd::expect_success_and_text 'oc new-app --strategy=docker --binary --name my-docker-app' 'A binary build was created' +os::cmd::expect_success_and_text 'oc get bc my-docker-app -o yaml' 'type: Binary' +os::cmd::expect_success 'oc delete all -l app=my-docker-app' - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/rsync.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +# new-app source build strategy with binary input +os::cmd::expect_success_and_text 'oc new-app ruby --binary --name my-imagestream-app' 'A binary build was created' +os::cmd::expect_success_and_text 'oc get bc my-imagestream-app -o yaml' 'type: Binary' +os::cmd::expect_success 'oc delete all -l app=my-imagestream-app' -var _testExtendedTestdataCmdTestCmdRunSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT +# new-app with source repository and binary input +os::cmd::expect_failure_and_text 'oc new-app ./test/testdata/testapp --binary' 'error: specifying binary builds and source repositories at the same time is not allowed' -os::test::junit::declare_suite_start "cmd/run" -# This test validates the value of --image for oc run -os::cmd::expect_success_and_text 'oc create deploymentconfig newdcforimage --image=validimagevalue' 'deploymentconfig.apps.openshift.io/newdcforimage created' -os::cmd::expect_failure_and_text 'oc run newdcforimage2 --image="InvalidImageValue0192"' 'error: Invalid image name "InvalidImageValue0192": invalid reference format' -echo "oc run: ok" +echo "new-app: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdRunShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdRunSh, nil +func testExtendedTestdataCmdTestCmdNewappShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdNewappSh, nil } -func testExtendedTestdataCmdTestCmdRunSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdRunShBytes() +func testExtendedTestdataCmdTestCmdNewappSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdNewappShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/run.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/newapp.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdSecretsSh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdPolicySh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT -# Cleanup cluster resources created by this test -( - set +e - oc delete all,templates,secrets --all - exit 0 -) &>/dev/null - - -os::test::junit::declare_suite_start "cmd/secrets" -# This test validates secret interaction -touch Makefile -os::cmd::expect_success 'oc create secret generic foo --type=blah --from-file=makefile=Makefile' -os::cmd::expect_success_and_text 'oc get secrets/foo -o jsonpath={.type}' 'blah' - -os::cmd::expect_success 'oc create secret docker-registry dockerconfigjson --docker-username=sample-user --docker-password=sample-password --docker-email=fake@example.org' -# can't use a go template here because the output needs to be base64 decoded. base64 isn't installed by default in all distros -os::cmd::expect_success "oc get secrets/dockerconfigjson -o jsonpath='{ .data.\.dockerconfigjson }' | base64 -d > ${HOME}/dockerconfigjson" -os::cmd::expect_success 'oc create secret generic from-file --from-file=.dockerconfigjson=${HOME}/dockerconfigjson --type=kubernetes.io/dockerconfigjson' -# check to make sure the type was correctly auto-detected -os::cmd::expect_success_and_text 'oc get secret/from-file --template="{{ .type }}"' 'kubernetes.io/dockerconfigjson' -# make sure the -o works correctly -os::cmd::expect_success_and_text 'oc create secret docker-registry dockerconfigjson --docker-username=sample-user --docker-password=sample-password --docker-email=fake@example.org --dry-run -o yaml' 'kubernetes.io/dockerconfigjson' -os::cmd::expect_success_and_text 'oc create secret generic from-file-again --from-file=.dockerconfigjson=${HOME}/dockerconfigjson --type=kubernetes.io/dockerconfigjson -o yaml' 'kubernetes.io/dockerconfigjson' -# check to make sure malformed names fail as expected -os::cmd::expect_failure_and_text 'oc create secret generic bad-name --from-file=.docker=cfg=${HOME}/dockerconfigjson' "error: Key names or file paths cannot contain '='" - -workingdir="$( mktemp -d )" -os::cmd::try_until_success "oc get secret/dockerconfigjson" -os::cmd::expect_success_and_text "oc extract secret/dockerconfigjson --to '${workingdir}'" '.dockerconfigjson' -os::cmd::expect_success_and_text "oc extract secret/dockerconfigjson --to=-" 'sample-user' -os::cmd::expect_success_and_text "oc extract secret/dockerconfigjson --to=-" 'sample-password' -os::cmd::expect_success_and_text "cat '${workingdir}/.dockerconfigjson'" 'sample-user' -os::cmd::expect_failure_and_text "oc extract secret/dockerconfigjson --to '${workingdir}'" 'error: .dockerconfigjson: file exists, pass --confirm to overwrite' -os::cmd::expect_failure_and_text "oc extract secret/dockerconfigjson secret/dockerconfigjson --to '${workingdir}'" 'error: .dockerconfigjson: file exists, pass --confirm to overwrite' -os::cmd::expect_success_and_text "oc extract secret/dockerconfigjson secret/dockerconfigjson --to '${workingdir}' --confirm" '.dockerconfigjson' -os::cmd::expect_success_and_text "oc extract secret/dockerconfigjson --to '${workingdir}' --confirm" '.dockerconfigjson' -os::cmd::expect_success "oc extract secret/dockerconfigjson --to '${workingdir}' --confirm | xargs rm" -os::cmd::expect_failure_and_text "oc extract secret/dockerconfigjson --to missing-dir" "stat missing-dir: no such file or directory" - -# attach secrets to service account -# single secret with prefix -os::cmd::expect_success 'oc secrets link deployer dockerconfigjson' -# don't add the same secret twice -os::cmd::expect_success 'oc secrets link serviceaccounts/deployer dockerconfigjson secrets/from-file' -# make sure we can add as as pull secret -os::cmd::expect_success 'oc secrets link deployer dockerconfigjson from-file --for=pull' -# make sure we can add as as pull secret and mount secret at once -os::cmd::expect_success 'oc secrets link serviceaccounts/deployer secrets/dockerconfigjson secrets/from-file --for=pull,mount' +project="$( oc project -q )" +testpod="apiVersion: v1 +kind: Pod +metadata: + name: testpod +spec: + containers: + - image: node + imagePullPolicy: IfNotPresent + name: testpod + volumes: + - emptyDir: {} + name: tmp" -GIT_CONFIG_PATH="${ARTIFACT_DIR}/.gitconfig" -touch "${GIT_CONFIG_PATH}" -#git config --file "${GIT_CONFIG_PATH}" user.name sample-user -#git config --file "${GIT_CONFIG_PATH}" user.token password +os::test::junit::declare_suite_start "cmd/policy" +# This test validates user level policy +os::cmd::expect_success_and_text 'oc whoami --as deads' "deads" -function create_valid_file() { - echo test_data > "${ARTIFACT_DIR}/${1}" - echo "${ARTIFACT_DIR}/${1}" -} +os::cmd::expect_success 'oc adm policy add-cluster-role-to-user sudoer wheel' +os::cmd::try_until_text 'oc policy who-can impersonate users system:admin' "wheel" +os::cmd::try_until_text 'oc policy who-can impersonate groups system:masters' "wheel" +os::cmd::try_until_text 'oc policy who-can impersonate systemusers system:admin' "wheel" +os::cmd::try_until_text 'oc policy who-can impersonate systemgroups system:masters' "wheel" +os::cmd::expect_success 'oc login -u wheel -p pw' +os::cmd::expect_success_and_text 'oc whoami' "wheel" +os::cmd::expect_failure 'oc whoami --as deads' +os::cmd::expect_success_and_text 'oc whoami --as=system:admin' "system:admin" +os::cmd::expect_success_and_text 'oc auth can-i --list --as=system:admin' '.*' -CA_CERT_PATH=$(create_valid_file ca.pem) -PRIVATE_KEY_PATH=$(create_valid_file id_rsa) +os::cmd::expect_success 'oc login -u local-admin -p pw' +os::cmd::expect_success 'oc new-project policy-login' +os::cmd::expect_failure 'oc whoami --as=system:admin' +os::cmd::expect_success_and_text 'oc whoami --as=system:serviceaccount:policy-login:default' "system:serviceaccount:policy-login:default" +os::cmd::expect_failure 'oc whoami --as=system:serviceaccount:another:default' +os::cmd::expect_success "oc login -u system:admin -n '${project}'" +os::cmd::expect_success 'oc delete project policy-login' -os::cmd::expect_success "oc create secret generic basicauth --type=kubernetes.io/basic-auth --from-literal=username=sample-user --from-literal=password=sample-password --from-file=gitconfig='${GIT_CONFIG_PATH}' --from-file=ca-cert='${CA_CERT_PATH}'" -# check to make sure incorrect .gitconfig path fail as expected -os::cmd::expect_failure_and_text 'oc create secret generic bad-file --type=kubernetes.io/basic-auth --from-literal=username=user --from-file=gitconfig=/bad/path' 'error reading /bad/path: no such file or directory' +# validate --serviceaccount values +os::cmd::expect_success_and_text 'oc policy add-role-to-user admin -z default' 'clusterrole.rbac.authorization.k8s.io/admin added: "default"' +os::cmd::expect_failure_and_text 'oc policy add-role-to-user admin -z system:serviceaccount:test:default' 'should only be used with short\-form serviceaccount names' +os::cmd::expect_failure_and_text 'oc policy add-role-to-user admin -z :invalid' '"\:invalid" is not a valid serviceaccount name' -os::cmd::expect_success "oc create secret generic sshauth --from-file=ssh-privatekey='${PRIVATE_KEY_PATH}' --from-file=ca-cert='${CA_CERT_PATH}'" -# check to make sure incorrect SSH private-key path fail as expected -os::cmd::expect_failure_and_text 'oc create secret generic bad-file --from-file=ssh-privatekey=/bad/path' 'error reading /bad/path: no such file or directory' +# This test validates user level policy +os::cmd::expect_failure_and_text 'oc policy add-role-to-user' 'you must specify a role' +os::cmd::expect_failure_and_text 'oc policy add-role-to-user -z NamespaceWithoutRole' 'you must specify a role' +os::cmd::expect_failure_and_text 'oc policy add-role-to-user view' 'you must specify at least one user or service account' -# attach secrets to service account -# single secret with prefix -os::cmd::expect_success 'oc secrets link deployer basicauth' -# don't add the same secret twice -os::cmd::expect_success 'oc secrets link deployer basicauth sshauth' -# make sure we can add as as pull secret -os::cmd::expect_success 'oc secrets link deployer basicauth sshauth --for=pull' -# make sure we can add as as pull secret and mount secret at once -os::cmd::expect_success 'oc secrets link deployer basicauth sshauth --for=pull,mount' +os::cmd::expect_success_and_text 'oc policy add-role-to-group cluster-admin --rolebinding-name cluster-admin system:unauthenticated' 'clusterrole.rbac.authorization.k8s.io/cluster-admin added: "system:unauthenticated"' +os::cmd::expect_success_and_text 'oc policy add-role-to-user --rolebinding-name cluster-admin cluster-admin system:no-user' 'clusterrole.rbac.authorization.k8s.io/cluster-admin added: "system:no-user"' +os::cmd::expect_success 'oc get rolebinding/cluster-admin --no-headers' +os::cmd::expect_success_and_text 'oc get rolebinding/cluster-admin --no-headers' 'system:no-user' -# attach secrets to service account -# test that those secrets can be unlinked -# after they have been deleted. -os::cmd::expect_success 'oc create secret generic deleted-secret' -os::cmd::expect_success 'oc secrets link deployer deleted-secret' -# confirm our soon-to-be-deleted secret has been linked -os::cmd::expect_success_and_text "oc get serviceaccount deployer -o jsonpath='{.secrets[?(@.name==\"deleted-secret\")]}'" 'deleted\-secret' -# delete "deleted-secret" and attempt to unlink from service account -os::cmd::expect_success 'oc delete secret deleted-secret' -os::cmd::expect_failure_and_text 'oc secrets unlink deployer secrets/deleted-secret' 'Unlinked deleted secrets' -# ensure already-deleted secret has been unlinked -os::cmd::expect_success_and_not_text "oc get serviceaccount deployer -o jsonpath='{.secrets[?(@.name==\"deleted-secret\")]}'" 'deleted\-secret' +os::cmd::expect_success_and_text 'oc policy add-role-to-user --rolebinding-name cluster-admin cluster-admin -z=one,two --serviceaccount=three,four' 'clusterrole.rbac.authorization.k8s.io/cluster-admin added: \["one" "two" "three" "four"\]' +os::cmd::expect_success 'oc get rolebinding/cluster-admin --no-headers' +os::cmd::expect_success_and_text 'oc get rolebinding/cluster-admin --no-headers' 'one' +os::cmd::expect_success_and_text 'oc get rolebinding/cluster-admin --no-headers' 'four' -# attach secrets to service account -# single secret with prefix -os::cmd::expect_success 'oc secrets link deployer basicauth' -# don't add the same secret twice -os::cmd::expect_success 'oc secrets link deployer basicauth sshauth' -# make sure we can add as as pull secret -os::cmd::expect_success 'oc secrets link deployer basicauth sshauth --for=pull' -# make sure we can add as as pull secret and mount secret at once -os::cmd::expect_success 'oc secrets link deployer basicauth sshauth --for=pull,mount' +os::cmd::expect_success_and_text 'oc policy remove-role-from-group --rolebinding-name cluster-admin cluster-admin system:unauthenticated' 'clusterrole.rbac.authorization.k8s.io/cluster-admin removed: "system:unauthenticated"' -# Confirm that all the linked secrets are present -os::cmd::expect_success 'oc get serviceaccounts/deployer -o yaml |grep -q basicauth' -os::cmd::expect_success 'oc get serviceaccounts/deployer -o yaml |grep -q sshauth' +os::cmd::expect_success_and_text 'oc policy remove-role-from-user --rolebinding-name cluster-admin cluster-admin system:no-user' 'clusterrole.rbac.authorization.k8s.io/cluster-admin removed: "system:no-user"' +os::cmd::expect_success_and_text 'oc policy remove-role-from-user --rolebinding-name cluster-admin cluster-admin -z=one,two --serviceaccount=three,four' 'clusterrole.rbac.authorization.k8s.io/cluster-admin removed: \["one" "two" "three" "four"\]' +os::cmd::expect_failure_and_text 'oc get rolebinding/cluster-admin --no-headers' 'NotFound' -# Remove secrets from service account -os::cmd::expect_success 'oc secrets unlink deployer basicauth' -# Confirm that the secret was removed -os::cmd::expect_failure 'oc get serviceaccounts/deployer -o yaml |grep -q basicauth' +os::cmd::expect_success 'oc policy remove-group system:unauthenticated' +os::cmd::expect_success 'oc policy remove-user system:no-user' -# Re-link that secret -os::cmd::expect_success 'oc secrets link deployer basicauth' +# Test failure to mix and mismatch role/rolebiding removal +os::cmd::expect_success 'oc login -u local-admin -p pw' +os::cmd::expect_success 'oc new-project mismatch-prj' +os::cmd::expect_success 'oc create rolebinding match --clusterrole=admin --user=user' +os::cmd::expect_success 'oc create rolebinding mismatch --clusterrole=edit --user=user' +os::cmd::expect_failure_and_text 'oc policy remove-role-from-user admin user --rolebinding-name mismatch' 'rolebinding mismatch' +os::cmd::expect_success_and_text 'oc policy remove-user user' 'user' +os::cmd::expect_failure_and_text 'oc get rolebinding mismatch --no-headers' 'NotFound' +os::cmd::expect_failure_and_text 'oc get rolebinding match --no-headers' 'NotFound' +os::cmd::expect_success "oc login -u system:admin -n '${project}'" +os::cmd::expect_success 'oc delete project mismatch-prj' -# Removing a non-existent secret should warn but succeed and change nothing -os::cmd::expect_failure_and_text 'oc secrets unlink deployer foobar' 'secret "foobar" not found' +# check to make sure that our SCC policies don't prevent GC from deleting pods +os::cmd::expect_success 'oc create -f ${OS_ROOT}/test/testdata/privileged-pod.yaml' +os::cmd::expect_success 'oc delete pod/test-build-pod-issue --cascade=false' +os::cmd::try_until_failure 'oc get pods pod/test-build-pod-issue' -# Make sure that removing an existent and non-existent secret succeeds but warns about the non-existent one -os::cmd::expect_failure_and_text 'oc secrets unlink deployer foobar basicauth' 'secret "foobar" not found' -# Make sure that the existing secret is removed -os::cmd::expect_failure 'oc get serviceaccounts/deployer -o yaml |grep -q basicauth' -# Make sure that removing a real but unlinked secret succeeds -# https://github.com/openshift/origin/pull/9234#discussion_r70832486 -os::cmd::expect_failure_and_text 'oc secrets unlink deployer basicauth', 'No valid secrets found or secrets not linked to service account' +os::cmd::expect_success_and_text 'oc policy add-role-to-user admin namespaced-user' 'clusterrole.rbac.authorization.k8s.io/admin added: "namespaced-user"' +# Ensure the user has create permissions on builds, but that build strategy permissions are granted through the authenticated users group +os::cmd::try_until_text 'oc adm policy who-can create builds' 'namespaced-user' +os::cmd::expect_success_and_not_text 'oc adm policy who-can create builds/docker' 'namespaced-user' +os::cmd::expect_success_and_not_text 'oc adm policy who-can create builds/custom' 'namespaced-user' +os::cmd::expect_success_and_not_text 'oc adm policy who-can create builds/source' 'namespaced-user' +os::cmd::expect_success_and_not_text 'oc adm policy who-can create builds/jenkinspipeline' 'namespaced-user' +os::cmd::expect_success_and_text 'oc adm policy who-can create builds/docker' 'system:authenticated' +os::cmd::expect_success_and_text 'oc adm policy who-can create builds/source' 'system:authenticated' +os::cmd::expect_success_and_text 'oc adm policy who-can create builds/jenkinspipeline' 'system:authenticated' +# if this method for removing access to docker/custom/source/jenkinspipeline builds changes, docs need to be updated as well +os::cmd::expect_success_and_text 'oc adm policy remove-cluster-role-from-group system:build-strategy-docker system:authenticated' 'clusterrole.rbac.authorization.k8s.io/system:build-strategy-docker removed: "system:authenticated"' +os::cmd::expect_success_and_text 'oc adm policy remove-cluster-role-from-group system:build-strategy-source system:authenticated' 'clusterrole.rbac.authorization.k8s.io/system:build-strategy-source removed: "system:authenticated"' +os::cmd::expect_success_and_text 'oc adm policy remove-cluster-role-from-group system:build-strategy-jenkinspipeline system:authenticated' 'clusterrole.rbac.authorization.k8s.io/system:build-strategy-jenkinspipeline removed: "system:authenticated"' -# Make sure that it succeeds if *any* of the secrets are linked -# https://github.com/openshift/origin/pull/9234#discussion_r70832486 -os::cmd::expect_success 'oc secrets unlink deployer basicauth sshauth' +# ensure build strategy permissions no longer exist +os::cmd::try_until_failure 'oc adm policy who-can create builds/source | grep system:authenticated' +os::cmd::expect_success_and_not_text 'oc adm policy who-can create builds/docker' 'system:authenticated' +os::cmd::expect_success_and_not_text 'oc adm policy who-can create builds/source' 'system:authenticated' +os::cmd::expect_success_and_not_text 'oc adm policy who-can create builds/jenkinspipeline' 'system:authenticated' -# Confirm that the linked one was removed -os::cmd::expect_failure 'oc get serviceaccounts/deployer -o yaml |grep -q sshauth' +# validate --output and --dry-run flags for oc-adm-policy sub-commands +os::cmd::expect_success_and_text 'oc adm policy remove-role-from-user admin namespaced-user -o yaml' 'name: admin' +os::cmd::expect_success_and_text 'oc adm policy add-role-to-user admin namespaced-user -o yaml' 'name: namespaced-user' -# command alias -os::cmd::expect_success 'oc secret --help' -os::cmd::expect_success 'oc secret new --help' -os::cmd::expect_success 'oc secret new-dockercfg --help' -os::cmd::expect_success 'oc secret new-basicauth --help' -os::cmd::expect_success 'oc secret new-sshauth --help' -os::cmd::expect_success 'oc secret add --help' -os::cmd::expect_success 'oc secret link --help' -os::cmd::expect_success 'oc secret unlink --help' +os::cmd::expect_success_and_text 'oc adm policy remove-role-from-user admin namespaced-user --dry-run' 'clusterrole.rbac.authorization.k8s.io/admin removed: "namespaced-user" \(dry run\)' +os::cmd::expect_success_and_text 'oc adm policy add-role-to-user admin namespaced-user --dry-run' 'clusterrole.rbac.authorization.k8s.io/admin added: "namespaced-user" \(dry run\)' -echo "secrets: ok" -os::test::junit::declare_suite_end +# ensure that running an ` + "`" + `oc adm policy` + "`" + ` sub-command with --output does not actually perform any changes +os::cmd::expect_success_and_text 'oc adm policy who-can create pods -o yaml' '\- namespaced\-user' -os::test::junit::declare_suite_start "cmd/serviceaccounts-create-kubeconfig" -os::cmd::expect_success "oc serviceaccounts create-kubeconfig default > '${BASETMPDIR}/generated_default.kubeconfig'" -os::cmd::expect_success_and_text "KUBECONFIG='${BASETMPDIR}/generated_default.kubeconfig' oc whoami" "system:serviceaccount:$(oc project -q):default" -echo "serviceaccounts: ok" -os::test::junit::declare_suite_end -`) +os::cmd::expect_success_and_text 'oc adm policy scc-subject-review -u namespaced-user --output yaml -f - << __EOF__ +$testpod +__EOF__' 'name: testpod' +os::cmd::expect_success_and_text 'oc adm policy scc-subject-review -u namespaced-user --output wide -f - << __EOF__ +$testpod +__EOF__' 'Pod/testpod' -func testExtendedTestdataCmdTestCmdSecretsShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdSecretsSh, nil -} +os::cmd::expect_success_and_text 'oc adm policy scc-review --output yaml -f - << __EOF__ +$testpod +__EOF__' 'allowedServiceAccounts: null' -func testExtendedTestdataCmdTestCmdSecretsSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdSecretsShBytes() - if err != nil { - return nil, err - } +os::cmd::expect_success_and_text 'oc adm policy add-role-to-group view testgroup -o yaml' 'name: view' +os::cmd::expect_success_and_text 'oc adm policy add-cluster-role-to-group cluster-reader testgroup -o yaml' 'name: testgroup' +os::cmd::expect_success_and_text 'oc adm policy add-cluster-role-to-user cluster-reader namespaced-user -o yaml' 'name: namespaced\-user' - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/secrets.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +os::cmd::expect_success_and_text 'oc adm policy add-role-to-group view testgroup --dry-run' 'rolebinding.rbac.authorization.k8s.io/view added: "testgroup" \(dry run\)' +os::cmd::expect_success_and_text 'oc adm policy add-cluster-role-to-group cluster-reader testgroup --dry-run' 'clusterrolebinding.rbac.authorization.k8s.io/cluster-reader added: "testgroup" \(dry run\)' +os::cmd::expect_success_and_text 'oc adm policy add-cluster-role-to-user cluster-reader namespaced-user --dry-run' 'clusterrolebinding.rbac.authorization.k8s.io/cluster-reader added: "namespaced-user" \(dry run\)' -var _testExtendedTestdataCmdTestCmdServicesSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT +os::cmd::expect_success 'oc adm policy add-role-to-group view testgroup' +os::cmd::expect_success 'oc adm policy add-cluster-role-to-group cluster-reader testgroup' +os::cmd::expect_success 'oc adm policy add-cluster-role-to-user cluster-reader namespaced-user' -# Cleanup cluster resources created by this test -( - set +e - oc delete all,templates --all - exit 0 -) &>/dev/null +# ensure that removing missing target causes error. +os::cmd::expect_failure_and_text 'oc adm policy remove-cluster-role-from-user admin ghost' 'error: unable to find target \[ghost\]' +os::cmd::expect_failure_and_text 'oc adm policy remove-cluster-role-from-user admin -z ghost' 'error: unable to find target \[ghost\]' +os::cmd::expect_success_and_not_text 'oc adm policy remove-role-from-group view testgroup -o yaml' 'subjects: ' +os::cmd::expect_success_and_text 'oc adm policy remove-cluster-role-from-group cluster-reader testgroup -o yaml' 'name: cluster\-readers' +os::cmd::expect_success_and_text 'oc adm policy remove-cluster-role-from-user cluster-reader namespaced-user -o yaml' 'name: cluster\-reader' -os::test::junit::declare_suite_start "cmd/create-service-nodeport" -# This test validates the 'create service nodeport' command and its "--node-port" and "--tcp" options -os::cmd::expect_success_and_text 'oc create service nodeport mynodeport --tcp=8080:7777 --node-port=30000' 'service/mynodeport created' -os::cmd::expect_failure_and_text 'oc create service nodeport mynodeport --tcp=8080:7777 --node-port=30000' 'provided port is already allocated' -os::cmd::expect_failure_and_text 'oc create service nodeport mynodeport --tcp=8080:7777 --node-port=300' 'provided port is not in the valid range. The range of valid ports is 30000-32767' -os::cmd::expect_success_and_text 'oc describe service mynodeport' 'NodePort\:.*30000' -os::cmd::expect_success_and_text 'oc describe service mynodeport' 'NodePort\:.*8080-7777' -os::cmd::expect_success_and_text 'oc describe --v=8 service mynodeport' 'Response Body' +os::cmd::expect_success_and_text 'oc adm policy remove-role-from-group view testgroup --dry-run' 'clusterrole.rbac.authorization.k8s.io/view removed: "testgroup" \(dry run\)' +os::cmd::expect_success_and_text 'oc adm policy remove-cluster-role-from-group cluster-reader testgroup --dry-run' 'clusterrole.rbac.authorization.k8s.io/cluster-reader removed: "testgroup" \(dry run\)' +os::cmd::expect_success_and_text 'oc adm policy remove-cluster-role-from-user cluster-reader namespaced-user --dry-run' 'clusterrole.rbac.authorization.k8s.io/cluster-reader removed: "namespaced-user" \(dry run\)' -echo "create-services-nodeport: ok" -os::test::junit::declare_suite_end -`) +os::cmd::expect_success_and_text 'oc adm policy remove-user namespaced-user -o yaml' "namespace: ${project}" +os::cmd::expect_success_and_text 'oc adm policy remove-user namespaced-user --dry-run' "Removing admin from users \[namespaced\-user\] in project ${project}" -func testExtendedTestdataCmdTestCmdServicesShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdServicesSh, nil -} +os::cmd::expect_success_and_text 'oc adm policy add-scc-to-user anyuid namespaced-user -o yaml' '\- namespaced\-user' +os::cmd::expect_success_and_text 'oc adm policy add-scc-to-user anyuid namespaced-user --dry-run' 'securitycontextconstraints.security.openshift.io/anyuid added to: \["namespaced\-user"\] \(dry run\)' -func testExtendedTestdataCmdTestCmdServicesSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdServicesShBytes() - if err != nil { - return nil, err - } +os::cmd::expect_success_and_text 'oc adm policy add-scc-to-group anyuid testgroup -o yaml' '\- testgroup' +os::cmd::expect_success_and_text 'oc adm policy add-scc-to-group anyuid testgroup --dry-run' 'securitycontextconstraints.security.openshift.io/anyuid added to groups: \["testgroup"\] \(dry run\)' - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/services.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +os::cmd::expect_success_and_not_text 'oc adm policy remove-scc-from-user anyuid namespaced-user -o yaml' '\- namespaced\-user' +os::cmd::expect_success_and_text 'oc adm policy remove-scc-from-user anyuid namespaced-user --dry-run' 'securitycontextconstraints.security.openshift.io/anyuid removed from: \["namespaced\-user"\] \(dry run\)' -var _testExtendedTestdataCmdTestCmdSetDataSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT +os::cmd::expect_success_and_not_text 'oc adm policy remove-scc-from-group anyuid testgroup -o yaml' '\- testgroup' +os::cmd::expect_success_and_text 'oc adm policy remove-scc-from-group anyuid testgroup --dry-run' 'securitycontextconstraints.security.openshift.io/anyuid removed from groups: \["testgroup"\] \(dry run\)' -# Cleanup cluster resources created by this test -( - set +e - oc delete cm --all - oc delete secret test - exit 0 -) &>/dev/null +# ensure system:authenticated users can not create custom builds by default, but can if explicitly granted access +os::cmd::expect_success_and_not_text 'oc adm policy who-can create builds/custom' 'system:authenticated' +os::cmd::expect_success_and_text 'oc adm policy add-cluster-role-to-group system:build-strategy-custom system:authenticated' 'clusterrole.rbac.authorization.k8s.io/system:build-strategy-custom added: "system:authenticated"' +os::cmd::expect_success_and_text 'oc adm policy who-can create builds/custom' 'system:authenticated' +os::cmd::expect_success 'oc auth reconcile --remove-extra-permissions --remove-extra-subjects -f "${BASE_RBAC_DATA}"' -os::test::junit::declare_suite_start "cmd/oc/set/data" +os::cmd::try_until_text 'oc auth can-i --list' 'get update.*imagestreams/layers' +os::cmd::try_until_text 'oc auth can-i create pods --all-namespaces' 'yes' +os::cmd::try_until_text 'oc auth can-i create pods' 'yes' +os::cmd::try_until_text 'oc auth can-i create pods --as harold' 'no' +os::cmd::expect_failure 'oc auth can-i create pods --as harold --user harold' +os::cmd::expect_failure 'oc auth can-i --list --as harold --user harold' +os::cmd::expect_failure 'oc auth can-i create pods --as harold -q' -os::cmd::expect_success 'oc create configmap test' -tmpfile="$(mktemp)" -echo "c" > "${tmpfile}" +os::cmd::expect_success_and_text 'oc auth can-i create pods --user system:admin' 'yes' +os::cmd::expect_success_and_text 'oc auth can-i create pods --groups system:unauthenticated --groups system:masters' 'yes' +os::cmd::expect_success_and_text 'oc auth can-i create pods --groups system:unauthenticated' 'no' +os::cmd::expect_success_and_text 'oc auth can-i create pods --user harold' 'no' -# test --local flag -os::cmd::expect_failure_and_text 'oc set data cm/test a=b --local' 'provide one or more resources by argument or filename' -# test --dry-run flag with -o formats -os::cmd::expect_success_and_text 'oc set data cm/test a=b --dry-run' 'test' -os::cmd::expect_success_and_text 'oc set data cm/test a=b --dry-run -o name' 'configmap/test' -os::cmd::expect_success_and_text 'oc set data cm/test a=b --dry-run' 'configmap/test data updated \(dry run\)' +os::cmd::expect_success_and_text 'oc auth can-i --list --user system:admin' 'get update.*imagestreams/layers' +os::cmd::expect_success_and_text 'oc auth can-i --list --groups system:unauthenticated --groups system:cluster-readers' 'get.*imagestreams/layers' +os::cmd::expect_success_and_not_text 'oc auth can-i --list --groups system:unauthenticated' 'get update.*imagestreams/layers' +os::cmd::expect_success_and_not_text 'oc auth can-i --list --user harold --groups system:authenticated' 'get update.*imagestreams/layers' +os::cmd::expect_success_and_text 'oc auth can-i --list --user harold --groups system:authenticated' 'create get.*buildconfigs/webhooks' -os::cmd::expect_failure_and_text 'oc set data cm/test a=c a-' 'you may not remove and set the key' -os::cmd::expect_failure_and_text 'oc set data cm/test a=c --from-literal=a=b' 'cannot set key "a" in both argument and flag' +os::cmd::expect_failure 'oc policy scc-subject-review' +os::cmd::expect_failure 'oc policy scc-review' +os::cmd::expect_failure 'oc policy scc-subject-review -u invalid --namespace=noexist' +os::cmd::expect_failure_and_text 'oc policy scc-subject-review -f ${OS_ROOT}/test/testdata/pspreview_unsupported_statefulset.yaml' 'error: StatefulSet "rd" with spec.volumeClaimTemplates currently not supported.' +os::cmd::expect_failure_and_text 'oc policy scc-subject-review -z foo,bar -f ${OS_ROOT}/test/testdata/job.yaml' 'error: only one Service Account is supported' +os::cmd::expect_failure_and_text 'oc policy scc-subject-review -z system:serviceaccount:test:default,system:serviceaccount:test:builder -f ${OS_ROOT}/test/testdata/job.yaml' 'error: only one Service Account is supported' +os::cmd::expect_failure_and_text 'oc policy scc-review -f ${OS_ROOT}/test/testdata/pspreview_unsupported_statefulset.yaml' 'error: StatefulSet "rd" with spec.volumeClaimTemplates currently not supported.' +os::cmd::expect_success_and_text 'oc policy scc-subject-review -f ${OS_ROOT}/test/testdata/job.yaml -o=jsonpath={.status.allowedBy.name}' 'anyuid' +os::cmd::expect_success_and_text 'oc policy scc-subject-review -f ${OS_ROOT}/test/testdata/redis-slave.yaml -o=jsonpath={.status.allowedBy.name}' 'anyuid' +# In the past system:admin only had access to a few SCCs, so the following command resulted in the privileged SCC being used +# Since SCCs are now authorized via RBAC, and system:admin can perform all RBAC actions == system:admin can access all SCCs now +# Thus the following command now results in the use of the hostnetwork SCC which is the most restrictive SCC that still allows the pod to run +os::cmd::expect_success_and_text 'oc policy scc-subject-review -f ${OS_ROOT}/test/testdata/nginx_pod.yaml -o=jsonpath={.status.allowedBy.name}' 'hostnetwork' +# Make sure that the legacy ungroupified objects continue to work by directly doing a create +os::cmd::expect_success_and_text 'oc create -f ${OS_ROOT}/test/testdata/legacy_ungroupified_psp_review.yaml -o=jsonpath={.status.allowedBy.name}' 'restricted' +os::cmd::expect_success "oc login -u bob -p bobpassword" +os::cmd::expect_success_and_text 'oc whoami' 'bob' +os::cmd::expect_success 'oc new-project policy-second' +os::cmd::expect_success_and_text 'oc policy scc-subject-review -f ${OS_ROOT}/test/testdata/job.yaml -o=jsonpath={.status.allowedBy.name}' 'restricted' +os::cmd::expect_success_and_text 'oc policy scc-subject-review -f ${OS_ROOT}/test/testdata/job.yaml --no-headers=true' 'Job/hello restricted' +os::cmd::expect_success_and_text 'oc policy scc-subject-review -f ${OS_ROOT}/test/testdata/two_jobs.yaml -o=jsonpath={.status.allowedBy.name}' 'restrictedrestricted' +os::cmd::expect_success_and_text 'oc policy scc-review -f ${OS_ROOT}/test/testdata/job.yaml -ojsonpath={.status.allowedServiceAccounts}' '' +os::cmd::expect_success_and_text 'oc policy scc-review -f ${OS_ROOT}/test/extended/testdata/deployments/deployment-simple.yaml -ojsonpath={.status.allowedServiceAccounts}' '' +os::cmd::expect_failure 'oc policy scc-subject-review -f ${OS_ROOT}/test/testdata/external-service.yaml' +os::cmd::expect_success "oc login -u system:admin -n '${project}'" +os::cmd::expect_success_and_text 'oc policy scc-subject-review -u bob -g system:authenticated -f ${OS_ROOT}/test/testdata/job.yaml -n policy-second -o=jsonpath={.status.allowedBy.name}' 'restricted' +os::cmd::expect_success_and_text 'oc policy scc-subject-review -u bob -f ${OS_ROOT}/test/testdata/job.yaml -n policy-second --no-headers=true' 'Job/hello ' +os::cmd::expect_success_and_text 'oc policy scc-subject-review -z default -f ${OS_ROOT}/test/testdata/job.yaml' '' +os::cmd::expect_success_and_text 'oc policy scc-subject-review -z default -g system:authenticated -f ${OS_ROOT}/test/testdata/job.yaml' 'restricted' +os::cmd::expect_failure_and_text 'oc policy scc-subject-review -u alice -z default -g system:authenticated -f ${OS_ROOT}/test/testdata/job.yaml' 'error: --user and --serviceaccount are mutually exclusive' +os::cmd::expect_success_and_text 'oc policy scc-subject-review -z system:serviceaccount:alice:default -g system:authenticated -f ${OS_ROOT}/test/testdata/job.yaml' 'restricted' +os::cmd::expect_success_and_text 'oc policy scc-subject-review -u alice -g system:authenticated -f ${OS_ROOT}/test/testdata/job.yaml' 'restricted' +os::cmd::expect_failure_and_text 'oc policy scc-subject-review -u alice -g system:authenticated -n noexist -f ${OS_ROOT}/test/testdata/job.yaml' 'error: unable to compute Pod Security Policy Subject Review for "hello": namespaces "noexist" not found' +os::cmd::expect_success 'oc create -f ${OS_ROOT}/test/testdata/scc_lax.yaml' +os::cmd::expect_success "oc login -u bob -p bobpassword" +os::cmd::expect_success_and_text 'oc policy scc-review -f ${OS_ROOT}/test/testdata/job.yaml --no-headers=true' 'Job/hello default lax' +os::cmd::expect_success_and_text 'oc policy scc-review -z default -f ${OS_ROOT}/test/testdata/job.yaml --no-headers=true' 'Job/hello default lax' +os::cmd::expect_success_and_text 'oc policy scc-review -z system:serviceaccount:policy-second:default -f ${OS_ROOT}/test/testdata/job.yaml --no-headers=true' 'Job/hello default lax' +os::cmd::expect_success_and_text 'oc policy scc-review -f ${OS_ROOT}/test/extended/testdata/deployments/deployment-simple.yaml --no-headers=true' 'DeploymentConfig/deployment-simple default lax' +os::cmd::expect_success_and_text 'oc policy scc-review -f ${OS_ROOT}/test/testdata/nginx_pod.yaml --no-headers=true' '' +os::cmd::expect_failure_and_text 'oc policy scc-review -z default -f ${OS_ROOT}/test/testdata/job.yaml --namespace=no-exist' 'error: unable to compute Pod Security Policy Review for "hello": podsecuritypolicyreviews.security.openshift.io is forbidden: User "bob" cannot create resource "podsecuritypolicyreviews" in API group "security.openshift.io" in the namespace "no-exist"' +os::cmd::expect_failure_and_text 'oc policy scc-review -z default -f ${OS_ROOT}/test/testdata/pspreview_unsupported_statefulset.yaml' 'error: StatefulSet "rd" with spec.volumeClaimTemplates currently not supported.' +os::cmd::expect_failure_and_text 'oc policy scc-review -z no-exist -f ${OS_ROOT}/test/testdata/job.yaml' 'error: unable to compute Pod Security Policy Review for "hello": unable to retrieve ServiceAccount no-exist: serviceaccount "no-exist" not found' +os::cmd::expect_success "oc login -u system:admin -n '${project}'" +os::cmd::expect_success 'oc delete project policy-second' -os::cmd::expect_success 'oc set data cm/test a=b' -os::cmd::expect_success_and_text "oc get cm/test -o jsonpath='{.data.a}'" 'b' -os::cmd::expect_success_and_text 'oc set data cm/test a=b' 'info: test was not changed' +# adjust the cluster-admin role to check defaulting and coverage checks +# this is done here instead of an integration test because we need to make sure the actual yaml serializations work +workingdir=$(mktemp -d) +cp ${OS_ROOT}/hack/local-up-master/test-manifests/cluster_admin_1.0.yaml ${workingdir} +os::util::sed "s/RESOURCE_VERSION//g" ${workingdir}/cluster_admin_1.0.yaml +os::cmd::expect_success "oc create -f ${workingdir}/cluster_admin_1.0.yaml" +os::cmd::expect_success 'oc adm policy add-cluster-role-to-user alternate-cluster-admin alternate-cluster-admin-user' -os::cmd::expect_success 'oc set data cm/test a-' -os::cmd::expect_success_and_text "oc get cm/test -o jsonpath='{.data.a}'" '' -os::cmd::expect_success_and_text 'oc set data cm/test a-' 'info: test was not changed' +# switch to test user to be sure that default project admin policy works properly +new_kubeconfig="${workingdir}/tempconfig" +os::cmd::expect_success "oc config view --raw > $new_kubeconfig" +os::cmd::expect_success "oc login -u alternate-cluster-admin-user -p anything --kubeconfig=${new_kubeconfig}" -os::cmd::expect_success "oc set data cm/test --from-file=b=${tmpfile}" -os::cmd::expect_success_and_text "oc get cm/test -o jsonpath='{.data.b}'" 'c' -os::cmd::expect_success_and_text "oc set data cm/test --from-file=b=${tmpfile}" 'info: test was not changed' +# alternate-cluster-admin can restrict himself to less groups (no star) +os::cmd::try_until_text "oc policy who-can update clusterrroles" "alternate-cluster-admin-user" +resourceversion=$(oc get clusterrole/alternate-cluster-admin -o=jsonpath="{.metadata.resourceVersion}") +cp ${OS_ROOT}/hack/local-up-master/test-manifests/cluster_admin_without_apigroups.yaml ${workingdir} +os::util::sed "s/RESOURCE_VERSION/${resourceversion}/g" ${workingdir}/cluster_admin_without_apigroups.yaml +os::cmd::expect_success "oc replace --kubeconfig=${new_kubeconfig} clusterrole/alternate-cluster-admin -f ${workingdir}/cluster_admin_without_apigroups.yaml" -rm -rf ${tmpfile} -mkdir -p ${tmpfile} -echo '1' > "${tmpfile}/a" -echo '2' > "${tmpfile}/b" -os::cmd::expect_success 'oc set data cm/test b-' -os::cmd::expect_success "oc set data cm/test --from-file=${tmpfile}" -os::cmd::expect_success_and_text "oc get cm/test -o jsonpath='{.data.a}'" '1' -os::cmd::expect_success_and_text "oc get cm/test -o jsonpath='{.data.b}'" '2' -os::cmd::expect_success_and_text "oc set data cm/test --from-file=${tmpfile}" "info: test was not changed" +# alternate-cluster-admin should NOT have the power add back star now (anything other than star is considered less so this mimics testing against no groups) +os::cmd::try_until_failure "oc policy who-can update hpa.autoscaling | grep -q alternate-cluster-admin-user" +resourceversion=$(oc get clusterrole/alternate-cluster-admin -o=jsonpath="{.metadata.resourceVersion}") +cp ${OS_ROOT}/vendor/github.com/openshift/openshift-apiserver/test/testdata/bootstrappolicy/alternate_cluster_admin.yaml ${workingdir} +os::util::sed "s/RESOURCE_VERSION/${resourceversion}/g" ${workingdir}/alternate_cluster_admin.yaml +os::cmd::expect_failure_and_text "oc replace --kubeconfig=${new_kubeconfig} clusterrole/alternate-cluster-admin -f ${workingdir}/alternate_cluster_admin.yaml" "attempting to grant RBAC permissions not currently held" -os::cmd::expect_success 'oc create secret generic test' -os::cmd::expect_success 'oc set data secret/test a=b' -os::cmd::expect_success_and_text "oc get secret/test -o jsonpath='{.data.a}'" 'Yg==' -os::cmd::expect_success_and_text 'oc set data secret/test a=b' 'info: test was not changed' +# This test validates cluster level policy for serviceaccounts +# ensure service account cannot list pods at the namespace level +os::cmd::expect_success_and_text "oc auth can-i list pods --as=system:serviceaccount:cmd-policy:testserviceaccount" "no" +os::cmd::expect_success_and_text "oc adm policy add-role-to-user view -z=testserviceaccount" 'clusterrole.rbac.authorization.k8s.io/view added: "testserviceaccount"' +# ensure service account can list pods at the namespace level after "view" role is added, but not at the cluster level +os::cmd::try_until_text "oc auth can-i list pods --as=system:serviceaccount:${project}:testserviceaccount" "yes" +os::cmd::try_until_text "oc auth can-i list pods --all-namespaces --as=system:serviceaccount:${project}:testserviceaccount" "no" +# ensure service account can list pods at the cluster level after "cluster-reader" cluster role is added +os::cmd::expect_success_and_text "oc adm policy add-cluster-role-to-user cluster-reader -z=testserviceaccount" 'clusterrole.rbac.authorization.k8s.io/cluster-reader added: "testserviceaccount"' +os::cmd::try_until_text "oc auth can-i list pods --all-namespaces --as=system:serviceaccount:${project}:testserviceaccount" "yes" +# make sure users can easily create roles for RBAC based SCC access +os::cmd::expect_success_and_text 'oc create role scc-privileged --verb=use --resource=scc --resource-name=privileged' 'role.rbac.authorization.k8s.io/scc-privileged created' +os::cmd::expect_success_and_text 'oc delete role.rbac scc-privileged' 'role.rbac.authorization.k8s.io "scc-privileged" deleted' -echo "set-data: ok" +echo "policy: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdSetDataShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdSetDataSh, nil +func testExtendedTestdataCmdTestCmdPolicyShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdPolicySh, nil } -func testExtendedTestdataCmdTestCmdSetDataSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdSetDataShBytes() +func testExtendedTestdataCmdTestCmdPolicySh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdPolicyShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/set-data.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/policy.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdSetImageSh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdPrinterSh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT -# Cleanup cluster resources created by this test -( - set +e - oc delete all,templates --all - exit 0 -) &>/dev/null - - -os::test::junit::declare_suite_start "cmd/oc/set/image" -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-deployment-config.yaml' -os::cmd::expect_success 'oc create -f ${TEST_DATA}/hello-openshift/hello-pod.json' -os::cmd::expect_success 'oc create -f ${TEST_DATA}/image-streams/image-streams-centos7.json' -os::cmd::try_until_success 'oc get imagestreamtags ruby:2.7-ubi8' - -# test --local flag -os::cmd::expect_failure_and_text 'oc set image dc/test-deployment-config ruby-helloworld=ruby:2.7-ubi8 --local' 'you must specify resources by --filename when --local is set.' -# test --dry-run flag with -o formats -os::cmd::expect_success_and_text 'oc set image dc/test-deployment-config ruby-helloworld=ruby:2.7-ubi8 --source=istag --dry-run' 'test-deployment-config' -os::cmd::expect_success_and_text 'oc set image dc/test-deployment-config ruby-helloworld=ruby:2.7-ubi8 --source=istag --dry-run -o name' 'deploymentconfig.apps.openshift.io/test-deployment-config' -os::cmd::expect_success_and_text 'oc set image dc/test-deployment-config ruby-helloworld=ruby:2.7-ubi8 --source=istag --dry-run' 'deploymentconfig.apps.openshift.io/test-deployment-config image updated \(dry run\)' - -os::cmd::expect_success 'oc set image dc/test-deployment-config ruby-helloworld=ruby:2.7-ubi8 --source=istag' -os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o jsonpath='{.spec.template.spec.containers[0].image}'" 'image-registry.openshift-image-registry.svc:5000/cmd-set-image/ruby' - -os::cmd::expect_success 'oc set image dc/test-deployment-config ruby-helloworld=ruby:2.7-ubi8 --source=istag' -os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o jsonpath='{.spec.template.spec.containers[0].image}'" 'image-registry.openshift-image-registry.svc:5000/cmd-set-image/ruby' - -os::cmd::expect_failure 'oc set image dc/test-deployment-config ruby-helloworld=ruby:XYZ --source=istag' -os::cmd::expect_failure 'oc set image dc/test-deployment-config ruby-helloworld=ruby:XYZ --source=isimage' - -os::cmd::expect_success 'oc set image dc/test-deployment-config ruby-helloworld=nginx' -os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o jsonpath='{.spec.template.spec.containers[0].image}'" 'nginx' - -os::cmd::expect_success 'oc set image pod/hello-openshift hello-openshift=nginx' -os::cmd::expect_success_and_text "oc get pod/hello-openshift -o jsonpath='{.spec.containers[0].image}'" 'nginx' - -os::cmd::expect_success 'oc set image pod/hello-openshift hello-openshift=nginx:1.9.1' -os::cmd::expect_success_and_text "oc get pod/hello-openshift -o jsonpath='{.spec.containers[0].image}'" 'nginx:1.9.1' +# Test that resource printer includes resource kind on multiple resources +os::test::junit::declare_suite_start "cmd/basicresources/printer" +os::cmd::expect_success 'oc create imagestream test1' +os::cmd::expect_success 'oc new-app openshift/nodejs' +os::cmd::expect_success_and_text 'oc get all' 'imagestream.image.openshift.io/test1' +os::cmd::expect_success_and_not_text 'oc get is' 'imagestream.image.openshift.io/test1' -os::cmd::expect_success 'oc set image pods,dc *=ruby:2.7-ubi8 --all --source=imagestreamtag' -os::cmd::expect_success_and_text "oc get pod/hello-openshift -o jsonpath='{.spec.containers[0].image}'" 'image-registry.openshift-image-registry.svc:5000/cmd-set-image/ruby' -os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o jsonpath='{.spec.template.spec.containers[0].image}'" 'image-registry.openshift-image-registry.svc:5000/cmd-set-image/ruby' +# Test that resource printer includes namespaces for buildconfigs with custom strategies +os::cmd::expect_success 'oc create -f ${TEST_DATA}/application-template-custombuild.json' +os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample' 'deployment.*.apps.* "frontend" created' +os::cmd::expect_success_and_text 'oc get all --all-namespaces' 'cmd-printer[\ ]+buildconfig.build.openshift.io\/ruby\-sample\-build' -echo "set-image: ok" +# Test that infos printer supports all outputFormat options +os::cmd::expect_success_and_text 'oc new-app openshift/nodejs --dry-run -o yaml | oc set env --local -f - MYVAR=value' 'deployment.*.apps.*/nodejs updated' +os::cmd::expect_success_and_text 'oc new-app openshift/nodejs --dry-run -o yaml | oc set env --local -f - MYVAR=value -o yaml' 'apiVersion: apps.*/v1' +os::cmd::expect_success_and_text 'oc new-app openshift/nodejs --dry-run -o yaml | oc set env --local -f - MYVAR=value -o json' '"apiVersion": "apps.*/v1"' +echo "resource printer: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdSetImageShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdSetImageSh, nil +func testExtendedTestdataCmdTestCmdPrinterShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdPrinterSh, nil } -func testExtendedTestdataCmdTestCmdSetImageSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdSetImageShBytes() +func testExtendedTestdataCmdTestCmdPrinterSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdPrinterShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/set-image.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/printer.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdSetLivenessProbeSh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdProjectsSh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT # Cleanup cluster resources created by this test ( set +e - oc delete all,templates --all + oc delete namespace test4 + oc delete namespace test5 + oc delete namespace test6 + oc wait --for=delete namespace test4 --timeout=60s || true + oc wait --for=delete namespace test5 --timeout=60s || true + oc wait --for=delete namespace test6 --timeout=60s || true exit 0 ) &>/dev/null -os::test::junit::declare_suite_start "cmd/set-probe-liveness" -# This test setting a liveness probe, without warning about replication controllers whose deployment depends on deployment configs -os::cmd::expect_success_and_text 'oc create -f ${TEST_DATA}/simple-deployment.yaml' 'deploymentconfig.apps.openshift.io/simple-deployment created' -os::cmd::expect_success_and_text 'oc status --suggest' 'dc/simple-deployment has no liveness probe' +os::test::junit::declare_suite_start "cmd/projects" + +os::test::junit::declare_suite_start "cmd/projects/lifecycle" +# resourceaccessreview +os::cmd::expect_success 'oc policy who-can get pods -n missing-ns' +# selfsubjectaccessreview +os::cmd::expect_success 'oc auth can-i get pods -n missing-ns' +# selfsubjectrulesreivew +os::cmd::expect_success 'oc auth can-i --list -n missing-ns' +# create bob +os::cmd::expect_success 'oc create user bob' +# subjectaccessreview +os::cmd::expect_failure_and_text 'oc auth can-i get pods --as=bob -n missing-ns' 'no' +# subjectrulesreview +os::cmd::expect_success 'oc auth can-i --list --as=bob -n missing-ns' +echo 'project lifecycle ok' +os::test::junit::declare_suite_end + +os::cmd::expect_failure_and_text 'oc projects test_arg' 'no arguments' +# log in as a test user and expect no projects +#os::cmd::expect_success 'oc login -u test -p test' +#os::cmd::expect_success_and_text 'oc projects' 'You are not a member of any projects' +# add a project and expect text for a single project +os::cmd::expect_success_and_text 'oc new-project test4' 'Now using project "test4" on server ' +os::cmd::try_until_text 'oc projects' 'Using project "test4" on server' +os::cmd::expect_success_and_text 'oc new-project test5' 'Now using project "test5" on server ' +os::cmd::try_until_text 'oc projects' 'You have access to the following projects and can switch between them with ' +# HA masters means that you may have to wait for the lists to settle, so you allow for that by waiting +os::cmd::try_until_text 'oc projects' 'test4' +os::cmd::try_until_text 'oc projects' 'test5' +# test --skip-config-write +os::cmd::expect_success_and_text 'oc new-project test6 --skip-config-write' 'To switch to this project and start adding applications, use' +os::cmd::expect_success_and_not_text 'oc config view -o jsonpath="{.contexts[*].context.namespace}"' '\btest6\b' +os::cmd::try_until_text 'oc projects' 'test6' +os::cmd::expect_success_and_text 'oc project test6' 'Now using project "test6"' +os::cmd::expect_success_and_text 'oc config view -o jsonpath="{.contexts[*].context.namespace}"' '\btest6\b' +echo 'projects command ok' -# test --local flag -os::cmd::expect_failure_and_text 'oc set probe dc/simple-deployment --liveness --get-url=http://google.com:80 --local' 'You must provide one or more resources by argument or filename' -# test --dry-run flag with -o formats -os::cmd::expect_success_and_text 'oc set probe dc/simple-deployment --liveness --get-url=http://google.com:80 --dry-run' 'simple-deployment' -os::cmd::expect_success_and_text 'oc set probe dc/simple-deployment --liveness --get-url=http://google.com:80 --dry-run -o name' 'deploymentconfig.apps.openshift.io/simple-deployment' -os::cmd::expect_success_and_not_text 'oc status --suggest' 'rc/simple-deployment-1 has no liveness probe' -os::cmd::expect_success_and_text 'oc set probe dc/simple-deployment --liveness --get-url=http://google.com:80' 'deploymentconfig.apps.openshift.io/simple-deployment probes updated' -os::cmd::expect_success_and_not_text 'oc status --suggest' 'dc/simple-deployment has no liveness probe' -echo "set-probe-liveness: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdSetLivenessProbeShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdSetLivenessProbeSh, nil +func testExtendedTestdataCmdTestCmdProjectsShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdProjectsSh, nil } -func testExtendedTestdataCmdTestCmdSetLivenessProbeSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdSetLivenessProbeShBytes() +func testExtendedTestdataCmdTestCmdProjectsSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdProjectsShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/set-liveness-probe.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/projects.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdSetbuildhookSh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdQuotaSh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT -# Cleanup cluster resources created by this test +os::test::junit::declare_suite_start "cmd/quota" + +# Cleanup cluster resources created by this test suite ( set +e - oc delete all,templates --all + oc delete namespace quota-{foo,bar,asmail,images} + oc wait --for=delete namespace quota-{foo,bar,asmail,images} --timeout=60s || true + oc delete clusterresourcequotas.quota.openshift.io "for-deads" + oc delete clusterresourcequotas.quota.openshift.io "for-deads-by-annotation" + oc delete clusterresourcequotas.quota.openshift.io "for-deads-email-by-annotation" + oc delete clusterresourcequotas.quota.openshift.io "annotation-value-with-commas" exit 0 ) &>/dev/null +os::test::junit::declare_suite_start "cmd/quota/clusterquota" -os::test::junit::declare_suite_start "cmd/builds/setbuildhook" -# Validate the set build-hook command -arg="-f ${TEST_DATA}/test-bc.yaml" -os::cmd::expect_failure_and_text "oc set build-hook" "error: one or more build configs" -os::cmd::expect_failure_and_text "oc set build-hook ${arg}" "error: you must specify a type of hook" -os::cmd::expect_failure_and_text "oc set build-hook ${arg} --local --post-commit -o yaml -- echo 'hello world'" 'you must specify either a script or command for the build hook' -os::cmd::expect_success_and_text "oc set build-hook ${arg} --local --post-commit --command -o yaml -- echo 'hello world'" 'command:' -os::cmd::expect_success_and_text "oc set build-hook ${arg} --local --post-commit -o yaml --script='echo \"hello world\"'" 'script: echo \"hello world\"' -# Server object tests -os::cmd::expect_success "oc create -f ${TEST_DATA}/test-bc.yaml" -# Must specify --command or --script -os::cmd::expect_failure_and_text "oc set build-hook bc/test-buildconfig --post-commit" "you must specify either a script or command" -# Setting args for the default entrypoint is not supported -os::cmd::expect_failure_and_text "oc set build-hook test-buildconfig --post-commit -- foo bar" "you must specify either a script or command for the build hook" -# Set a command + args on a specific build config -os::cmd::expect_success_and_text "oc set build-hook bc/test-buildconfig --post-commit --command -- /bin/bash -c \"echo 'test'\"" "updated" -os::cmd::expect_success_and_text "oc get bc/test-buildconfig -o yaml" "command:" -os::cmd::expect_success_and_text "oc get bc/test-buildconfig -o yaml" "args:" -os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "script:" -# Set a script on a specific build config -os::cmd::expect_success_and_text "oc set build-hook bc/test-buildconfig --post-commit --script /bin/script.sh -- arg1 arg2" "updated" -os::cmd::expect_success_and_text "oc get bc/test-buildconfig -o yaml" "script:" -os::cmd::expect_success_and_text "oc get bc/test-buildconfig -o yaml" "args:" -os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "command:" -# Remove the postcommit hook -os::cmd::expect_success_and_text "oc set build-hook bc/test-buildconfig --post-commit --remove" "updated" -os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "args:" -os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "command:" -os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "script:" -# Set a command + args on all build configs -os::cmd::expect_success_and_text "oc set build-hook --all --post-commit --command -- /bin/bash -c \"echo 'test'\"" "updated" -os::cmd::expect_success_and_text "oc get bc/test-buildconfig -o yaml" "command:" -os::cmd::expect_success_and_text "oc get bc/test-buildconfig -o yaml" "args:" -os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "script:" -# Set a script on all build configs -os::cmd::expect_success_and_text "oc set build-hook --all --post-commit --script /bin/script.sh" "updated" -os::cmd::expect_success_and_text "oc get bc/test-buildconfig -o yaml" "script:" -os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "args:" -os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "command:" +# This tests creating a clusterresourcequota against an existing namespace with a known number of resources +os::cmd::expect_success 'oc new-project quota-foo --as=deads --as-group=system:authenticated --as-group=system:authenticated:oauth' +os::cmd::expect_success 'oc label namespace/quota-foo owner=deads' +os::cmd::try_until_text 'oc get secrets -o name -n quota-foo | wc -l' '9' +os::cmd::expect_success 'oc create clusterquota for-deads --project-label-selector=owner=deads --hard=secrets=10' +os::cmd::try_until_text 'oc get appliedclusterresourcequota -n quota-foo --as deads -o name' "for-deads" +os::cmd::try_until_text 'oc get secrets --all-namespaces; oc get appliedclusterresourcequota/for-deads -n quota-foo --as deads -o jsonpath=used={.status.total.used.secrets}' "used=9" + +os::cmd::expect_failure_and_text 'oc create clusterquota for-deads-malformed --project-annotation-selector="openshift.#$%/requester=deads"' "prefix part a (DNS-1123|lowercase RFC 1123) subdomain must consist of lower case alphanumeric characters" +os::cmd::expect_failure_and_text 'oc create clusterquota for-deads-malformed --project-annotation-selector=openshift.io/requester=deads,openshift.io/novalue' "Malformed annotation selector" +os::cmd::expect_success 'oc create clusterquota for-deads-by-annotation --project-annotation-selector=openshift.io/requester=deads --hard=secrets=50' +os::cmd::expect_success 'oc create clusterquota for-deads-email-by-annotation --project-annotation-selector=openshift.io/requester=deads@deads.io --hard=secrets=50' +os::cmd::expect_success 'oc create clusterresourcequota annotation-value-with-commas --project-annotation-selector="openshift.io/requester=deads,\"openshift.io/withcomma=yes,true,1\"" --hard=pods=10' +os::cmd::expect_success 'oc new-project quota-bar --as=deads --as-group=system:authenticated --as-group=system:authenticated:oauth' +os::cmd::expect_success 'oc new-project quota-asmail --as=deads@deads.io --as-group=system:authenticated --as-group=system:authenticated:oauth' +os::cmd::try_until_text 'oc get appliedclusterresourcequota -n quota-bar --as deads -o name' "for-deads-by-annotation" +os::cmd::try_until_text 'oc get appliedclusterresourcequota -n quota-foo --as deads -o name' "for-deads-by-annotation" +os::cmd::try_until_text 'oc get appliedclusterresourcequota -n quota-asmail --as deads@deads.io -o name' "for-deads-email-by-annotation" +# the point of the test is to make sure that clusterquota is counting correct and secrets are auto-created and countable +# the create_dockercfg controller can issue multiple creates if the token controller doesn't fill them in, but the creates are duplicates +# since an annotation tracks the intended secrets to be created. That results in multi-counting quota until reconciliation runs +# do not go past 26. If you get to 27, you might be selecting an extra namespace. +os::cmd::try_until_text 'oc get secrets --all-namespaces; oc get appliedclusterresourcequota/for-deads-by-annotation -n quota-bar --as deads -o jsonpath=used={.status.total.used.secrets}' "used=(1[0-9]|20|21|22|23|24|25|26)" +os::cmd::expect_success 'oc delete project quota-foo' +os::cmd::try_until_not_text 'oc get clusterresourcequota/for-deads-by-annotation -o jsonpath="{.status.namespaces[*].namespace}"' 'quota-foo' +os::cmd::expect_success 'oc delete project quota-bar' +os::cmd::expect_success 'oc delete project quota-asmail' + +echo "clusterquota: ok" +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_start "cmd/quota/imagestreams" + +os::cmd::expect_success 'oc new-project quota-images --as=deads --as-group=system:authenticated --as-group=system:authenticated:oauth' +os::cmd::expect_success 'oc create quota -n quota-images is-quota --hard openshift.io/imagestreams=1' +os::cmd::try_until_success 'oc tag -n quota-images openshift/hello-openshift myis2:v2' +os::cmd::expect_failure_and_text 'oc tag -n quota-images busybox mybox:v1' "exceeded quota" +os::cmd::expect_failure_and_text 'oc import-image centos -n quota-images --from=registry.centos.org/centos:latest --confirm=true' "exceeded quota" +os::cmd::expect_success 'oc delete project quota-images' + +echo "imagestreams: ok" +os::test::junit::declare_suite_end -os::cmd::expect_success "oc delete bc/test-buildconfig" -# ensure command behaves as expected when an empty file is given -workingdir=$(mktemp -d) -touch "${workingdir}/emptyfile.json" -os::cmd::expect_failure_and_text "oc set build-hook -f ${workingdir}/emptyfile.json --post-commit=true --script=foo" "no resources found" -echo "set build-hook: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdSetbuildhookShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdSetbuildhookSh, nil +func testExtendedTestdataCmdTestCmdQuotaShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdQuotaSh, nil } -func testExtendedTestdataCmdTestCmdSetbuildhookSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdSetbuildhookShBytes() +func testExtendedTestdataCmdTestCmdQuotaSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdQuotaShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/setbuildhook.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/quota.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdSetbuildsecretSh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdRegistrySh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT # Cleanup cluster resources created by this test ( set +e - oc delete all,templates --all + oc delete all --all exit 0 ) &>/dev/null -os::test::junit::declare_suite_start "cmd/builds/setbuildsecret" -# Validate the set build-secret command -arg="-f ${TEST_DATA}/test-bc.yaml" -os::cmd::expect_failure_and_text "oc set build-secret" "error: a secret name must be specified" -os::cmd::expect_failure_and_text "oc set build-secret ${arg}" "error: a secret name must be specified" -os::cmd::expect_failure_and_text "oc set build-secret ${arg} mysecret" "error: specify the type of secret" -os::cmd::expect_success_and_text "oc set build-secret ${arg} mysecret --push --local -o yaml" 'pushSecret:' -os::cmd::expect_success_and_text "oc set build-secret ${arg} mysecret --push --local -o yaml" 'name: mysecret' -os::cmd::expect_success_and_text "oc set build-secret ${arg} mysecret --pull --local -o yaml" 'pullSecret:' -os::cmd::expect_success_and_text "oc set build-secret ${arg} mysecret --pull --local -o yaml" 'name: mysecret' -os::cmd::expect_success_and_text "oc set build-secret ${arg} mysecret --source --local -o yaml" 'sourceSecret:' -os::cmd::expect_success_and_text "oc set build-secret ${arg} mysecret --source --local -o yaml" 'name: mysecret' -os::cmd::expect_success_and_not_text "oc set build-secret ${arg} mysecret --push --local -o yaml | oc set build-secret --local -f - --remove --push -o yaml" 'pushSecret:' -os::cmd::expect_success_and_not_text "oc set build-secret ${arg} mysecret --pull --local -o yaml | oc set build-secret --local -f - --remove --pull -o yaml" 'pullSecret:' -os::cmd::expect_success_and_not_text "oc set build-secret ${arg} mysecret --push --local -o yaml | oc set build-secret --local -f - --remove --source -o yaml" 'sourceSecret:' -# Server object tests -os::cmd::expect_success "oc create -f ${TEST_DATA}/test-bc.yaml" -os::cmd::expect_success_and_text "oc set build-secret test-buildconfig mysecret --push" "updated" -os::cmd::expect_success_and_text "oc set build-secret bc/test-buildconfig mysecret --push --v=1" "was not changed" -os::cmd::expect_success_and_text "oc get bc/test-buildconfig -o yaml" "pushSecret:" -os::cmd::expect_success_and_text "oc set build-secret bc/test-buildconfig --push --remove" "updated" -os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "pushSecret:" -os::cmd::expect_success "oc delete bc/test-buildconfig" -echo "set build-secret: ok" + +os::test::junit::declare_suite_start "cmd/registry/login" +# TODO - re-enable these tests on a real cluster +#os::cmd::expect_success_and_text "oc registry login -z 'default' --registry=localhost:5000 --to=- --skip-check" "auth" +#os::cmd::expect_failure_and_text "oc registry login -z 'default' --registry=localhost2 --to=- 2>&1" "unable to check your credentials" +#os::cmd::expect_success_and_text "oc registry login -z 'default' --registry=localhost2 --to=/tmp/test --skip-check && cat /tmp/test" "localhost2" +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_start "cmd/registry/info" +# TODO - re-enable these tests on a real cluster +#os::cmd::expect_success 'oc tag --source=docker openshift/origin-control-plane:latest newrepo:latest' +#os::cmd::expect_success "oc registry info" +#os::cmd::expect_failure_and_text "oc registry info --internal --public" "only one of --internal or --public" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdSetbuildsecretShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdSetbuildsecretSh, nil +func testExtendedTestdataCmdTestCmdRegistryShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdRegistrySh, nil } -func testExtendedTestdataCmdTestCmdSetbuildsecretSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdSetbuildsecretShBytes() +func testExtendedTestdataCmdTestCmdRegistrySh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdRegistryShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/setbuildsecret.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/registry.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdStatusSh = []byte(`#!/bin/bash - -set -o errexit -set -o nounset -set -o pipefail - -OS_ROOT=$(dirname "${BASH_SOURCE}")/../.. -source "${OS_ROOT}/hack/lib/init.sh" -os::log::stacktrace::install +var _testExtendedTestdataCmdTestCmdRoutesSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT # Cleanup cluster resources created by this test ( set +e - oc delete project project-bar - oc delete project project-status + oc delete route foo bar testroute test-route new-route exit 0 ) &>/dev/null -login_kubeconfig="${ARTIFACT_DIR}/login.kubeconfig" -cp "${KUBECONFIG}" "${login_kubeconfig}" - -os::test::junit::declare_suite_start "cmd/status" -# login and ensure no current projects exist -#os::cmd::expect_success "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${MASTER_CONFIG_DIR}/server-ca.crt' -u test-user2 -p anything" -#os::cmd::expect_success 'oc delete project --all' -#os::cmd::try_until_text "oc get projects -o jsonpath='{.items}'" "^\[\]$" -#os::cmd::expect_success 'oc logout' - -# remove self-provisioner role from user and test login prompt before creating any projects -#os::cmd::expect_success "oc adm policy remove-cluster-role-from-group self-provisioner system:authenticated:oauth --kubeconfig='${login_kubeconfig}'" -# login as 'test-user2' -#os::cmd::expect_success "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${MASTER_CONFIG_DIR}/server-ca.crt' -u test-user2 -p anything" +os::test::junit::declare_suite_start "cmd/routes" -# make sure ` + "`" + `oc status` + "`" + ` re-uses the correct "no projects" message from ` + "`" + `oc login` + "`" + ` with no self-provisioner role -#os::cmd::expect_success_and_text 'oc status' "You don't have any projects. Contact your system administrator to request a project" -os::cmd::expect_success_and_text 'oc status --all-namespaces' "Showing all projects on server" -# make sure standard login prompt is printed once self-provisioner status is restored -#os::cmd::expect_success "oc logout" -#os::cmd::expect_success "oc adm policy add-cluster-role-to-group self-provisioner system:authenticated:oauth --kubeconfig='${login_kubeconfig}'" -#os::cmd::try_until_text "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${MASTER_CONFIG_DIR}/server-ca.crt' -u test-user2 -p anything" "You don't have any projects. You can try to create a new project, by running" $(( 30 * second )) 0.25 +os::cmd::expect_success 'oc get routes' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-route.json' +os::cmd::expect_success_and_text 'oc get routes testroute --show-labels' 'rtlabel1' +os::cmd::expect_success 'oc delete routes testroute' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-service.json' +os::cmd::expect_success 'oc create route passthrough --service=svc/frontend' +os::cmd::expect_success 'oc delete routes frontend' +os::cmd::expect_success 'oc create route edge --path /test --service=services/non-existent --port=80' +os::cmd::expect_success 'oc delete routes non-existent' +os::cmd::expect_success 'oc create route edge test-route --service=frontend' +os::cmd::expect_success 'oc delete routes test-route' +os::cmd::expect_failure 'oc create route edge new-route' +os::cmd::expect_success 'oc delete services frontend' +os::cmd::expect_success 'oc create route edge --insecure-policy=Allow --service=foo --port=80' +os::cmd::expect_success_and_text 'oc get route foo -o jsonpath="{.spec.tls.insecureEdgeTerminationPolicy}"' 'Allow' +os::cmd::expect_success 'oc delete routes foo' -# make sure ` + "`" + `oc status` + "`" + ` re-uses the correct "no projects" message from ` + "`" + `oc login` + "`" + ` -#os::cmd::expect_success_and_text 'oc status' "You don't have any projects. You can try to create a new project, by running" -os::cmd::expect_success_and_text 'oc status -A' "Showing all projects on server" -# make sure ` + "`" + `oc status` + "`" + ` does not re-use the "no projects" message from ` + "`" + `oc login` + "`" + ` if -n is specified -#os::cmd::expect_failure_and_text 'oc status -n forbidden' 'Error from server \(Forbidden\): projects.project.openshift.io "forbidden" is forbidden: User "test-user2" cannot get resource "projects" in API group "project.openshift.io" in the namespace "forbidden"' +os::cmd::expect_success_and_text 'oc create route edge --service foo --port=8080' 'created' +os::cmd::expect_success_and_text 'oc create route edge --service bar --port=9090' 'created' -# create a new project -os::cmd::expect_success "oc new-project project-bar --display-name='my project' --description='test project'" -os::cmd::expect_success_and_text "oc project" 'Using project "project-bar"' +# verify that reencrypt routes with no destination CA return the stub PEM block on the old API +project="$(oc project -q)" +os::cmd::expect_success_and_text 'oc create route reencrypt --service baz --port=9090' 'created' +os::cmd::expect_success_and_not_text 'oc get --raw /apis/route.openshift.io/v1/namespaces/${project}/routes/baz' 'This is an empty PEM file' -# make sure ` + "`" + `oc status` + "`" + ` does not use "no projects" message if there is a project created -os::cmd::expect_success_and_text 'oc status' "In project my project \(project-bar\) on server" -#os::cmd::expect_failure_and_text 'oc status -n forbidden' 'Error from server \(Forbidden\): projects.project.openshift.io "forbidden" is forbidden: User "test-user2" cannot get resource "projects" in API group "project.openshift.io" in the namespace "forbidden"' +os::cmd::expect_success_and_text 'oc set route-backends foo' 'routes/foo' +os::cmd::expect_success_and_text 'oc set route-backends foo' 'Service' +os::cmd::expect_success_and_text 'oc set route-backends foo' '100' +os::cmd::expect_failure_and_text 'oc set route-backends foo --zero --equal' 'error: --zero and --equal may not be specified together' +os::cmd::expect_failure_and_text 'oc set route-backends foo --zero --adjust' 'error: --adjust and --zero may not be specified together' +os::cmd::expect_failure_and_text 'oc set route-backends foo a=' 'expected NAME=WEIGHT' +os::cmd::expect_failure_and_text 'oc set route-backends foo =10' 'expected NAME=WEIGHT' +os::cmd::expect_failure_and_text 'oc set route-backends foo a=a' 'WEIGHT must be a number' +os::cmd::expect_success_and_text 'oc set route-backends foo a=10' 'updated' +os::cmd::expect_success_and_text 'oc set route-backends foo a=100' 'updated' +os::cmd::expect_success_and_text 'oc set route-backends foo a=0' 'updated' +os::cmd::expect_success_and_text 'oc set route-backends foo' '0' +os::cmd::expect_success_and_text 'oc get routes foo' 'a' +os::cmd::expect_success_and_text 'oc set route-backends foo a1=0 b2=0' 'updated' +os::cmd::expect_success_and_text 'oc set route-backends foo' 'a1' +os::cmd::expect_success_and_text 'oc set route-backends foo' 'b2' +os::cmd::expect_success_and_text 'oc set route-backends foo a1=100 b2=50 c3=0' 'updated' +os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(66%\),b2\(33%\),c3\(0%\)' +os::cmd::expect_success_and_text 'oc set route-backends foo a1=100 b2=0 c3=0' 'updated' +os::cmd::expect_success_and_text 'oc set route-backends foo --adjust b2=+10%' 'updated' +os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(90%\),b2\(10%\),c3\(0%\)' +os::cmd::expect_success_and_text 'oc set route-backends foo --adjust b2=+25%' 'updated' +os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(65%\),b2\(35%\),c3\(0%\)' +os::cmd::expect_success_and_text 'oc set route-backends foo --adjust b2=+99%' 'updated' +os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(0%\),b2\(100%\),c3\(0%\)' +os::cmd::expect_success_and_text 'oc set route-backends foo --adjust b2=-51%' 'updated' +os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(51%\),b2\(49%\),c3\(0%\)' +os::cmd::expect_success_and_text 'oc set route-backends foo --adjust a1=20%' 'updated' +os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(20%\),b2\(80%\),c3\(0%\)' +os::cmd::expect_success_and_text 'oc set route-backends foo --adjust c3=50%' 'updated' +os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(10%\),b2\(80%\),c3\(10%\)' +os::cmd::expect_success_and_text 'oc describe routes foo' '25 \(10%\)' +os::cmd::expect_success_and_text 'oc describe routes foo' '200 \(80%\)' +os::cmd::expect_success_and_text 'oc describe routes foo' '25 \(10%\)' +os::cmd::expect_success_and_text 'oc describe routes foo' '' +os::cmd::expect_success_and_text 'oc set route-backends foo --adjust c3=1' 'updated' +os::cmd::expect_success_and_text 'oc describe routes foo' '1 \(0%\)' +os::cmd::expect_success_and_text 'oc set route-backends foo --equal' 'updated' +os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(33%\),b2\(33%\),c3\(33%\)' +os::cmd::expect_success_and_text 'oc describe routes foo' '100 \(33%\)' +os::cmd::expect_success_and_text 'oc set route-backends foo --zero' 'updated' +os::cmd::expect_success_and_text 'oc get routes foo' 'a1\(0%\),b2\(0%\),c3\(0%\)' +os::cmd::expect_success_and_text 'oc describe routes foo' '0' -# create a second project -os::cmd::expect_success "oc new-project project-bar-2 --display-name='my project 2' --description='test project 2'" -os::cmd::expect_success_and_text "oc project" 'Using project "project-bar-2"' +os::test::junit::declare_suite_end +`) -# delete the current project ` + "`" + `project-bar-2` + "`" + ` and make sure ` + "`" + `oc status` + "`" + ` does not return the "no projects" -# message since ` + "`" + `project-bar` + "`" + ` still exists -os::cmd::expect_success_and_text "oc delete project project-bar-2" 'project.project.openshift.io "project-bar-2" deleted' -# the deletion is asynchronous and can take a while, so wait until we see the error -#os::cmd::try_until_text "oc status" 'Error from server \(Forbidden\): projects.project.openshift.io "project-bar-2" is forbidden: User "test-user2" cannot get resource "projects" in API group "project.openshift.io" in the namespace "project-bar-2"' +func testExtendedTestdataCmdTestCmdRoutesShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdRoutesSh, nil +} -# delete "project-bar" and test that ` + "`" + `oc status` + "`" + ` still does not return the "no projects" message. -# Although we are deleting the last remaining project, the current context's namespace is still set -# to it, therefore ` + "`" + `oc status` + "`" + ` should simply return a forbidden error and not the "no projects" message -# until the next time the user logs in. -os::cmd::expect_success "oc project project-bar" -os::cmd::expect_success "oc delete project project-bar" -# the deletion is asynchronous and can take a while, so wait until we see the error -#os::cmd::try_until_text "oc status" 'Error from server \(Forbidden\): projects.project.openshift.io "project-bar" is forbidden: User "test-user2" cannot get resource "projects" in API group "project.openshift.io" in the namespace "project-bar"' -os::cmd::try_until_not_text "oc get projects" "project-bar" -os::cmd::try_until_not_text "oc get projects" "project-bar-2" -#os::cmd::expect_success "oc logout" -#os::cmd::expect_success_and_text "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${MASTER_CONFIG_DIR}/server-ca.crt' -u test-user2 -p anything" "You don't have any projects. You can try to create a new project, by running" -#os::cmd::expect_success_and_text 'oc status' "You don't have any projects. You can try to create a new project, by running" -os::cmd::expect_success "oc new-project project-status --display-name='my project' --description='test project'" +func testExtendedTestdataCmdTestCmdRoutesSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdRoutesShBytes() + if err != nil { + return nil, err + } -# Verify jobs are showing in status -os::cmd::expect_success "oc create job pi --image=perl -- perl -Mbignum=bpi -wle 'print bpi(2000)'" -os::cmd::expect_success_and_text "oc status" "job/pi manages perl" + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/routes.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} -# logout -#os::cmd::expect_success "oc logout" +var _testExtendedTestdataCmdTestCmdRunSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" +trap os::test::junit::reconcile_output EXIT -echo "status: ok" +os::test::junit::declare_suite_start "cmd/run" +# This test validates the value of --image for oc run +os::cmd::expect_success_and_text 'oc create deploymentconfig newdcforimage --image=validimagevalue' 'deploymentconfig.apps.openshift.io/newdcforimage created' +os::cmd::expect_failure_and_text 'oc run newdcforimage2 --image="InvalidImageValue0192"' 'error: Invalid image name "InvalidImageValue0192": invalid reference format' +echo "oc run: ok" os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdStatusShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdStatusSh, nil +func testExtendedTestdataCmdTestCmdRunShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdRunSh, nil } -func testExtendedTestdataCmdTestCmdStatusSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdStatusShBytes() +func testExtendedTestdataCmdTestCmdRunSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdRunShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/status.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/run.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdTemplatesSh = []byte(`#!/bin/bash +var _testExtendedTestdataCmdTestCmdSecretsSh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT # Cleanup cluster resources created by this test ( set +e - oc delete all,templates --all - oc delete template/ruby-helloworld-sample -n openshift - oc delete project test-template-project - oc delete user someval someval=moreval someval=moreval2 someval=moreval3 + oc delete all,templates,secrets --all exit 0 ) &>/dev/null -os::test::junit::declare_suite_start "cmd/templates" -# This test validates template commands - -os::test::junit::declare_suite_start "cmd/templates/basic" -os::cmd::expect_success 'oc get templates' -os::cmd::expect_success 'oc create -f ${TEST_DATA}/application-template-dockerbuild.json' -os::cmd::expect_success 'oc get templates' -os::cmd::expect_success 'oc get templates ruby-helloworld-sample' -os::cmd::expect_success 'oc get template ruby-helloworld-sample -o json | oc process -f -' -os::cmd::expect_success 'oc process ruby-helloworld-sample' -os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o template --template "{{.kind}}"' "List" -os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o go-template --template "{{.kind}}"' "List" -os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o go-template={{.kind}}' "List" -os::cmd::expect_success 'oc process ruby-helloworld-sample -o go-template-file=/dev/null' -os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o jsonpath --template "{.kind}"' "List" -os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o jsonpath={.kind}' "List" -os::cmd::expect_success 'oc process ruby-helloworld-sample -o jsonpath-file=/dev/null' -os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o describe' "ruby-27-centos7" -os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o json' "ruby-27-centos7" -os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o yaml' "ruby-27-centos7" -os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o name' "ruby-27-centos7" -os::cmd::expect_success_and_text 'oc describe templates ruby-helloworld-sample' "BuildConfig.*ruby-sample-build" -os::cmd::expect_success 'oc delete templates ruby-helloworld-sample' -os::cmd::expect_success 'oc get templates' -# TODO: create directly from template -echo "templates: ok" -os::test::junit::declare_suite_end - -os::test::junit::declare_suite_start "cmd/templates/config" -guestbook_template="${TEST_DATA}/templates/guestbook.json" -os::cmd::expect_success "oc process -f '${guestbook_template}' -l app=guestbook | oc create -f -" -os::cmd::expect_success_and_text 'oc status' 'frontend-service' -echo "template+config: ok" - -os::test::junit::declare_suite_start "cmd/templates/local-config" -# Processes the template locally -os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --local -l app=guestbook -o yaml" "app: guestbook" -# Processes the template locally and get the same output in YAML -new="$(mktemp -d)" -os::cmd::expect_success 'oc process -f "${guestbook_template}" --local -l app=guestbook -o yaml ADMIN_USERNAME=au ADMIN_PASSWORD=ap REDIS_PASSWORD=rp > "${new}/localtemplate"' -os::cmd::expect_success 'oc process -f "${guestbook_template}" -l app=guestbook -o yaml ADMIN_USERNAME=au ADMIN_PASSWORD=ap REDIS_PASSWORD=rp > "${new}/remotetemplate"' -os::cmd::expect_success 'diff "${new}/localtemplate" "${new}/remotetemplate"' -# Does not even try to hit the server -os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --local -l app=guestbook -o yaml --server 0.0.0.0:1" "app: guestbook" -echo "template+config+local: ok" -os::test::junit::declare_suite_end - -os::test::junit::declare_suite_start "cmd/templates/parameters" -guestbook_params="${TEST_DATA}/templates/guestbook.env" -# Individually specified parameter values are honored -os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' -p ADMIN_USERNAME=myuser -p ADMIN_PASSWORD=mypassword" '"myuser"' -os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' -p ADMIN_USERNAME=myuser -p ADMIN_PASSWORD=mypassword" '"mypassword"' -# Argument values are honored -os::cmd::expect_success_and_text "oc process ADMIN_USERNAME=myuser ADMIN_PASSWORD=mypassword -f '${guestbook_template}'" '"myuser"' -os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' ADMIN_USERNAME=myuser ADMIN_PASSWORD=mypassword" '"mypassword"' -# Argument values with commas are honored -os::cmd::expect_success 'oc create -f ${TEST_DATA}/application-template-stibuild.json' -os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample MYSQL_USER=myself MYSQL_PASSWORD=my,1%pa=s' '"myself"' -os::cmd::expect_success_and_text 'oc process MYSQL_USER=myself MYSQL_PASSWORD=my,1%pa=s ruby-helloworld-sample' '"my,1%pa=s"' -os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -p MYSQL_USER=myself -p MYSQL_PASSWORD=my,1%pa=s' '"myself"' -os::cmd::expect_success_and_text 'oc process -p MYSQL_USER=myself -p MYSQL_PASSWORD=my,1%pa=s ruby-helloworld-sample' '"my,1%pa=s"' -# Argument values can be read from file -os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --param-file='${guestbook_params}'" '"root"' -os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --param-file='${guestbook_params}'" '"adminpass"' -os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --param-file='${guestbook_params}'" '"redispass"' -# Argument values can be read from stdin -os::cmd::expect_success_and_text "cat '${guestbook_params}' | oc process -f '${guestbook_template}' --param-file=-" '"root"' -os::cmd::expect_success_and_text "cat '${guestbook_params}' | oc process -f '${guestbook_template}' --param-file=-" '"adminpass"' -os::cmd::expect_success_and_text "cat '${guestbook_params}' | oc process -f '${guestbook_template}' --param-file=-" '"redispass"' -# Argument values from command line have precedence over those from file -os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --param-file='${guestbook_params}' -p ADMIN_USERNAME=myuser" 'ignoring value from file' -os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --param-file='${guestbook_params}' -p ADMIN_USERNAME=myuser" '"myuser"' -os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --param-file='${guestbook_params}' -p ADMIN_PASSWORD=mypassword" '"mypassword"' -os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --param-file='${guestbook_params}' -p REDIS_PASSWORD=rrr" '"rrr"' -# Set template parameters from parameter file with multiline values -os::cmd::expect_success_and_text "oc process -f ${TEST_DATA}/templates/template_required_params.yaml --param-file=${TEST_DATA}/templates/template_required_params.env -o yaml" 'first$' -os::cmd::expect_success 'oc delete template ruby-helloworld-sample' -# Parameter file failure cases -os::cmd::expect_failure_and_text "oc process -f ${TEST_DATA}/templates/template_required_params.yaml --param-file=does/not/exist" 'no such file or directory' -os::cmd::expect_failure_and_text "oc process -f ${TEST_DATA}/templates/template_required_params.yaml --param-file=${TEST_DATA}" 'is a directory' -os::cmd::expect_failure_and_text "oc process -f ${TEST_DATA}/templates/template_required_params.yaml --param-file=/dev/null" 'parameter required_param is required and must be specified' -os::cmd::expect_success "oc process -f '${guestbook_template}' --param-file=/dev/null --param-file='${guestbook_params}'" -os::cmd::expect_failure_and_text "echo 'fo%(o=bar' | oc process -f ${TEST_DATA}/templates/template_required_params.yaml --param-file=-" 'invalid parameter assignment' -os::cmd::expect_failure_and_text "echo 'S P A C E S=test' | oc process -f ${TEST_DATA}/templates/template_required_params.yaml --param-file=-" 'invalid parameter assignment' -# Handle absent parameter -os::cmd::expect_failure_and_text "oc process -f '${guestbook_template}' -p ABSENT_PARAMETER=absent" 'unknown parameter name' -os::cmd::expect_success "oc process -f '${guestbook_template}' -p ABSENT_PARAMETER=absent --ignore-unknown-parameters" -echo "template+parameters: ok" -os::test::junit::declare_suite_end - -os::test::junit::declare_suite_start "cmd/templates/data-precision" -# Run as cluster-admin to allow choosing any supplemental groups we want -# Ensure large integers survive unstructured JSON creation -os::cmd::expect_success 'oc create -f ${TEST_DATA}/templates/template-type-precision.json' -# ... and processing -os::cmd::expect_success_and_text 'oc process template-type-precision' '1000030003' -os::cmd::expect_success_and_text 'oc process template-type-precision' '2147483647' -os::cmd::expect_success_and_text 'oc process template-type-precision' '9223372036854775807' -# ... and re-encoding as structured resources -os::cmd::expect_success 'oc process template-type-precision | oc create -f -' -# ... and persisting -os::cmd::expect_success_and_text 'oc get pod/template-type-precision -o json' '1000030003' -os::cmd::expect_success_and_text 'oc get pod/template-type-precision -o json' '2147483647' -os::cmd::expect_success_and_text 'oc get pod/template-type-precision -o json' '9223372036854775807' -# Ensure patch computation preserves data -patch='{"metadata":{"annotations":{"comment":"patch comment"}}}' -os::cmd::expect_success "oc patch pod template-type-precision -p '${patch}'" -os::cmd::expect_success_and_text 'oc get pod/template-type-precision -o json' '9223372036854775807' -os::cmd::expect_success_and_text 'oc get pod/template-type-precision -o json' 'patch comment' -os::cmd::expect_success 'oc delete template/template-type-precision' -os::cmd::expect_success 'oc delete pod/template-type-precision' -echo "template data precision: ok" -os::test::junit::declare_suite_end - -os::test::junit::declare_suite_start "cmd/templates/different-namespaces" -#os::cmd::expect_success 'oc create -f ${TEST_DATA}/application-template-dockerbuild.json -n openshift' -#os::cmd::expect_success 'oc policy add-role-to-user admin test-user' -#new="$(mktemp -d)/tempconfig" -#os::cmd::expect_success "oc config view --raw > ${new}" -#old="${KUBECONFIG}" -#export KUBECONFIG=${new} -#os::cmd::expect_success 'oc login -u test-user -p password' -#os::cmd::expect_success 'oc new-project test-template-project' -## make sure the permissions on the new project are set up -#os::cmd::try_until_success 'oc get templates' -#os::cmd::expect_success 'oc create -f ${TEST_DATA}/application-template-dockerbuild.json' -#os::cmd::expect_success 'oc process template/ruby-helloworld-sample' -#os::cmd::expect_success 'oc process templates/ruby-helloworld-sample' -#os::cmd::expect_success 'oc process openshift//ruby-helloworld-sample' -#os::cmd::expect_success 'oc process openshift/template/ruby-helloworld-sample' -#os::cmd::expect_success 'oc get template ruby-helloworld-sample -n openshift -o yaml | oc process -f -' -#export KUBECONFIG=${old} -echo "processing templates in different namespace: ok" -os::test::junit::declare_suite_end +os::test::junit::declare_suite_start "cmd/secrets" +# This test validates secret interaction +touch Makefile +os::cmd::expect_success 'oc create secret generic foo --type=blah --from-file=makefile=Makefile' +os::cmd::expect_success_and_text 'oc get secrets/foo -o jsonpath={.type}' 'blah' -os::test::junit::declare_suite_start "cmd/templates/process" -# This test validates oc process -# fail to process two templates by name -os::cmd::expect_failure_and_text 'oc process name1 name2' 'template name must be specified only once' -# fail to pass a filename or template by name -os::cmd::expect_failure_and_text 'oc process' 'Must pass a filename or name of stored template' -# can't ask for parameters and try process the template -os::cmd::expect_failure_and_text 'oc process template-name --parameters --param=someval' '\-\-parameters flag does not process the template, can.t be used with \-\-param' -os::cmd::expect_failure_and_text 'oc process template-name --parameters -p someval' '\-\-parameters flag does not process the template, can.t be used with \-\-param' -os::cmd::expect_failure_and_text 'oc process template-name --parameters --labels=someval' '\-\-parameters flag does not process the template, can.t be used with \-\-labels' -os::cmd::expect_failure_and_text 'oc process template-name --parameters -l someval' '\-\-parameters flag does not process the template, can.t be used with \-\-labels' -os::cmd::expect_failure_and_text 'oc process template-name --parameters --output=yaml' '\-\-parameters flag does not process the template, can.t be used with \-\-output' -os::cmd::expect_failure_and_text 'oc process template-name --parameters -o yaml' '\-\-parameters flag does not process the template, can.t be used with \-\-output' -os::cmd::expect_failure_and_text 'oc process template-name --parameters --raw' '\-\-parameters flag does not process the template, can.t be used with \-\-raw' -os::cmd::expect_failure_and_text 'oc process template-name --parameters --template=someval' '\-\-parameters flag does not process the template, can.t be used with \-\-template' -# providing a value more than once should fail -os::cmd::expect_failure_and_text 'oc process template-name key=value key=value' 'provided more than once: key' -os::cmd::expect_failure_and_text 'oc process template-name --param=key=value --param=key=value' 'provided more than once: key' -os::cmd::expect_failure_and_text 'oc process template-name key=value --param=key=value' 'provided more than once: key' -os::cmd::expect_failure_and_text 'oc process template-name key=value other=foo --param=key=value --param=other=baz' 'provided more than once: key, other' -required_params="${TEST_DATA}/templates/template_required_params.yaml" -# providing something other than a template is not OK -os::cmd::expect_failure_and_text "oc process -f '${TEST_DATA}/templates/basic-users-binding.json'" 'not a valid Template but' -# not providing required parameter should fail -os::cmd::expect_failure_and_text "oc process -f '${required_params}'" 'parameter required_param is required and must be specified' -# not providing an optional param is OK -os::cmd::expect_success "oc process -f '${required_params}' --param=required_param=someval" -os::cmd::expect_success "oc process -f '${required_params}' -p required_param=someval | oc create -f -" -# parameters with multiple equal signs are OK -os::cmd::expect_success "oc process -f '${required_params}' required_param=someval=moreval | oc create -f -" -os::cmd::expect_success "oc process -f '${required_params}' -p required_param=someval=moreval2 | oc create -f -" -os::cmd::expect_success "oc process -f '${required_params}' -p required_param=someval=moreval3 | oc create -f -" -# we should have overwritten the template param -os::cmd::expect_success_and_text 'oc get user someval -o jsonpath={.metadata.name}' 'someval' -os::cmd::expect_success_and_text 'oc get user someval=moreval -o jsonpath={.metadata.name}' 'someval=moreval' -os::cmd::expect_success_and_text 'oc get user someval=moreval2 -o jsonpath={.metadata.name}' 'someval=moreval2' -os::cmd::expect_success_and_text 'oc get user someval=moreval3 -o jsonpath={.metadata.name}' 'someval=moreval3' -# providing a value not in the template should fail -os::cmd::expect_failure_and_text "oc process -f '${required_params}' --param=required_param=someval --param=other_param=otherval" 'unknown parameter name "other_param"' -# failure on values fails the entire call -os::cmd::expect_failure_and_text "oc process -f '${required_params}' --param=required_param=someval --param=optional_param" 'invalid parameter assignment in' -# failure on labels fails the entire call -os::cmd::expect_failure_and_text "oc process -f '${required_params}' --param=required_param=someval --labels======" 'error parsing labels' -# values are not split on commas, required parameter is not recognized -os::cmd::expect_failure_and_text "oc process -f '${required_params}' --param=optional_param=a,required_param=b" 'parameter required_param is required and must be specified' -# warning is printed iff --value/--param looks like two k-v pairs separated by comma -os::cmd::expect_success_and_text "oc process -f '${required_params}' --param=required_param=a,b=c,d" 'no longer accepts comma-separated list' -os::cmd::expect_success_and_not_text "oc process -f '${required_params}' --param=required_param=a_b_c_d" 'no longer accepts comma-separated list' -os::cmd::expect_success_and_not_text "oc process -f '${required_params}' --param=required_param=a,b,c,d" 'no longer accepts comma-separated list' -# warning is not printed for template values passed as positional arguments -os::cmd::expect_success_and_not_text "oc process -f '${required_params}' required_param=a,b=c,d" 'no longer accepts comma-separated list' -# set template parameter to contents of file -os::cmd::expect_success_and_text "oc process -f '${required_params}' --param=required_param='` + "`" + `cat ${TEST_DATA}/templates/multiline.txt` + "`" + `'" 'also,with=commas' -echo "process: ok" -os::test::junit::declare_suite_end +os::cmd::expect_success 'oc create secret docker-registry dockerconfigjson --docker-username=sample-user --docker-password=sample-password --docker-email=fake@example.org' +# can't use a go template here because the output needs to be base64 decoded. base64 isn't installed by default in all distros +os::cmd::expect_success "oc get secrets/dockerconfigjson -o jsonpath='{ .data.\.dockerconfigjson }' | base64 -d > ${HOME}/dockerconfigjson" +os::cmd::expect_success 'oc create secret generic from-file --from-file=.dockerconfigjson=${HOME}/dockerconfigjson --type=kubernetes.io/dockerconfigjson' +# check to make sure the type was correctly auto-detected +os::cmd::expect_success_and_text 'oc get secret/from-file --template="{{ .type }}"' 'kubernetes.io/dockerconfigjson' +# make sure the -o works correctly +os::cmd::expect_success_and_text 'oc create secret docker-registry dockerconfigjson --docker-username=sample-user --docker-password=sample-password --docker-email=fake@example.org --dry-run -o yaml' 'kubernetes.io/dockerconfigjson' +os::cmd::expect_success_and_text 'oc create secret generic from-file-again --from-file=.dockerconfigjson=${HOME}/dockerconfigjson --type=kubernetes.io/dockerconfigjson -o yaml' 'kubernetes.io/dockerconfigjson' +# check to make sure malformed names fail as expected +# TODO(jchaloup): "error: Key names or file paths cannot contain '='" changed into "error: key names or file paths cannot contain '='" (s/K/k) +# Once oc rebase to 1.20 is merged, enable this test again with s/K/k +# os::cmd::expect_failure_and_text 'oc create secret generic bad-name --from-file=.docker=cfg=${HOME}/dockerconfigjson' "error: key names or file paths cannot contain '='" -os::test::junit::declare_suite_end -`) +workingdir="$( mktemp -d )" +os::cmd::try_until_success "oc get secret/dockerconfigjson" +os::cmd::expect_success_and_text "oc extract secret/dockerconfigjson --to '${workingdir}'" '.dockerconfigjson' +os::cmd::expect_success_and_text "oc extract secret/dockerconfigjson --to=-" 'sample-user' +os::cmd::expect_success_and_text "oc extract secret/dockerconfigjson --to=-" 'sample-password' +os::cmd::expect_success_and_text "cat '${workingdir}/.dockerconfigjson'" 'sample-user' +os::cmd::expect_failure_and_text "oc extract secret/dockerconfigjson --to '${workingdir}'" 'error: .dockerconfigjson: file exists, pass --confirm to overwrite' +os::cmd::expect_failure_and_text "oc extract secret/dockerconfigjson secret/dockerconfigjson --to '${workingdir}'" 'error: .dockerconfigjson: file exists, pass --confirm to overwrite' +os::cmd::expect_success_and_text "oc extract secret/dockerconfigjson secret/dockerconfigjson --to '${workingdir}' --confirm" '.dockerconfigjson' +os::cmd::expect_success_and_text "oc extract secret/dockerconfigjson --to '${workingdir}' --confirm" '.dockerconfigjson' +os::cmd::expect_success "oc extract secret/dockerconfigjson --to '${workingdir}' --confirm | xargs rm" +os::cmd::expect_failure_and_text "oc extract secret/dockerconfigjson --to missing-dir" "stat missing-dir: no such file or directory" -func testExtendedTestdataCmdTestCmdTemplatesShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTemplatesSh, nil -} +# attach secrets to service account +# single secret with prefix +os::cmd::expect_success 'oc secrets link deployer dockerconfigjson' +# don't add the same secret twice +os::cmd::expect_success 'oc secrets link serviceaccounts/deployer dockerconfigjson secrets/from-file' +# make sure we can add as as pull secret +os::cmd::expect_success 'oc secrets link deployer dockerconfigjson from-file --for=pull' +# make sure we can add as as pull secret and mount secret at once +os::cmd::expect_success 'oc secrets link serviceaccounts/deployer secrets/dockerconfigjson secrets/from-file --for=pull,mount' -func testExtendedTestdataCmdTestCmdTemplatesSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTemplatesShBytes() - if err != nil { - return nil, err - } +GIT_CONFIG_PATH="${ARTIFACT_DIR}/.gitconfig" +touch "${GIT_CONFIG_PATH}" +#git config --file "${GIT_CONFIG_PATH}" user.name sample-user +#git config --file "${GIT_CONFIG_PATH}" user.token password - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/templates.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil +function create_valid_file() { + echo test_data > "${ARTIFACT_DIR}/${1}" + echo "${ARTIFACT_DIR}/${1}" } -var _testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexAppDockerfile = []byte(`FROM node:0.10.38 +CA_CERT_PATH=$(create_valid_file ca.pem) +PRIVATE_KEY_PATH=$(create_valid_file id_rsa) -RUN mkdir /src +os::cmd::expect_success "oc create secret generic basicauth --type=kubernetes.io/basic-auth --from-literal=username=sample-user --from-literal=password=sample-password --from-file=gitconfig='${GIT_CONFIG_PATH}' --from-file=ca-cert='${CA_CERT_PATH}'" +# check to make sure incorrect .gitconfig path fail as expected +os::cmd::expect_failure_and_text 'oc create secret generic bad-file --type=kubernetes.io/basic-auth --from-literal=username=user --from-file=gitconfig=/bad/path' 'error reading /bad/path: no such file or directory' -RUN npm install nodemon -g +os::cmd::expect_success "oc create secret generic sshauth --from-file=ssh-privatekey='${PRIVATE_KEY_PATH}' --from-file=ca-cert='${CA_CERT_PATH}'" +# check to make sure incorrect SSH private-key path fail as expected +os::cmd::expect_failure_and_text 'oc create secret generic bad-file --from-file=ssh-privatekey=/bad/path' 'error reading /bad/path: no such file or directory' -WORKDIR /src -ADD package.json package.json -RUN npm install +# attach secrets to service account +# single secret with prefix +os::cmd::expect_success 'oc secrets link deployer basicauth' +# don't add the same secret twice +os::cmd::expect_success 'oc secrets link deployer basicauth sshauth' +# make sure we can add as as pull secret +os::cmd::expect_success 'oc secrets link deployer basicauth sshauth --for=pull' +# make sure we can add as as pull secret and mount secret at once +os::cmd::expect_success 'oc secrets link deployer basicauth sshauth --for=pull,mount' -ADD nodemon.json nodemon.json -`) +# attach secrets to service account +# test that those secrets can be unlinked +# after they have been deleted. +os::cmd::expect_success 'oc create secret generic deleted-secret' +os::cmd::expect_success 'oc secrets link deployer deleted-secret' +# confirm our soon-to-be-deleted secret has been linked +os::cmd::expect_success_and_text "oc get serviceaccount deployer -o jsonpath='{.secrets[?(@.name==\"deleted-secret\")]}'" 'deleted\-secret' +# delete "deleted-secret" and attempt to unlink from service account +os::cmd::expect_success 'oc delete secret deleted-secret' +os::cmd::expect_failure_and_text 'oc secrets unlink deployer secrets/deleted-secret' 'Unlinked deleted secrets' +# ensure already-deleted secret has been unlinked +os::cmd::expect_success_and_not_text "oc get serviceaccount deployer -o jsonpath='{.secrets[?(@.name==\"deleted-secret\")]}'" 'deleted\-secret' -func testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexAppDockerfileBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexAppDockerfile, nil -} +# attach secrets to service account +# single secret with prefix +os::cmd::expect_success 'oc secrets link deployer basicauth' +# don't add the same secret twice +os::cmd::expect_success 'oc secrets link deployer basicauth sshauth' +# make sure we can add as as pull secret +os::cmd::expect_success 'oc secrets link deployer basicauth sshauth --for=pull' +# make sure we can add as as pull secret and mount secret at once +os::cmd::expect_success 'oc secrets link deployer basicauth sshauth --for=pull,mount' -func testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexAppDockerfile() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexAppDockerfileBytes() - if err != nil { - return nil, err - } +# Confirm that all the linked secrets are present +os::cmd::expect_success 'oc get serviceaccounts/deployer -o yaml |grep -q basicauth' +os::cmd::expect_success 'oc get serviceaccounts/deployer -o yaml |grep -q sshauth' - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/app/Dockerfile", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +# Remove secrets from service account +os::cmd::expect_success 'oc secrets unlink deployer basicauth' +# Confirm that the secret was removed +os::cmd::expect_failure 'oc get serviceaccounts/deployer -o yaml |grep -q basicauth' -var _testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeGeneratedYaml = []byte(`apiVersion: v1 -items: -- apiVersion: v1 - kind: ImageStream - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: nginx - spec: - tags: - - annotations: - openshift.io/imported-from: tutum/nginx - from: - kind: DockerImage - name: tutum/nginx - generation: null - importPolicy: {} - name: from - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: BuildConfig - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: nginx - spec: - output: - to: - kind: ImageStreamTag - name: nginx:latest - postCommit: {} - resources: {} - source: - contextDir: test/testdata/app-scenarios/docker-compose/complex/nginx - git: - ref: libcompose - uri: git@github.com:openshift/origin.git - secrets: null - type: Git - strategy: - dockerStrategy: - from: - kind: ImageStreamTag - name: nginx:from - type: Docker - triggers: - - github: - secret: IE96Fw4CdQs-g3giIjWZ - type: GitHub - - generic: - secret: B8mx-lYjIBjNY6ymP6MT - type: Generic - - type: ConfigChange - - imageChange: {} - type: ImageChange - status: - lastVersion: 0 -- apiVersion: v1 - kind: ImageStream - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: web - spec: - tags: - - annotations: - openshift.io/imported-from: node:0.10.38 - from: - kind: DockerImage - name: node:0.10.38 - generation: null - importPolicy: {} - name: from - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: BuildConfig - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: web - spec: - output: - to: - kind: ImageStreamTag - name: web:latest - postCommit: {} - resources: {} - source: - contextDir: test/testdata/app-scenarios/docker-compose/complex/app - git: - ref: libcompose - uri: git@github.com:openshift/origin.git - secrets: null - type: Git - strategy: - dockerStrategy: - from: - kind: ImageStreamTag - name: web:from - type: Docker - triggers: - - github: - secret: xMiKAo9EEZMKMxCRZSUk - type: GitHub - - generic: - secret: doIIibCQIxRvv28uyP9J - type: Generic - - type: ConfigChange - - imageChange: {} - type: ImageChange - status: - lastVersion: 0 -- apiVersion: v1 - kind: ImageStream - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: db - spec: - tags: - - annotations: - openshift.io/imported-from: redis - from: - kind: DockerImage - name: redis - generation: null - importPolicy: {} - name: latest - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: DeploymentConfig - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: db - spec: - replicas: 1 - selector: - deploymentconfig: db - strategy: - resources: {} - template: - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - deploymentconfig: db - spec: - containers: - - image: redis - name: db - ports: - - containerPort: 6379 - resources: - limits: - cpu: 100m - memory: 1G - test: false - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - db - from: - kind: ImageStreamTag - name: db:latest - type: ImageChange - status: {} -- apiVersion: v1 - kind: DeploymentConfig - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: nginx - spec: - replicas: 1 - selector: - deploymentconfig: nginx - strategy: - resources: {} - template: - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - deploymentconfig: nginx - spec: - containers: - - image: nginx - name: nginx - ports: - - containerPort: 80 - resources: {} - volumeMounts: - - mountPath: /www/public - name: dir-1 - - mountPath: /src/app - name: dir-2 - - args: - - nodemon - - -L - - app/bin/www - image: web - name: web - ports: - - containerPort: 3000 - resources: - requests: - cpu: 500m - volumeMounts: - - mountPath: /src/app - name: dir-2 - volumes: - - emptyDir: {} - name: dir-1 - - emptyDir: {} - name: dir-2 - test: false - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - nginx - from: - kind: ImageStreamTag - name: nginx:latest - type: ImageChange - - imageChangeParams: - automatic: true - containerNames: - - web - from: - kind: ImageStreamTag - name: web:latest - type: ImageChange - status: {} -- apiVersion: v1 - kind: Service - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: redis - spec: - ports: - - name: 6379-tcp - port: 6379 - targetPort: 6379 - selector: - deploymentconfig: db - status: - loadBalancer: {} -- apiVersion: v1 - kind: Service - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: nginx - spec: - ports: - - name: 80-tcp - port: 80 - targetPort: 80 - - name: 3000-tcp - port: 3000 - targetPort: 3000 - selector: - deploymentconfig: nginx - status: - loadBalancer: {} -kind: List -metadata: {} -`) +# Re-link that secret +os::cmd::expect_success 'oc secrets link deployer basicauth' -func testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeGeneratedYamlBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeGeneratedYaml, nil -} +# Removing a non-existent secret should warn but succeed and change nothing +os::cmd::expect_failure_and_text 'oc secrets unlink deployer foobar' 'secret "foobar" not found' -func testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeGeneratedYaml() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeGeneratedYamlBytes() - if err != nil { - return nil, err - } +# Make sure that removing an existent and non-existent secret succeeds but warns about the non-existent one +os::cmd::expect_failure_and_text 'oc secrets unlink deployer foobar basicauth' 'secret "foobar" not found' +# Make sure that the existing secret is removed +os::cmd::expect_failure 'oc get serviceaccounts/deployer -o yaml |grep -q basicauth' - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.generated.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +# Make sure that removing a real but unlinked secret succeeds +# https://github.com/openshift/origin/pull/9234#discussion_r70832486 +os::cmd::expect_failure_and_text 'oc secrets unlink deployer basicauth', 'No valid secrets found or secrets not linked to service account' -var _testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeImportedYaml = []byte(`apiVersion: v1 -items: -- apiVersion: v1 - kind: ImageStream - metadata: - creationTimestamp: null - name: nginx - spec: - tags: - - annotations: - openshift.io/imported-from: tutum/nginx - from: - kind: DockerImage - name: tutum/nginx - generation: null - importPolicy: {} - name: from - referencePolicy: - type: "" - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: BuildConfig - metadata: - creationTimestamp: null - name: nginx - spec: - nodeSelector: null - output: - to: - kind: ImageStreamTag - name: nginx:latest - postCommit: {} - resources: {} - source: - contextDir: test/testdata/app-scenarios/docker-compose/complex/nginx - git: - ref: master - uri: git@github.com:openshift/origin.git - secrets: null - type: Git - strategy: - dockerStrategy: - from: - kind: ImageStreamTag - name: nginx:from - type: Docker - triggers: - - github: - secret: FdDzZzJCBkHQGxYMMBw0 - type: GitHub - - generic: - secret: wMAV07N8TWt9dz40LDjL - type: Generic - - type: ConfigChange - - imageChange: {} - type: ImageChange - status: - lastVersion: 0 -- apiVersion: v1 - kind: ImageStream - metadata: - creationTimestamp: null - name: web - spec: - tags: - - annotations: - openshift.io/imported-from: node:0.10.38 - from: - kind: DockerImage - name: node:0.10.38 - generation: null - importPolicy: {} - name: from - referencePolicy: - type: "" - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: BuildConfig - metadata: - creationTimestamp: null - name: web - spec: - nodeSelector: null - output: - to: - kind: ImageStreamTag - name: web:latest - postCommit: {} - resources: {} - source: - contextDir: test/testdata/app-scenarios/docker-compose/complex/app - git: - ref: master - uri: git@github.com:openshift/origin.git - secrets: null - type: Git - strategy: - dockerStrategy: - from: - kind: ImageStreamTag - name: web:from - type: Docker - triggers: - - github: - secret: 3QSLvrej6A2E-CMYSEvQ - type: GitHub - - generic: - secret: uBl0LIK0anHOaRJ8-4dI - type: Generic - - type: ConfigChange - - imageChange: {} - type: ImageChange - status: - lastVersion: 0 -- apiVersion: v1 - kind: ImageStream - metadata: - creationTimestamp: null - name: db - spec: - tags: - - annotations: - openshift.io/imported-from: redis - from: - kind: DockerImage - name: redis - generation: null - importPolicy: {} - name: latest - referencePolicy: - type: "" - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: null - name: db - spec: - replicas: 1 - selector: - deploymentconfig: db - strategy: - resources: {} - template: - metadata: - creationTimestamp: null - labels: - deploymentconfig: db - spec: - containers: - - image: redis - name: db - ports: - - containerPort: 6379 - resources: - limits: - cpu: 100m - memory: 1G - test: false - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - db - from: - kind: ImageStreamTag - name: db:latest - type: ImageChange - status: - availableReplicas: 0 - latestVersion: 0 - observedGeneration: 0 - replicas: 0 - unavailableReplicas: 0 - updatedReplicas: 0 -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: null - name: nginx - spec: - replicas: 1 - selector: - deploymentconfig: nginx - strategy: - resources: {} - template: - metadata: - creationTimestamp: null - labels: - deploymentconfig: nginx - spec: - containers: - - image: nginx - name: nginx - ports: - - containerPort: 80 - resources: {} - volumeMounts: - - mountPath: /www/public - name: dir-1 - - mountPath: /src/app - name: dir-2 - - args: - - nodemon - - -L - - app/bin/www - image: web - name: web - ports: - - containerPort: 3000 - resources: - requests: - cpu: 500m - volumeMounts: - - mountPath: /src/app - name: dir-2 - volumes: - - emptyDir: {} - name: dir-1 - - emptyDir: {} - name: dir-2 - test: false - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - nginx - from: - kind: ImageStreamTag - name: nginx:latest - type: ImageChange - - imageChangeParams: - automatic: true - containerNames: - - web - from: - kind: ImageStreamTag - name: web:latest - type: ImageChange - status: - availableReplicas: 0 - latestVersion: 0 - observedGeneration: 0 - replicas: 0 - unavailableReplicas: 0 - updatedReplicas: 0 -- apiVersion: v1 - kind: ImageStream - metadata: - creationTimestamp: null - name: no-ports - spec: - tags: - - annotations: - openshift.io/imported-from: redis - from: - kind: DockerImage - name: redis - generation: null - importPolicy: {} - name: latest - referencePolicy: - type: "" - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: null - name: no-ports - spec: - replicas: 1 - selector: - deploymentconfig: no-ports - strategy: - resources: {} - template: - metadata: - creationTimestamp: null - labels: - deploymentconfig: no-ports - spec: - containers: - - image: redis - name: no-ports - resources: {} - test: false - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - no-ports - from: - kind: ImageStreamTag - name: no-ports:latest - type: ImageChange - status: - availableReplicas: 0 - latestVersion: 0 - observedGeneration: 0 - replicas: 0 - unavailableReplicas: 0 - updatedReplicas: 0 -- apiVersion: v1 - kind: Service - metadata: - creationTimestamp: null - name: redis - spec: - ports: - - name: 6379-tcp - port: 6379 - targetPort: 6379 - selector: - deploymentconfig: db - status: - loadBalancer: {} -- apiVersion: v1 - kind: Service - metadata: - creationTimestamp: null - name: nginx - spec: - ports: - - name: 80-tcp - port: 80 - targetPort: 80 - - name: 3000-tcp - port: 3000 - targetPort: 3000 - selector: - deploymentconfig: nginx - status: - loadBalancer: {} -kind: List -metadata: {} +# Make sure that it succeeds if *any* of the secrets are linked +# https://github.com/openshift/origin/pull/9234#discussion_r70832486 +os::cmd::expect_success 'oc secrets unlink deployer basicauth sshauth' + +# Confirm that the linked one was removed +os::cmd::expect_failure 'oc get serviceaccounts/deployer -o yaml |grep -q sshauth' + +# command alias +os::cmd::expect_success 'oc secret --help' +os::cmd::expect_success 'oc secret new --help' +os::cmd::expect_success 'oc secret new-dockercfg --help' +os::cmd::expect_success 'oc secret new-basicauth --help' +os::cmd::expect_success 'oc secret new-sshauth --help' +os::cmd::expect_success 'oc secret add --help' +os::cmd::expect_success 'oc secret link --help' +os::cmd::expect_success 'oc secret unlink --help' + +echo "secrets: ok" +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_start "cmd/serviceaccounts-create-kubeconfig" +os::cmd::expect_success "oc serviceaccounts create-kubeconfig default > '${BASETMPDIR}/generated_default.kubeconfig'" +os::cmd::expect_success_and_text "KUBECONFIG='${BASETMPDIR}/generated_default.kubeconfig' oc whoami" "system:serviceaccount:$(oc project -q):default" +echo "serviceaccounts: ok" +os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeImportedYamlBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeImportedYaml, nil +func testExtendedTestdataCmdTestCmdSecretsShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdSecretsSh, nil } -func testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeImportedYaml() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeImportedYamlBytes() +func testExtendedTestdataCmdTestCmdSecretsSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdSecretsShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.imported.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/secrets.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeYml = []byte(`web: - build: ./app - volumes: - - "./app:/src/app" - ports: - - "3030:3000" - links: - - "db:redis" - command: nodemon -L app/bin/www - cpu_shares: 512 - -nginx: - restart: always - build: ./nginx/ - ports: - - "80:80" - volumes: - - /www/public - volumes_from: - - web - links: - - web:web - -db: - image: redis - ports: - - "6379:6379" - cpu_quota: 10000 - mem_limit: 1000000000 - cpuset: 1 - -no-ports: - image: redis`) +var _testExtendedTestdataCmdTestCmdServicesSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" +trap os::test::junit::reconcile_output EXIT -func testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeYmlBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeYml, nil -} +# Cleanup cluster resources created by this test +( + set +e + oc delete all,templates --all + exit 0 +) &>/dev/null -func testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeYml() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeYmlBytes() - if err != nil { - return nil, err - } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.yml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +os::test::junit::declare_suite_start "cmd/create-service-nodeport" +# This test validates the 'create service nodeport' command and its "--node-port" and "--tcp" options +os::cmd::expect_success_and_text 'oc create service nodeport mynodeport --tcp=8080:7777 --node-port=30000' 'service/mynodeport created' +os::cmd::expect_failure_and_text 'oc create service nodeport mynodeport --tcp=8080:7777 --node-port=30000' 'provided port is already allocated' +os::cmd::expect_failure_and_text 'oc create service nodeport mynodeport --tcp=8080:7777 --node-port=300' 'provided port is not in the valid range. The range of valid ports is 30000-32767' +os::cmd::expect_success_and_text 'oc describe service mynodeport' 'NodePort\:.*30000' +os::cmd::expect_success_and_text 'oc describe service mynodeport' 'NodePort\:.*8080-7777' +os::cmd::expect_success_and_text 'oc describe --v=8 service mynodeport' 'Response Body' -var _testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexNginxDockerfile = []byte(`FROM tutum/nginx -RUN rm /etc/nginx/sites-enabled/default -ADD sites-enabled/ /etc/nginx/sites-enabled +echo "create-services-nodeport: ok" +os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexNginxDockerfileBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexNginxDockerfile, nil +func testExtendedTestdataCmdTestCmdServicesShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdServicesSh, nil } -func testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexNginxDockerfile() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexNginxDockerfileBytes() +func testExtendedTestdataCmdTestCmdServicesSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdServicesShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/nginx/Dockerfile", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/services.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeWordpressDockerComposeYml = []byte(`version: "2" -services: - WP: - image: "centurylink/wordpress:3.9.1" - links: - - "DB:DB_1" - ports: - - "8080:80" - environment: - - "DB_PASSWORD=pass@word01" - - DB_NAME=wordpress - dns: - - 8.8.8.8 - - 9.9.9.9 - hostname: wordpress - domainname: wordpress.mysite.com - DB: - image: "centurylink/mysql:5.5" - ports: - - "3306:3306" - environment: - - "MYSQL_ROOT_PASSWORD=pass@word01" - mem_limit: "1000000000" - cpu_shares: "40" +var _testExtendedTestdataCmdTestCmdSetDataSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" +trap os::test::junit::reconcile_output EXIT + +# Cleanup cluster resources created by this test +( + set +e + oc delete cm --all + oc delete secret test + exit 0 +) &>/dev/null + + +os::test::junit::declare_suite_start "cmd/oc/set/data" + +os::cmd::expect_success 'oc create configmap test' +tmpfile="$(mktemp)" +echo "c" > "${tmpfile}" + +# test --local flag +os::cmd::expect_failure_and_text 'oc set data cm/test a=b --local' 'provide one or more resources by argument or filename' +# test --dry-run flag with -o formats +os::cmd::expect_success_and_text 'oc set data cm/test a=b --dry-run' 'test' +os::cmd::expect_success_and_text 'oc set data cm/test a=b --dry-run -o name' 'configmap/test' +os::cmd::expect_success_and_text 'oc set data cm/test a=b --dry-run' 'configmap/test data updated \(dry run\)' + +os::cmd::expect_failure_and_text 'oc set data cm/test a=c a-' 'you may not remove and set the key' +os::cmd::expect_failure_and_text 'oc set data cm/test a=c --from-literal=a=b' 'cannot set key "a" in both argument and flag' + +os::cmd::expect_success 'oc set data cm/test a=b' +os::cmd::expect_success_and_text "oc get cm/test -o jsonpath='{.data.a}'" 'b' +os::cmd::expect_success_and_text 'oc set data cm/test a=b' 'info: test was not changed' + +os::cmd::expect_success 'oc set data cm/test a-' +os::cmd::expect_success_and_text "oc get cm/test -o jsonpath='{.data.a}'" '' +os::cmd::expect_success_and_text 'oc set data cm/test a-' 'info: test was not changed' + +os::cmd::expect_success "oc set data cm/test --from-file=b=${tmpfile}" +os::cmd::expect_success_and_text "oc get cm/test -o jsonpath='{.data.b}'" 'c' +os::cmd::expect_success_and_text "oc set data cm/test --from-file=b=${tmpfile}" 'info: test was not changed' + +rm -rf ${tmpfile} +mkdir -p ${tmpfile} +echo '1' > "${tmpfile}/a" +echo '2' > "${tmpfile}/b" +os::cmd::expect_success 'oc set data cm/test b-' +os::cmd::expect_success "oc set data cm/test --from-file=${tmpfile}" +os::cmd::expect_success_and_text "oc get cm/test -o jsonpath='{.data.a}'" '1' +os::cmd::expect_success_and_text "oc get cm/test -o jsonpath='{.data.b}'" '2' +os::cmd::expect_success_and_text "oc set data cm/test --from-file=${tmpfile}" "info: test was not changed" + +os::cmd::expect_success 'oc create secret generic test' +os::cmd::expect_success 'oc set data secret/test a=b' +os::cmd::expect_success_and_text "oc get secret/test -o jsonpath='{.data.a}'" 'Yg==' +os::cmd::expect_success_and_text 'oc set data secret/test a=b' 'info: test was not changed' + + +echo "set-data: ok" +os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeWordpressDockerComposeYmlBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeWordpressDockerComposeYml, nil +func testExtendedTestdataCmdTestCmdSetDataShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdSetDataSh, nil } -func testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeWordpressDockerComposeYml() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeWordpressDockerComposeYmlBytes() +func testExtendedTestdataCmdTestCmdSetDataSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdSetDataShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/wordpress/docker-compose.yml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/set-data.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sLonelyPodJson = []byte(`{ - "kind": "List", - "apiVersion": "v1", - "metadata": {}, - "items": [ - { - "kind": "Pod", - "apiVersion": "v1", - "metadata": { - "name": "lonely-pod", - "creationTimestamp": null, - "labels": { - "name": "lonely-pod" - } - }, - "spec": { - "containers": [ - { - "name": "lonely-pod", - "image": "openshift/hello-openshift", - "ports": [ - { - "containerPort": 8080, - "protocol": "TCP" - } - ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "capabilities": {}, - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst" - }, - "status": {} - } - ] -}`) +var _testExtendedTestdataCmdTestCmdSetImageSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" +trap os::test::junit::reconcile_output EXIT -func testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sLonelyPodJsonBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sLonelyPodJson, nil -} +# Cleanup cluster resources created by this test +( + set +e + oc delete all,templates --all + exit 0 +) &>/dev/null -func testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sLonelyPodJson() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sLonelyPodJsonBytes() - if err != nil { - return nil, err - } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-lonely-pod.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +os::test::junit::declare_suite_start "cmd/oc/set/image" +os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-deployment-config.yaml' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/hello-openshift/hello-pod.json' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/image-streams/image-streams-centos7.json' +os::cmd::try_until_success 'oc get imagestreamtags ruby:2.7-ubi8' -var _testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sSampleAppJson = []byte(`{ - "kind": "List", - "apiVersion": "v1", - "metadata": {}, - "items": [ - { - "kind": "ReplicationController", - "apiVersion": "v1", - "metadata": { - "name": "database-app-1", - "creationTimestamp": null, - "labels": { - "template": "ruby-helloworld-sample" - } - }, - "spec": { - "replicas": 1, - "selector": { - "name": "database", - "deconflict": "database.app" - }, - "template": { - "metadata": { - "creationTimestamp": null, - "labels": { - "name": "database", - "template": "ruby-helloworld-sample", - "deconflict": "database.app" - } - }, - "spec": { - "containers": [ - { - "name": "ruby-helloworld-database", - "image": "mysql", - "ports": [ - { - "containerPort": 3306, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "MYSQL_ROOT_PASSWORD", - "value": "rQHfVnTo" - }, - { - "name": "MYSQL_DATABASE", - "value": "root" - } - ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "capabilities": {}, - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst" - } - } - }, - "status": { - "replicas": 0 - } - }, - { - "kind": "ReplicationController", - "apiVersion": "v1", - "metadata": { - "name": "frontend-app-1", - "creationTimestamp": null, - "labels": { - "template": "ruby-helloworld-sample" - } - }, - "spec": { - "replicas": 3, - "selector": { - "name": "frontend", - "deconflict": "frontend.app" - }, - "template": { - "metadata": { - "creationTimestamp": null, - "labels": { - "name": "frontend", - "template": "ruby-helloworld-sample", - "deconflict": "frontend.app" - } - }, - "spec": { - "containers": [ - { - "name": "ruby-helloworld", - "image": "openshift/ruby-hello-world", - "ports": [ - { - "containerPort": 8080, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "ADMIN_USERNAME", - "value": "admin6TM" - }, - { - "name": "ADMIN_PASSWORD", - "value": "xImx1tHR" - }, - { - "name": "MYSQL_ROOT_PASSWORD", - "value": "rQHfVnTo" - }, - { - "name": "MYSQL_DATABASE", - "value": "root" - } - ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "capabilities": {}, - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst" - } - } - }, - "status": { - "replicas": 0 - } - }, - { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "database-app", - "creationTimestamp": null, - "labels": { - "template": "ruby-helloworld-sample" - } - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 5434, - "targetPort": 3306, - "nodePort": 0 - } - ], - "selector": { - "name": "database" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } - }, - { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "frontend-app", - "creationTimestamp": null, - "labels": { - "template": "ruby-helloworld-sample" - } - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 5432, - "targetPort": 8080, - "nodePort": 0 - } - ], - "selector": { - "name": "frontend" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } - } - ] -}`) +# test --local flag +os::cmd::expect_failure_and_text 'oc set image dc/test-deployment-config ruby-helloworld=ruby:2.7-ubi8 --local' 'you must specify resources by --filename when --local is set.' +# test --dry-run flag with -o formats +os::cmd::expect_success_and_text 'oc set image dc/test-deployment-config ruby-helloworld=ruby:2.7-ubi8 --source=istag --dry-run' 'test-deployment-config' +os::cmd::expect_success_and_text 'oc set image dc/test-deployment-config ruby-helloworld=ruby:2.7-ubi8 --source=istag --dry-run -o name' 'deploymentconfig.apps.openshift.io/test-deployment-config' +os::cmd::expect_success_and_text 'oc set image dc/test-deployment-config ruby-helloworld=ruby:2.7-ubi8 --source=istag --dry-run' 'deploymentconfig.apps.openshift.io/test-deployment-config image updated \(dry run\)' -func testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sSampleAppJsonBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sSampleAppJson, nil -} +os::cmd::expect_success 'oc set image dc/test-deployment-config ruby-helloworld=ruby:2.7-ubi8 --source=istag' +os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o jsonpath='{.spec.template.spec.containers[0].image}'" 'image-registry.openshift-image-registry.svc:5000/cmd-set-image/ruby' -func testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sSampleAppJson() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sSampleAppJsonBytes() - if err != nil { - return nil, err - } +os::cmd::expect_success 'oc set image dc/test-deployment-config ruby-helloworld=ruby:2.7-ubi8 --source=istag' +os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o jsonpath='{.spec.template.spec.containers[0].image}'" 'image-registry.openshift-image-registry.svc:5000/cmd-set-image/ruby' - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-sample-app.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +os::cmd::expect_failure 'oc set image dc/test-deployment-config ruby-helloworld=ruby:XYZ --source=istag' +os::cmd::expect_failure 'oc set image dc/test-deployment-config ruby-helloworld=ruby:XYZ --source=isimage' -var _testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sServicePodNoRcJson = []byte(`{ - "kind": "List", - "apiVersion": "v1", - "metadata": {}, - "items": [ - { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "hello-openshift", - "creationTimestamp": null, - "labels": { - "template": "hello-openshift" - } - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 5432, - "targetPort": 8080, - "nodePort": 0 - } - ], - "selector": { - "name": "hello-openshift" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } - }, - { - "kind": "Pod", - "apiVersion": "v1", - "metadata": { - "name": "hello-openshift", - "creationTimestamp": null, - "labels": { - "name": "hello-openshift" - } - }, - "spec": { - "containers": [ - { - "name": "hello-openshift", - "image": "openshift/hello-openshift", - "ports": [ - { - "containerPort": 8080, - "protocol": "TCP" - } - ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "capabilities": {}, - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst" - }, - "status": {} - } - ] -}`) +os::cmd::expect_success 'oc set image dc/test-deployment-config ruby-helloworld=nginx' +os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o jsonpath='{.spec.template.spec.containers[0].image}'" 'nginx' + +os::cmd::expect_success 'oc set image pod/hello-openshift hello-openshift=nginx' +os::cmd::expect_success_and_text "oc get pod/hello-openshift -o jsonpath='{.spec.containers[0].image}'" 'nginx' + +os::cmd::expect_success 'oc set image pod/hello-openshift hello-openshift=nginx:1.9.1' +os::cmd::expect_success_and_text "oc get pod/hello-openshift -o jsonpath='{.spec.containers[0].image}'" 'nginx:1.9.1' + +os::cmd::expect_success 'oc set image pods,dc *=ruby:2.7-ubi8 --all --source=imagestreamtag' +os::cmd::expect_success_and_text "oc get pod/hello-openshift -o jsonpath='{.spec.containers[0].image}'" 'image-registry.openshift-image-registry.svc:5000/cmd-set-image/ruby' +os::cmd::expect_success_and_text "oc get dc/test-deployment-config -o jsonpath='{.spec.template.spec.containers[0].image}'" 'image-registry.openshift-image-registry.svc:5000/cmd-set-image/ruby' -func testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sServicePodNoRcJsonBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sServicePodNoRcJson, nil +echo "set-image: ok" +os::test::junit::declare_suite_end +`) + +func testExtendedTestdataCmdTestCmdSetImageShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdSetImageSh, nil } -func testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sServicePodNoRcJson() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sServicePodNoRcJsonBytes() +func testExtendedTestdataCmdTestCmdSetImageSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdSetImageShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-service-pod-no-rc.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/set-image.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sServiceWithNothingJson = []byte(`{ - "kind": "List", - "apiVersion": "v1", - "metadata": {}, - "items": [ - { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "empty-service", - "creationTimestamp": null, - "labels": { - "template": "empty-service" - } - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 5432, - "targetPort": 8080, - "nodePort": 0 - } - ], - "selector": { - "name": "empty-service" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } - } - ] -}`) +var _testExtendedTestdataCmdTestCmdSetLivenessProbeSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" +trap os::test::junit::reconcile_output EXIT + +# Cleanup cluster resources created by this test +( + set +e + oc delete all,templates --all + exit 0 +) &>/dev/null + + +os::test::junit::declare_suite_start "cmd/set-probe-liveness" +# This test setting a liveness probe, without warning about replication controllers whose deployment depends on deployment configs +os::cmd::expect_success_and_text 'oc create -f ${TEST_DATA}/simple-deployment.yaml' 'deploymentconfig.apps.openshift.io/simple-deployment created' +os::cmd::expect_success_and_text 'oc status --suggest' 'dc/simple-deployment has no liveness probe' + +# test --local flag +os::cmd::expect_failure_and_text 'oc set probe dc/simple-deployment --liveness --get-url=http://google.com:80 --local' 'You must provide one or more resources by argument or filename' +# test --dry-run flag with -o formats +os::cmd::expect_success_and_text 'oc set probe dc/simple-deployment --liveness --get-url=http://google.com:80 --dry-run' 'simple-deployment' +os::cmd::expect_success_and_text 'oc set probe dc/simple-deployment --liveness --get-url=http://google.com:80 --dry-run -o name' 'deploymentconfig.apps.openshift.io/simple-deployment' + +os::cmd::expect_success_and_not_text 'oc status --suggest' 'rc/simple-deployment-1 has no liveness probe' +os::cmd::expect_success_and_text 'oc set probe dc/simple-deployment --liveness --get-url=http://google.com:80' 'deploymentconfig.apps.openshift.io/simple-deployment probes updated' +os::cmd::expect_success_and_not_text 'oc status --suggest' 'dc/simple-deployment has no liveness probe' +echo "set-probe-liveness: ok" +os::test::junit::declare_suite_end +`) -func testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sServiceWithNothingJsonBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sServiceWithNothingJson, nil +func testExtendedTestdataCmdTestCmdSetLivenessProbeShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdSetLivenessProbeSh, nil } -func testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sServiceWithNothingJson() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sServiceWithNothingJsonBytes() +func testExtendedTestdataCmdTestCmdSetLivenessProbeSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdSetLivenessProbeShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-service-with-nothing.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/set-liveness-probe.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sUnservicedRcJson = []byte(`{ - "kind": "List", - "apiVersion": "v1", - "metadata": {}, - "items": [ - { - "kind": "ReplicationController", - "apiVersion": "v1", - "metadata": { - "name": "database-rc-1", - "creationTimestamp": null, - "labels": { - "template": "ruby-helloworld-sample" - } - }, - "spec": { - "replicas": 1, - "selector": { - "name": "database", - "deconflict": "database.rc" - }, - "template": { - "metadata": { - "creationTimestamp": null, - "labels": { - "name": "database", - "template": "ruby-helloworld-sample", - "deconflict": "database.rc" - } - }, - "spec": { - "containers": [ - { - "name": "ruby-helloworld-database", - "image": "mysql", - "ports": [ - { - "containerPort": 3306, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "MYSQL_ROOT_PASSWORD", - "value": "rQHfVnTo" - }, - { - "name": "MYSQL_DATABASE", - "value": "root" - } - ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "capabilities": {}, - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst" - } - } - }, - "status": { - "replicas": 0 - } - }, - { - "kind": "ReplicationController", - "apiVersion": "v1", - "metadata": { - "name": "frontend-rc-1", - "creationTimestamp": null, - "labels": { - "template": "ruby-helloworld-sample" - } - }, - "spec": { - "replicas": 3, - "selector": { - "name": "frontend", - "deconflict": "frontend.rc" - }, - "template": { - "metadata": { - "creationTimestamp": null, - "labels": { - "name": "frontend", - "template": "ruby-helloworld-sample", - "deconflict": "frontend.rc" - } - }, - "spec": { - "containers": [ - { - "name": "ruby-helloworld", - "image": "openshift/ruby-hello-world", - "ports": [ - { - "containerPort": 8080, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "ADMIN_USERNAME", - "value": "admin6TM" - }, - { - "name": "ADMIN_PASSWORD", - "value": "xImx1tHR" - }, - { - "name": "MYSQL_ROOT_PASSWORD", - "value": "rQHfVnTo" - }, - { - "name": "MYSQL_DATABASE", - "value": "root" - } - ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "capabilities": {}, - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst" - } - } - }, - "status": { - "replicas": 0 - } - }, - { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "database-rc", - "creationTimestamp": null, - "labels": { - "template": "ruby-helloworld-sample" - } - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 5434, - "targetPort": 3306, - "nodePort": 0 - } - ], - "selector": { - "name": "database" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } - } - ] -}`) - -func testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sUnservicedRcJsonBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sUnservicedRcJson, nil -} - -func testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sUnservicedRcJson() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sUnservicedRcJsonBytes() - if err != nil { - return nil, err - } +var _testExtendedTestdataCmdTestCmdSetbuildhookSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" +trap os::test::junit::reconcile_output EXIT - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-unserviced-rc.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +# Cleanup cluster resources created by this test +( + set +e + oc delete all,templates --all + exit 0 +) &>/dev/null -var _testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectDeployedAppYaml = []byte(`apiVersion: v1 -items: -- apiVersion: v1 - kind: BuildConfig - metadata: - creationTimestamp: 2015-04-07T04:12:17Z - labels: - name: ruby-sample-build - template: application-template-stibuild - name: ruby-sample-build - namespace: example - spec: - output: - to: - kind: ImageStreamTag - name: origin-ruby-sample:latest - resources: {} - source: - git: - uri: git://github.com/openshift/ruby-hello-world.git - type: Git - strategy: - sourceStrategy: - from: - kind: DockerImage - name: centos/ruby-25-centos7 - incremental: true - type: Source - triggers: - - github: - secret: secret101 - type: github - - generic: - secret: secret101 - type: generic - - imageChange: - lastTriggeredImageID: centos/ruby-25-centos7:latest - type: imageChange - status: - lastVersion: 1 -- apiVersion: v1 - kind: Build - metadata: - creationTimestamp: 2015-04-07T04:12:18Z - labels: - buildconfig: ruby-sample-build - name: ruby-sample-build - template: application-template-stibuild - name: ruby-sample-build-1 - namespace: example - spec: - output: - to: - kind: ImageStreamTag - name: origin-ruby-sample:latest - resources: {} - source: - git: - uri: git://github.com/openshift/ruby-hello-world.git - type: Git - strategy: - sourceStrategy: - from: - kind: DockerImage - name: centos/ruby-25-centos7:latest - incremental: true - type: Source - status: - completionTimestamp: 2015-04-07T04:13:01Z - config: - kind: BuildConfig - name: ruby-sample-build - phase: Complete - startTimestamp: 2015-04-07T04:12:21Z -- apiVersion: v1 - kind: ReplicationController - metadata: - annotations: - openshift.io/deployment-config.name: database - openshift.io/deployment.phase: Running - openshift.io/deployment-config.latest-version: "2" - openshift.io/encoded-deployment-config: '{"kind":"DeploymentConfig","apiVersion":"v1beta1","metadata":{"name":"database","namespace":"test","selfLink":"/osapi/v1beta1/watch/deploymentConfigs/database","uid":"4725b5d3-dcdc-11e4-968a-080027c5bfa9","resourceVersion":"271","creationTimestamp":"2015-04-07T04:12:17Z","labels":{"template":"application-template-stibuild"}},"triggers":[{"type":"ConfigChange"}],"template":{"strategy":{"type":"Recreate"},"controllerTemplate":{"replicas":1,"replicaSelector":{"name":"database"},"podTemplate":{"desiredState":{"manifest":{"version":"v1beta2","id":"","volumes":null,"containers":[{"name":"ruby-helloworld-database","image":"centos/mysql-56-centos7","ports":[{"containerPort":3306,"protocol":"TCP"}],"env":[{"name":"MYSQL_USER","key":"MYSQL_USER","value":"user1CY"},{"name":"MYSQL_PASSWORD","key":"MYSQL_PASSWORD","value":"FfyXmsGG"},{"name":"MYSQL_DATABASE","key":"MYSQL_DATABASE","value":"root"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"PullIfNotPresent","capabilities":{}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"}},"labels":{"name":"database","template":"application-template-stibuild"}}}},"latestVersion":1,"details":{"causes":[{"type":"ConfigChange"}]}}' - pod: deploy-database-19m1he - creationTimestamp: 2015-04-07T04:12:18Z - labels: - template: application-template-stibuild - name: database-2 - namespace: example - spec: - replicas: 1 - selector: - deployment: database-2 - deploymentconfig: database - name: database - template: - metadata: - annotations: - openshift.io/deployment.name: database-2 - openshift.io/deployment-config.name: database - openshift.io/deployment-config.latest-version: "2" - creationTimestamp: null - labels: - deployment: database-2 - deploymentconfig: database - name: database - template: application-template-stibuild - spec: - containers: - - capabilities: {} - env: - - name: MYSQL_USER - value: user1CY - - name: MYSQL_PASSWORD - value: FfyXmsGG - - name: MYSQL_DATABASE - value: root - image: centos/mysql-56-centos7 - imagePullPolicy: IfNotPresent - name: ruby-helloworld-database - ports: - - containerPort: 3306 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - status: - replicas: 2 -- apiVersion: v1 - kind: ReplicationController - metadata: - annotations: - openshift.io/deployment-config.name: database - openshift.io/deployment.phase: Complete - openshift.io/deployment-config.latest-version: "1" - openshift.io/encoded-deployment-config: '{"kind":"DeploymentConfig","apiVersion":"v1beta1","metadata":{"name":"database","namespace":"test","selfLink":"/osapi/v1beta1/watch/deploymentConfigs/database","uid":"4725b5d3-dcdc-11e4-968a-080027c5bfa9","resourceVersion":"271","creationTimestamp":"2015-04-07T04:12:17Z","labels":{"template":"application-template-stibuild"}},"triggers":[{"type":"ConfigChange"}],"template":{"strategy":{"type":"Recreate"},"controllerTemplate":{"replicas":1,"replicaSelector":{"name":"database"},"podTemplate":{"desiredState":{"manifest":{"version":"v1beta2","id":"","volumes":null,"containers":[{"name":"ruby-helloworld-database","image":"centos/mysql-56-centos7","ports":[{"containerPort":3306,"protocol":"TCP"}],"env":[{"name":"MYSQL_USER","key":"MYSQL_USER","value":"user1CY"},{"name":"MYSQL_PASSWORD","key":"MYSQL_PASSWORD","value":"FfyXmsGG"},{"name":"MYSQL_DATABASE","key":"MYSQL_DATABASE","value":"root"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"PullIfNotPresent","capabilities":{}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"}},"labels":{"name":"database","template":"application-template-stibuild"}}}},"latestVersion":1,"details":{"causes":[{"type":"ConfigChange"}]}}' - pod: deploy-database-19m1he - creationTimestamp: 2015-04-07T04:12:17Z - labels: - template: application-template-stibuild - name: database-1 - namespace: example - spec: - replicas: 1 - selector: - deployment: database-1 - deploymentconfig: database - name: database - template: - metadata: - annotations: - openshift.io/deployment.name: database-1 - openshift.io/deployment-config.name: database - openshift.io/deployment-config.latest-version: "1" - creationTimestamp: null - labels: - deployment: database-1 - deploymentconfig: database - name: database - template: application-template-stibuild - spec: - containers: - - capabilities: {} - env: - - name: MYSQL_USER - value: user1CY - - name: MYSQL_PASSWORD - value: FfyXmsGG - - name: MYSQL_DATABASE - value: root - image: centos/mysql-56-centos7 - imagePullPolicy: IfNotPresent - name: ruby-helloworld-database - ports: - - containerPort: 3306 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - status: - replicas: 1 -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: 2015-04-07T04:12:17Z - labels: - template: application-template-stibuild - name: database - namespace: example - spec: - replicas: 1 - selector: - name: database - strategy: - resources: {} - type: Recreate - template: - metadata: - creationTimestamp: null - labels: - name: database - template: application-template-stibuild - spec: - containers: - - capabilities: {} - env: - - name: MYSQL_USER - value: user1CY - - name: MYSQL_PASSWORD - value: FfyXmsGG - - name: MYSQL_DATABASE - value: root - image: centos/mysql-56-centos7 - imagePullPolicy: IfNotPresent - name: ruby-helloworld-database - ports: - - containerPort: 3306 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - test: true - triggers: - - type: ConfigChange - status: - details: - causes: - - type: ConfigChange - latestVersion: 1 -- apiVersion: v1 - kind: ReplicationController - metadata: - annotations: - openshift.io/deployment-config.name: frontend - openshift.io/deployment.phase: Failed - openshift.io/deployment-config.latest-version: "2" - openshift.io/encoded-deployment-config: '{"kind":"DeploymentConfig","apiVersion":"v1beta1","metadata":{"name":"frontend","namespace":"test","selfLink":"/osapi/v1beta1/watch/deploymentConfigs/frontend","uid":"471f24e3-dcdc-11e4-968a-080027c5bfa9","resourceVersion":"346","creationTimestamp":"2015-04-07T04:12:17Z","labels":{"template":"application-template-stibuild"}},"triggers":[{"type":"ImageChange","imageChangeParams":{"automatic":true,"containerNames":["ruby-helloworld"],"from":{"kind":"ImageStreamTag","name":"origin-ruby-sample:latest"},"tag":"latest","lastTriggeredImage":"172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58"}}],"template":{"strategy":{"type":"Recreate"},"controllerTemplate":{"replicas":1,"replicaSelector":{"name":"frontend"},"podTemplate":{"desiredState":{"manifest":{"version":"v1beta2","id":"","volumes":null,"containers":[{"name":"ruby-helloworld","image":"172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58","ports":[{"containerPort":8080,"protocol":"TCP"}],"env":[{"name":"ADMIN_USERNAME","key":"ADMIN_USERNAME","value":"adminNPX"},{"name":"ADMIN_PASSWORD","key":"ADMIN_PASSWORD","value":"7q1IdEao"},{"name":"MYSQL_USER","key":"MYSQL_USER","value":"user1CY"},{"name":"MYSQL_PASSWORD","key":"MYSQL_PASSWORD","value":"FfyXmsGG"},{"name":"MYSQL_DATABASE","key":"MYSQL_DATABASE","value":"root"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"PullIfNotPresent","capabilities":{}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"}},"labels":{"name":"frontend","template":"application-template-stibuild"}}}},"latestVersion":1,"details":{"causes":[{"type":"ImageChange","imageTrigger":{"repositoryName":"172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58","tag":"latest"}}]}}' - openshift.io/deployment.status-reason: unable to contact server - pod: deploy-frontend-17mza9 - creationTimestamp: 2015-04-07T04:12:53Z - labels: - template: application-template-stibuild - name: frontend-2 - namespace: example - spec: - replicas: 1 - selector: - deployment: frontend-2 - deploymentconfig: frontend - name: frontend - template: - metadata: - annotations: - openshift.io/deployment.name: frontend-2 - openshift.io/deployment-config.name: frontend - openshift.io/deployment-config.latest-version: "2" - creationTimestamp: null - labels: - deployment: frontend-2 - deploymentconfig: frontend - name: frontend - template: application-template-stibuild - spec: - containers: - - capabilities: {} - env: - - name: ADMIN_USERNAME - value: adminNPX - - name: ADMIN_PASSWORD - value: 7q1IdEao - - name: MYSQL_USER - value: user1CY - - name: MYSQL_PASSWORD - value: FfyXmsGG - - name: MYSQL_DATABASE - value: root - image: 172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58 - imagePullPolicy: IfNotPresent - name: ruby-helloworld - ports: - - containerPort: 8080 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - status: - replicas: 0 -- apiVersion: v1 - kind: ReplicationController - metadata: - annotations: - openshift.io/deployment-config.name: frontend - openshift.io/deployment.phase: Complete - openshift.io/deployment-config.latest-version: "1" - openshift.io/encoded-deployment-config: '{"kind":"DeploymentConfig","apiVersion":"v1beta1","metadata":{"name":"frontend","namespace":"test","selfLink":"/osapi/v1beta1/watch/deploymentConfigs/frontend","uid":"471f24e3-dcdc-11e4-968a-080027c5bfa9","resourceVersion":"346","creationTimestamp":"2015-04-07T04:12:17Z","labels":{"template":"application-template-stibuild"}},"triggers":[{"type":"ImageChange","imageChangeParams":{"automatic":true,"containerNames":["ruby-helloworld"],"from":{"kind":"ImageStreamTag","name":"origin-ruby-sample:latest"},"tag":"latest","lastTriggeredImage":"172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58"}}],"template":{"strategy":{"type":"Recreate"},"controllerTemplate":{"replicas":1,"replicaSelector":{"name":"frontend"},"podTemplate":{"desiredState":{"manifest":{"version":"v1beta2","id":"","volumes":null,"containers":[{"name":"ruby-helloworld","image":"172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58","ports":[{"containerPort":8080,"protocol":"TCP"}],"env":[{"name":"ADMIN_USERNAME","key":"ADMIN_USERNAME","value":"adminNPX"},{"name":"ADMIN_PASSWORD","key":"ADMIN_PASSWORD","value":"7q1IdEao"},{"name":"MYSQL_USER","key":"MYSQL_USER","value":"user1CY"},{"name":"MYSQL_PASSWORD","key":"MYSQL_PASSWORD","value":"FfyXmsGG"},{"name":"MYSQL_DATABASE","key":"MYSQL_DATABASE","value":"root"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"PullIfNotPresent","capabilities":{}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"}},"labels":{"name":"frontend","template":"application-template-stibuild"}}}},"latestVersion":1,"details":{"causes":[{"type":"ImageChange","imageTrigger":{"repositoryName":"172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58","tag":"latest"}}]}}' - pod: deploy-frontend-17mza9 - creationTimestamp: 2015-04-07T04:12:53Z - labels: - template: application-template-stibuild - name: frontend-1 - namespace: example - spec: - replicas: 1 - selector: - deployment: frontend-1 - deploymentconfig: frontend - name: frontend - template: - metadata: - annotations: - openshift.io/deployment.name: frontend-1 - openshift.io/deployment-config.name: frontend - openshift.io/deployment-config.latest-version: "1" - creationTimestamp: null - labels: - deployment: frontend-1 - deploymentconfig: frontend - name: frontend - template: application-template-stibuild - spec: - containers: - - capabilities: {} - env: - - name: ADMIN_USERNAME - value: adminNPX - - name: ADMIN_PASSWORD - value: 7q1IdEao - - name: MYSQL_USER - value: user1CY - - name: MYSQL_PASSWORD - value: FfyXmsGG - - name: MYSQL_DATABASE - value: root - image: 172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58 - imagePullPolicy: IfNotPresent - name: ruby-helloworld - ports: - - containerPort: 8080 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - status: - replicas: 1 -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: 2015-04-07T04:12:17Z - labels: - template: application-template-stibuild - name: frontend - namespace: example - spec: - replicas: 1 - selector: - name: frontend - strategy: - resources: {} - type: Recreate - template: - metadata: - creationTimestamp: null - labels: - name: frontend - template: application-template-stibuild - spec: - containers: - - capabilities: {} - env: - - name: ADMIN_USERNAME - value: adminNPX - - name: ADMIN_PASSWORD - value: 7q1IdEao - - name: MYSQL_USER - value: user1CY - - name: MYSQL_PASSWORD - value: FfyXmsGG - - name: MYSQL_DATABASE - value: root - image: 172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58 - imagePullPolicy: IfNotPresent - name: ruby-helloworld - ports: - - containerPort: 8080 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - triggers: - - imageChangeParams: - automatic: true - containerNames: - - ruby-helloworld - from: - kind: ImageStreamTag - name: origin-ruby-sample:latest - lastTriggeredImage: 172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58 - type: ImageChange - status: - details: - causes: - - imageTrigger: - from: - kind: DockerImage - name: 172.30.17.139:5000/test/origin-ruby-sample:latest - type: ImageChange - latestVersion: 3 -- apiVersion: v1 - kind: Service - metadata: - creationTimestamp: 2015-04-07T04:12:17Z - labels: - template: application-template-stibuild - name: database - namespace: example - spec: - ports: - - nodePort: 0 - port: 5434 - protocol: TCP - targetPort: 3306 - selector: - name: database - sessionAffinity: None - type: ClusterIP - status: - loadBalancer: {} -- apiVersion: v1 - kind: Service - metadata: - creationTimestamp: 2015-04-07T04:12:17Z - labels: - template: application-template-stibuild - name: database-external - namespace: example - spec: - ports: - - nodePort: 31000 - port: 5434 - protocol: TCP - targetPort: 3306 - selector: - name: database - sessionAffinity: None - type: NodePort - status: - loadBalancer: {} -- apiVersion: v1 - kind: Service - metadata: - creationTimestamp: 2015-04-07T04:12:17Z - labels: - template: application-template-stibuild - name: frontend - namespace: example - spec: - ports: - - nodePort: 0 - port: 5432 - protocol: TCP - targetPort: 8080 - selector: - name: frontend - sessionAffinity: None - type: ClusterIP - status: - loadBalancer: {} -- apiVersion: v1 - kind: Route - metadata: - annotations: - openshift.io/host.generated: "true" - creationTimestamp: 2015-04-07T04:12:17Z - labels: - template: application-template-stibuild - name: frontend - namespace: example - resourceVersion: "393" - spec: - host: frontend-example.router.default.svc.cluster.local - port: - targetPort: 8080 - to: - kind: Service - name: frontend - status: - ingress: - - routerName: default - host: frontend-example.router.default.svc.cluster.local - - routerName: other - host: www.test.com - conditions: - - type: Admitted - status: "False" - reason: HostAlreadyClaimed -- apiVersion: v1 - kind: Route - metadata: - annotations: - openshift.io/host.generated: "true" - creationTimestamp: 2015-04-07T04:12:17Z - labels: - template: application-template-stibuild - name: other - namespace: example - resourceVersion: "393" - spec: - host: www.test.com - port: - targetPort: 8080 - to: - kind: Service - name: frontend - tls: - insecureEdgeTerminationPolicy: Redirect - type: Edge - status: - ingress: - - routerName: other - host: www.test.com - conditions: - - type: Admitted - status: "True" -kind: List -metadata: - resourceVersion: "592" +os::test::junit::declare_suite_start "cmd/builds/setbuildhook" +# Validate the set build-hook command +arg="-f ${TEST_DATA}/test-bc.yaml" +os::cmd::expect_failure_and_text "oc set build-hook" "error: one or more build configs" +os::cmd::expect_failure_and_text "oc set build-hook ${arg}" "error: you must specify a type of hook" +os::cmd::expect_failure_and_text "oc set build-hook ${arg} --local --post-commit -o yaml -- echo 'hello world'" 'you must specify either a script or command for the build hook' +os::cmd::expect_success_and_text "oc set build-hook ${arg} --local --post-commit --command -o yaml -- echo 'hello world'" 'command:' +os::cmd::expect_success_and_text "oc set build-hook ${arg} --local --post-commit -o yaml --script='echo \"hello world\"'" 'script: echo \"hello world\"' +# Server object tests +os::cmd::expect_success "oc create -f ${TEST_DATA}/test-bc.yaml" +# Must specify --command or --script +os::cmd::expect_failure_and_text "oc set build-hook bc/test-buildconfig --post-commit" "you must specify either a script or command" +# Setting args for the default entrypoint is not supported +os::cmd::expect_failure_and_text "oc set build-hook test-buildconfig --post-commit -- foo bar" "you must specify either a script or command for the build hook" +# Set a command + args on a specific build config +os::cmd::expect_success_and_text "oc set build-hook bc/test-buildconfig --post-commit --command -- /bin/bash -c \"echo 'test'\"" "updated" +os::cmd::expect_success_and_text "oc get bc/test-buildconfig -o yaml" "command:" +os::cmd::expect_success_and_text "oc get bc/test-buildconfig -o yaml" "args:" +os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "script:" +# Set a script on a specific build config +os::cmd::expect_success_and_text "oc set build-hook bc/test-buildconfig --post-commit --script /bin/script.sh -- arg1 arg2" "updated" +os::cmd::expect_success_and_text "oc get bc/test-buildconfig -o yaml" "script:" +os::cmd::expect_success_and_text "oc get bc/test-buildconfig -o yaml" "args:" +os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "command:" +# Remove the postcommit hook +os::cmd::expect_success_and_text "oc set build-hook bc/test-buildconfig --post-commit --remove" "updated" +os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "args:" +os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "command:" +os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "script:" +# Set a command + args on all build configs +os::cmd::expect_success_and_text "oc set build-hook --all --post-commit --command -- /bin/bash -c \"echo 'test'\"" "updated" +os::cmd::expect_success_and_text "oc get bc/test-buildconfig -o yaml" "command:" +os::cmd::expect_success_and_text "oc get bc/test-buildconfig -o yaml" "args:" +os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "script:" +# Set a script on all build configs +os::cmd::expect_success_and_text "oc set build-hook --all --post-commit --script /bin/script.sh" "updated" +os::cmd::expect_success_and_text "oc get bc/test-buildconfig -o yaml" "script:" +os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "args:" +os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "command:" + +os::cmd::expect_success "oc delete bc/test-buildconfig" +# ensure command behaves as expected when an empty file is given +workingdir=$(mktemp -d) +touch "${workingdir}/emptyfile.json" +os::cmd::expect_failure_and_text "oc set build-hook -f ${workingdir}/emptyfile.json --post-commit=true --script=foo" "no resources found" +echo "set build-hook: ok" +os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectDeployedAppYamlBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectDeployedAppYaml, nil +func testExtendedTestdataCmdTestCmdSetbuildhookShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdSetbuildhookSh, nil } -func testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectDeployedAppYaml() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectDeployedAppYamlBytes() +func testExtendedTestdataCmdTestCmdSetbuildhookSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdSetbuildhookShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-deployed-app.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/setbuildhook.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectNoBuildYaml = []byte(`apiVersion: v1 -items: -- apiVersion: v1 - kind: BuildConfig - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-example-2 - spec: - output: - to: - kind: ImageStreamTag - name: sinatra-example-2:latest - resources: {} - source: - git: - uri: git://github.com/mfojtik/sinatra-example-2 - type: Git - strategy: - sourceStrategy: - from: - kind: DockerImage - name: centos/ruby-25-centos7 - type: Source - triggers: - - github: - secret: u5gRhTXiOJpOHxKSI1M6 - type: github - - generic: - secret: IDO5sRS52tsUq5hczU6o - type: generic - status: - lastVersion: 0 -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-example-2 - spec: - replicas: 1 - selector: - deploymentconfig: sinatra-example-2 - strategy: - resources: {} - type: Recreate - template: - metadata: - creationTimestamp: null - labels: - deploymentconfig: sinatra-example-2 - spec: - containers: - - capabilities: {} - image: library/sinatra-example-2:latest - imagePullPolicy: Always - name: sinatra-example-2 - ports: - - containerPort: 8080 - name: s-tcp-8080 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - sinatra-example-2 - from: - kind: ImageStreamTag - name: sinatra-example-2:latest - lastTriggeredImage: "" - type: ImageChange - status: {} -- apiVersion: v1 - kind: ImageStream - metadata: - creationTimestamp: 2015-04-06T21:18:56Z - name: sinatra-example-2 - spec: {} - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: Service - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-example-2 - spec: - ports: - - nodePort: 0 - port: 8080 - protocol: TCP - targetPort: 8080 - selector: - deploymentconfig: sinatra-example-2 - sessionAffinity: None - type: ClusterIP - status: - loadBalancer: {} -kind: List -metadata: - resourceVersion: "116" +var _testExtendedTestdataCmdTestCmdSetbuildsecretSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" +trap os::test::junit::reconcile_output EXIT + +# Cleanup cluster resources created by this test +( + set +e + oc delete all,templates --all + exit 0 +) &>/dev/null + +os::test::junit::declare_suite_start "cmd/builds/setbuildsecret" +# Validate the set build-secret command +arg="-f ${TEST_DATA}/test-bc.yaml" +os::cmd::expect_failure_and_text "oc set build-secret" "error: a secret name must be specified" +os::cmd::expect_failure_and_text "oc set build-secret ${arg}" "error: a secret name must be specified" +os::cmd::expect_failure_and_text "oc set build-secret ${arg} mysecret" "error: specify the type of secret" +os::cmd::expect_success_and_text "oc set build-secret ${arg} mysecret --push --local -o yaml" 'pushSecret:' +os::cmd::expect_success_and_text "oc set build-secret ${arg} mysecret --push --local -o yaml" 'name: mysecret' +os::cmd::expect_success_and_text "oc set build-secret ${arg} mysecret --pull --local -o yaml" 'pullSecret:' +os::cmd::expect_success_and_text "oc set build-secret ${arg} mysecret --pull --local -o yaml" 'name: mysecret' +os::cmd::expect_success_and_text "oc set build-secret ${arg} mysecret --source --local -o yaml" 'sourceSecret:' +os::cmd::expect_success_and_text "oc set build-secret ${arg} mysecret --source --local -o yaml" 'name: mysecret' +os::cmd::expect_success_and_not_text "oc set build-secret ${arg} mysecret --push --local -o yaml | oc set build-secret --local -f - --remove --push -o yaml" 'pushSecret:' +os::cmd::expect_success_and_not_text "oc set build-secret ${arg} mysecret --pull --local -o yaml | oc set build-secret --local -f - --remove --pull -o yaml" 'pullSecret:' +os::cmd::expect_success_and_not_text "oc set build-secret ${arg} mysecret --push --local -o yaml | oc set build-secret --local -f - --remove --source -o yaml" 'sourceSecret:' +# Server object tests +os::cmd::expect_success "oc create -f ${TEST_DATA}/test-bc.yaml" +os::cmd::expect_success_and_text "oc set build-secret test-buildconfig mysecret --push" "updated" +os::cmd::expect_success_and_text "oc set build-secret bc/test-buildconfig mysecret --push --v=1" "was not changed" +os::cmd::expect_success_and_text "oc get bc/test-buildconfig -o yaml" "pushSecret:" +os::cmd::expect_success_and_text "oc set build-secret bc/test-buildconfig --push --remove" "updated" +os::cmd::expect_success_and_not_text "oc get bc/test-buildconfig -o yaml" "pushSecret:" +os::cmd::expect_success "oc delete bc/test-buildconfig" +echo "set build-secret: ok" +os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectNoBuildYamlBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectNoBuildYaml, nil +func testExtendedTestdataCmdTestCmdSetbuildsecretShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdSetbuildsecretSh, nil } -func testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectNoBuildYaml() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectNoBuildYamlBytes() +func testExtendedTestdataCmdTestCmdSetbuildsecretSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdSetbuildsecretShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-no-build.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/setbuildsecret.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectOneBuildYaml = []byte(`apiVersion: v1 -items: -- apiVersion: v1 - kind: BuildConfig - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-example-1 - namespace: example - spec: - output: - to: - kind: ImageStreamTag - name: sinatra-example-1:latest - resources: {} - source: - git: - uri: git://github.com/mfojtik/sinatra-example-1 - type: Git - strategy: - sourceStrategy: - from: - kind: DockerImage - name: centos/ruby-25-centos7 - type: Source - triggers: - - github: - secret: u5gRhTXiOJpOHxKSI1M6 - type: github - - generic: - secret: IDO5sRS52tsUq5hczU6o - type: generic - status: - lastVersion: 1 -- apiVersion: v1 - kind: ImageStream - metadata: - creationTimestamp: 2015-04-06T21:18:56Z - name: sinatra-example-1 - namespace: example - spec: {} - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: Build - metadata: - creationTimestamp: 2015-04-06T21:18:56Z - labels: - buildconfig: sinatra-example-1 - name: sinatra-example-1-1 - namespace: example - spec: - output: - to: - kind: ImageStreamTag - name: sinatra-example-1:latest - resources: {} - source: - git: - uri: git://github.com/mfojtik/sinatra-example-1 - type: Git - strategy: - sourceStrategy: - from: - kind: DockerImage - name: centos/ruby-25-centos7 - type: Source - status: - phase: Running - startTimestamp: 2015-04-06T21:19:03Z -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-example-1 - namespace: example - spec: - replicas: 1 - selector: - deploymentconfig: sinatra-example-1 - strategy: - resources: {} - type: Recreate - template: - metadata: - creationTimestamp: null - labels: - deploymentconfig: sinatra-example-1 - spec: - containers: - - capabilities: {} - image: library/sinatra-example-1:latest - imagePullPolicy: Always - name: sinatra-example-1 - ports: - - containerPort: 8080 - name: s-tcp-8080 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - sinatra-example-1 - from: - kind: ImageStreamTag - name: sinatra-example-1:latest - lastTriggeredImage: "" - type: ImageChange - status: {} -- apiVersion: v1 - kind: Service - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-example-1 - namespace: example - spec: - ports: - - nodePort: 0 - port: 8080 - protocol: TCP - targetPort: 8080 - selector: - deploymentconfig: sinatra-example-1 - sessionAffinity: None - type: ClusterIP - status: - loadBalancer: {} -kind: List -metadata: {} +var _testExtendedTestdataCmdTestCmdStatusSh = []byte(`#!/bin/bash + +set -o errexit +set -o nounset +set -o pipefail + +OS_ROOT=$(dirname "${BASH_SOURCE}")/../.. +source "${OS_ROOT}/hack/lib/init.sh" +os::log::stacktrace::install +trap os::test::junit::reconcile_output EXIT + +# Cleanup cluster resources created by this test +( + set +e + oc delete project project-bar + oc delete project project-status + exit 0 +) &>/dev/null + +login_kubeconfig="${ARTIFACT_DIR}/login.kubeconfig" +cp "${KUBECONFIG}" "${login_kubeconfig}" + +os::test::junit::declare_suite_start "cmd/status" +# login and ensure no current projects exist +#os::cmd::expect_success "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${MASTER_CONFIG_DIR}/server-ca.crt' -u test-user2 -p anything" +#os::cmd::expect_success 'oc delete project --all' +#os::cmd::try_until_text "oc get projects -o jsonpath='{.items}'" "^\[\]$" +#os::cmd::expect_success 'oc logout' + +# remove self-provisioner role from user and test login prompt before creating any projects +#os::cmd::expect_success "oc adm policy remove-cluster-role-from-group self-provisioner system:authenticated:oauth --kubeconfig='${login_kubeconfig}'" + +# login as 'test-user2' +#os::cmd::expect_success "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${MASTER_CONFIG_DIR}/server-ca.crt' -u test-user2 -p anything" + +# make sure ` + "`" + `oc status` + "`" + ` re-uses the correct "no projects" message from ` + "`" + `oc login` + "`" + ` with no self-provisioner role +#os::cmd::expect_success_and_text 'oc status' "You don't have any projects. Contact your system administrator to request a project" +os::cmd::expect_success_and_text 'oc status --all-namespaces' "Showing all projects on server" +# make sure standard login prompt is printed once self-provisioner status is restored +#os::cmd::expect_success "oc logout" +#os::cmd::expect_success "oc adm policy add-cluster-role-to-group self-provisioner system:authenticated:oauth --kubeconfig='${login_kubeconfig}'" +#os::cmd::try_until_text "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${MASTER_CONFIG_DIR}/server-ca.crt' -u test-user2 -p anything" "You don't have any projects. You can try to create a new project, by running" $(( 30 * second )) 0.25 + +# make sure ` + "`" + `oc status` + "`" + ` re-uses the correct "no projects" message from ` + "`" + `oc login` + "`" + ` +#os::cmd::expect_success_and_text 'oc status' "You don't have any projects. You can try to create a new project, by running" +os::cmd::expect_success_and_text 'oc status -A' "Showing all projects on server" +# make sure ` + "`" + `oc status` + "`" + ` does not re-use the "no projects" message from ` + "`" + `oc login` + "`" + ` if -n is specified +#os::cmd::expect_failure_and_text 'oc status -n forbidden' 'Error from server \(Forbidden\): projects.project.openshift.io "forbidden" is forbidden: User "test-user2" cannot get resource "projects" in API group "project.openshift.io" in the namespace "forbidden"' + +# create a new project +os::cmd::expect_success "oc new-project project-bar --display-name='my project' --description='test project'" +os::cmd::expect_success_and_text "oc project" 'Using project "project-bar"' + +# make sure ` + "`" + `oc status` + "`" + ` does not use "no projects" message if there is a project created +os::cmd::expect_success_and_text 'oc status' "In project my project \(project-bar\) on server" +#os::cmd::expect_failure_and_text 'oc status -n forbidden' 'Error from server \(Forbidden\): projects.project.openshift.io "forbidden" is forbidden: User "test-user2" cannot get resource "projects" in API group "project.openshift.io" in the namespace "forbidden"' + +# create a second project +os::cmd::expect_success "oc new-project project-bar-2 --display-name='my project 2' --description='test project 2'" +os::cmd::expect_success_and_text "oc project" 'Using project "project-bar-2"' + +# delete the current project ` + "`" + `project-bar-2` + "`" + ` and make sure ` + "`" + `oc status` + "`" + ` does not return the "no projects" +# message since ` + "`" + `project-bar` + "`" + ` still exists +os::cmd::expect_success_and_text "oc delete project project-bar-2" 'project.project.openshift.io "project-bar-2" deleted' +# the deletion is asynchronous and can take a while, so wait until we see the error +#os::cmd::try_until_text "oc status" 'Error from server \(Forbidden\): projects.project.openshift.io "project-bar-2" is forbidden: User "test-user2" cannot get resource "projects" in API group "project.openshift.io" in the namespace "project-bar-2"' + +# delete "project-bar" and test that ` + "`" + `oc status` + "`" + ` still does not return the "no projects" message. +# Although we are deleting the last remaining project, the current context's namespace is still set +# to it, therefore ` + "`" + `oc status` + "`" + ` should simply return a forbidden error and not the "no projects" message +# until the next time the user logs in. +os::cmd::expect_success "oc project project-bar" +os::cmd::expect_success "oc delete project project-bar" +# the deletion is asynchronous and can take a while, so wait until we see the error +#os::cmd::try_until_text "oc status" 'Error from server \(Forbidden\): projects.project.openshift.io "project-bar" is forbidden: User "test-user2" cannot get resource "projects" in API group "project.openshift.io" in the namespace "project-bar"' +os::cmd::try_until_not_text "oc get projects" "project-bar" +os::cmd::try_until_not_text "oc get projects" "project-bar-2" +#os::cmd::expect_success "oc logout" +#os::cmd::expect_success_and_text "oc login --server=${KUBERNETES_MASTER} --certificate-authority='${MASTER_CONFIG_DIR}/server-ca.crt' -u test-user2 -p anything" "You don't have any projects. You can try to create a new project, by running" +#os::cmd::expect_success_and_text 'oc status' "You don't have any projects. You can try to create a new project, by running" +os::cmd::expect_success "oc new-project project-status --display-name='my project' --description='test project'" + +# Verify jobs are showing in status +os::cmd::expect_success "oc create job pi --image=image-registry.openshift-image-registry.svc:5000/openshift/tools:latest -- perl -Mbignum=bpi -wle 'print bpi(2000)'" +os::cmd::expect_success_and_text "oc status" "job/pi manages image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" + +# logout +#os::cmd::expect_success "oc logout" + +echo "status: ok" +os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectOneBuildYamlBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectOneBuildYaml, nil +func testExtendedTestdataCmdTestCmdStatusShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdStatusSh, nil } -func testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectOneBuildYaml() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectOneBuildYamlBytes() +func testExtendedTestdataCmdTestCmdStatusSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdStatusShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-one-build.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/status.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectTwoDeploymentConfigsYaml = []byte(`apiVersion: v1 -items: -- apiVersion: v1 - kind: BuildConfig - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-app-example - spec: - output: - to: - kind: ImageStreamTag - name: sinatra-app-example:latest - resources: {} - source: - git: - uri: git://github.com/mfojtik/sinatra-app-example - type: Git - strategy: - sourceStrategy: - from: - kind: DockerImage - name: centos/ruby-25-centos7 - type: Source - triggers: - - github: - secret: u5gRhTXiOJpOHxKSI1M6 - type: github - - generic: - secret: IDO5sRS52tsUq5hczU6o - type: generic - status: - lastVersion: 1 -- apiVersion: v1 - kind: ImageStream - metadata: - creationTimestamp: 2015-04-06T21:18:56Z - name: sinatra-app-example - spec: {} - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: Build - metadata: - creationTimestamp: 2015-04-06T21:18:56Z - labels: - buildconfig: sinatra-app-example - name: sinatra-app-example-1 - spec: - output: - to: - kind: ImageStreamTag - name: sinatra-app-example:latest - resources: {} - revision: - git: - author: - email: someguy@outhere.com - name: Roy Programmer - commit: 7a4f354721b0c9717e46f2e132b269b495d43e2b - committer: {} - message: Prepare v1 Template types - type: git - source: - git: - uri: git://github.com/mfojtik/sinatra-app-example - type: Git - strategy: - sourceStrategy: - from: - kind: DockerImage - name: centos/ruby-25-centos7 - type: Source - status: - phase: Running - startTimestamp: 2015-04-06T21:19:03Z -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-app-example-a - spec: - replicas: 1 - selector: - deploymentconfig: sinatra-app-example - strategy: - resources: {} - type: Recreate - template: - metadata: - creationTimestamp: null - labels: - deploymentconfig: sinatra-app-example - spec: - containers: - - capabilities: {} - image: library/sinatra-app-example:latest - imagePullPolicy: Always - name: sinatra-app-example - ports: - - containerPort: 8080 - name: s-tcp-8080 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - sinatra-app-example - from: - kind: ImageStreamTag - name: sinatra-app-example:latest - lastTriggeredImage: "" - type: ImageChange - status: {} -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-app-example-b - spec: - replicas: 1 - selector: - deploymentconfig: sinatra-app-example - strategy: - resources: {} - type: Recreate - template: - metadata: - creationTimestamp: null - labels: - deploymentconfig: sinatra-app-example - spec: - containers: - - capabilities: {} - image: library/sinatra-app-example:latest - imagePullPolicy: Always - name: sinatra-app-example - ports: - - containerPort: 8080 - name: s-tcp-8080 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - sinatra-app-example - from: - kind: ImageStreamTag - name: sinatra-app-example:latest - lastTriggeredImage: "" - type: ImageChange - status: {} -- apiVersion: v1 - kind: Service - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-app-example - spec: - ports: - - nodePort: 0 - port: 8080 - protocol: TCP - targetPort: 8080 - selector: - deploymentconfig: sinatra-app-example - sessionAffinity: None - type: ClusterIP - status: - loadBalancer: {} -kind: List -metadata: {} -`) +var _testExtendedTestdataCmdTestCmdTemplatesSh = []byte(`#!/bin/bash +source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" +trap os::test::junit::reconcile_output EXIT + +# Cleanup cluster resources created by this test +( + set +e + oc delete all,templates --all + oc delete template/ruby-helloworld-sample -n openshift + oc delete project test-template-project + oc delete user someval someval=moreval someval=moreval2 someval=moreval3 + exit 0 +) &>/dev/null + + +os::test::junit::declare_suite_start "cmd/templates" +# This test validates template commands + +os::test::junit::declare_suite_start "cmd/templates/basic" +os::cmd::expect_success 'oc get templates' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/application-template-dockerbuild.json' +os::cmd::expect_success 'oc get templates' +os::cmd::expect_success 'oc get templates ruby-helloworld-sample' +os::cmd::expect_success 'oc get template ruby-helloworld-sample -o json | oc process -f -' +os::cmd::expect_success 'oc process ruby-helloworld-sample' +os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o template --template "{{.kind}}"' "List" +os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o go-template --template "{{.kind}}"' "List" +os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o go-template={{.kind}}' "List" +os::cmd::expect_success 'oc process ruby-helloworld-sample -o go-template-file=/dev/null' +os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o jsonpath --template "{.kind}"' "List" +os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o jsonpath={.kind}' "List" +os::cmd::expect_success 'oc process ruby-helloworld-sample -o jsonpath-file=/dev/null' +os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o describe' "ruby-27-centos7" +os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o json' "ruby-27-centos7" +os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o yaml' "ruby-27-centos7" +os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -o name' "ruby-27-centos7" +os::cmd::expect_success_and_text 'oc describe templates ruby-helloworld-sample' "BuildConfig.*ruby-sample-build" +os::cmd::expect_success 'oc delete templates ruby-helloworld-sample' +os::cmd::expect_success 'oc get templates' +# TODO: create directly from template +echo "templates: ok" +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_start "cmd/templates/config" +guestbook_template="${TEST_DATA}/templates/guestbook.json" +os::cmd::expect_success "oc process -f '${guestbook_template}' -l app=guestbook | oc create -f -" +os::cmd::expect_success_and_text 'oc status' 'frontend-service' +echo "template+config: ok" + +os::test::junit::declare_suite_start "cmd/templates/local-config" +# Processes the template locally +os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --local -l app=guestbook -o yaml" "app: guestbook" +# Processes the template locally and get the same output in YAML +new="$(mktemp -d)" +os::cmd::expect_success 'oc process -f "${guestbook_template}" --local -l app=guestbook -o yaml ADMIN_USERNAME=au ADMIN_PASSWORD=ap REDIS_PASSWORD=rp > "${new}/localtemplate"' +os::cmd::expect_success 'oc process -f "${guestbook_template}" -l app=guestbook -o yaml ADMIN_USERNAME=au ADMIN_PASSWORD=ap REDIS_PASSWORD=rp > "${new}/remotetemplate"' +os::cmd::expect_success 'diff "${new}/localtemplate" "${new}/remotetemplate"' +# Does not even try to hit the server +os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --local -l app=guestbook -o yaml --server 0.0.0.0:1" "app: guestbook" +echo "template+config+local: ok" +os::test::junit::declare_suite_end -func testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectTwoDeploymentConfigsYamlBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectTwoDeploymentConfigsYaml, nil -} +os::test::junit::declare_suite_start "cmd/templates/parameters" +guestbook_params="${TEST_DATA}/templates/guestbook.env" +# Individually specified parameter values are honored +os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' -p ADMIN_USERNAME=myuser -p ADMIN_PASSWORD=mypassword" '"myuser"' +os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' -p ADMIN_USERNAME=myuser -p ADMIN_PASSWORD=mypassword" '"mypassword"' +# Argument values are honored +os::cmd::expect_success_and_text "oc process ADMIN_USERNAME=myuser ADMIN_PASSWORD=mypassword -f '${guestbook_template}'" '"myuser"' +os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' ADMIN_USERNAME=myuser ADMIN_PASSWORD=mypassword" '"mypassword"' +# Argument values with commas are honored +os::cmd::expect_success 'oc create -f ${TEST_DATA}/application-template-stibuild.json' +os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample MYSQL_USER=myself MYSQL_PASSWORD=my,1%pa=s' '"myself"' +os::cmd::expect_success_and_text 'oc process MYSQL_USER=myself MYSQL_PASSWORD=my,1%pa=s ruby-helloworld-sample' '"my,1%pa=s"' +os::cmd::expect_success_and_text 'oc process ruby-helloworld-sample -p MYSQL_USER=myself -p MYSQL_PASSWORD=my,1%pa=s' '"myself"' +os::cmd::expect_success_and_text 'oc process -p MYSQL_USER=myself -p MYSQL_PASSWORD=my,1%pa=s ruby-helloworld-sample' '"my,1%pa=s"' +# Argument values can be read from file +os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --param-file='${guestbook_params}'" '"root"' +os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --param-file='${guestbook_params}'" '"adminpass"' +os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --param-file='${guestbook_params}'" '"redispass"' +# Argument values can be read from stdin +os::cmd::expect_success_and_text "cat '${guestbook_params}' | oc process -f '${guestbook_template}' --param-file=-" '"root"' +os::cmd::expect_success_and_text "cat '${guestbook_params}' | oc process -f '${guestbook_template}' --param-file=-" '"adminpass"' +os::cmd::expect_success_and_text "cat '${guestbook_params}' | oc process -f '${guestbook_template}' --param-file=-" '"redispass"' +# Argument values from command line have precedence over those from file +os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --param-file='${guestbook_params}' -p ADMIN_USERNAME=myuser" 'ignoring value from file' +os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --param-file='${guestbook_params}' -p ADMIN_USERNAME=myuser" '"myuser"' +os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --param-file='${guestbook_params}' -p ADMIN_PASSWORD=mypassword" '"mypassword"' +os::cmd::expect_success_and_text "oc process -f '${guestbook_template}' --param-file='${guestbook_params}' -p REDIS_PASSWORD=rrr" '"rrr"' +# Set template parameters from parameter file with multiline values +os::cmd::expect_success_and_text "oc process -f ${TEST_DATA}/templates/template_required_params.yaml --param-file=${TEST_DATA}/templates/template_required_params.env -o yaml" 'first$' +os::cmd::expect_success 'oc delete template ruby-helloworld-sample' +# Parameter file failure cases +os::cmd::expect_failure_and_text "oc process -f ${TEST_DATA}/templates/template_required_params.yaml --param-file=does/not/exist" 'no such file or directory' +os::cmd::expect_failure_and_text "oc process -f ${TEST_DATA}/templates/template_required_params.yaml --param-file=${TEST_DATA}" 'is a directory' +os::cmd::expect_failure_and_text "oc process -f ${TEST_DATA}/templates/template_required_params.yaml --param-file=/dev/null" 'parameter required_param is required and must be specified' +os::cmd::expect_success "oc process -f '${guestbook_template}' --param-file=/dev/null --param-file='${guestbook_params}'" +os::cmd::expect_failure_and_text "echo 'fo%(o=bar' | oc process -f ${TEST_DATA}/templates/template_required_params.yaml --param-file=-" 'invalid parameter assignment' +os::cmd::expect_failure_and_text "echo 'S P A C E S=test' | oc process -f ${TEST_DATA}/templates/template_required_params.yaml --param-file=-" 'invalid parameter assignment' +# Handle absent parameter +os::cmd::expect_failure_and_text "oc process -f '${guestbook_template}' -p ABSENT_PARAMETER=absent" 'unknown parameter name' +os::cmd::expect_success "oc process -f '${guestbook_template}' -p ABSENT_PARAMETER=absent --ignore-unknown-parameters" +echo "template+parameters: ok" +os::test::junit::declare_suite_end -func testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectTwoDeploymentConfigsYaml() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectTwoDeploymentConfigsYamlBytes() - if err != nil { - return nil, err - } +os::test::junit::declare_suite_start "cmd/templates/data-precision" +# Run as cluster-admin to allow choosing any supplemental groups we want +# Ensure large integers survive unstructured JSON creation +os::cmd::expect_success 'oc create -f ${TEST_DATA}/templates/template-type-precision.json' +# ... and processing +os::cmd::expect_success_and_text 'oc process template-type-precision' '1000030003' +os::cmd::expect_success_and_text 'oc process template-type-precision' '2147483647' +os::cmd::expect_success_and_text 'oc process template-type-precision' '9223372036854775807' +# ... and re-encoding as structured resources +os::cmd::expect_success 'oc process template-type-precision | oc create -f -' +# ... and persisting +os::cmd::expect_success_and_text 'oc get pod/template-type-precision -o json' '1000030003' +os::cmd::expect_success_and_text 'oc get pod/template-type-precision -o json' '2147483647' +os::cmd::expect_success_and_text 'oc get pod/template-type-precision -o json' '9223372036854775807' +# Ensure patch computation preserves data +patch='{"metadata":{"annotations":{"comment":"patch comment"}}}' +os::cmd::expect_success "oc patch pod template-type-precision -p '${patch}'" +os::cmd::expect_success_and_text 'oc get pod/template-type-precision -o json' '9223372036854775807' +os::cmd::expect_success_and_text 'oc get pod/template-type-precision -o json' 'patch comment' +os::cmd::expect_success 'oc delete template/template-type-precision' +os::cmd::expect_success 'oc delete pod/template-type-precision' +echo "template data precision: ok" +os::test::junit::declare_suite_end - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-two-deployment-configs.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +os::test::junit::declare_suite_start "cmd/templates/different-namespaces" +#os::cmd::expect_success 'oc create -f ${TEST_DATA}/application-template-dockerbuild.json -n openshift' +#os::cmd::expect_success 'oc policy add-role-to-user admin test-user' +#new="$(mktemp -d)/tempconfig" +#os::cmd::expect_success "oc config view --raw > ${new}" +#old="${KUBECONFIG}" +#export KUBECONFIG=${new} +#os::cmd::expect_success 'oc login -u test-user -p password' +#os::cmd::expect_success 'oc new-project test-template-project' +## make sure the permissions on the new project are set up +#os::cmd::try_until_success 'oc get templates' +#os::cmd::expect_success 'oc create -f ${TEST_DATA}/application-template-dockerbuild.json' +#os::cmd::expect_success 'oc process template/ruby-helloworld-sample' +#os::cmd::expect_success 'oc process templates/ruby-helloworld-sample' +#os::cmd::expect_success 'oc process openshift//ruby-helloworld-sample' +#os::cmd::expect_success 'oc process openshift/template/ruby-helloworld-sample' +#os::cmd::expect_success 'oc get template ruby-helloworld-sample -n openshift -o yaml | oc process -f -' +#export KUBECONFIG=${old} +echo "processing templates in different namespace: ok" +os::test::junit::declare_suite_end -var _testExtendedTestdataCmdTestCmdTestdataAppScenariosPetsetYaml = []byte(`apiVersion: v1 -items: -- apiVersion: v1 - kind: Service - metadata: - annotations: - service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" - creationTimestamp: 2016-07-21T15:53:09Z - labels: - app: mysql - name: galera - namespace: default - resourceVersion: "343" - selfLink: /api/v1/namespaces/default/services/galera - uid: 38fb3915-4f5b-11e6-b8a1-080027242396 - spec: - clusterIP: None - ports: - - name: mysql - port: 3306 - protocol: TCP - targetPort: 3306 - selector: - app: mysql - sessionAffinity: None - type: ClusterIP - status: - loadBalancer: {} -- apiVersion: v1 - kind: Pod - metadata: - annotations: - kubernetes.io/created-by: | - {"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"StatefulSet","namespace":"default","name":"mysql","uid":"3900c985-4f5b-11e6-b8a1-080027242396","apiVersion":"apps","resourceVersion":"6784"}} - openshift.io/scc: anyuid - pod.alpha.kubernetes.io/init-container-statuses: '[{"name":"install","state":{"terminated":{"exitCode":0,"reason":"Completed","startedAt":"2016-07-27T02:41:12Z","finishedAt":"2016-07-27T02:41:12Z","containerID":"docker://5c727d8732899605fcfe3eecbeeb02576f18f5b989496073340427a8d2134622"}},"lastState":{},"ready":true,"restartCount":0,"image":"gcr.io/google_containers/galera-install:0.1","imageID":"docker://sha256:56ef857005d0ce479f2db0e4ee0ece05e0766ebfa7e79e27e1513915262a18ec","containerID":"docker://5c727d8732899605fcfe3eecbeeb02576f18f5b989496073340427a8d2134622"},{"name":"bootstrap","state":{"terminated":{"exitCode":0,"reason":"Completed","startedAt":"2016-07-27T02:41:14Z","finishedAt":"2016-07-27T02:41:15Z","containerID":"docker://ab4ca0b3b6ec4860cd55c615534e1e2b11f4c3a33746783aab145919feb2446e"}},"lastState":{},"ready":true,"restartCount":0,"image":"debian:jessie","imageID":"docker://sha256:1b088884749bd93867ddb48ff404d4bbff09a17af8d95bc863efa5d133f87b78","containerID":"docker://ab4ca0b3b6ec4860cd55c615534e1e2b11f4c3a33746783aab145919feb2446e"}]' - pod.alpha.kubernetes.io/init-containers: '[{"name":"install","image":"gcr.io/google_containers/galera-install:0.1","args":["--work-dir=/work-dir"],"resources":{},"volumeMounts":[{"name":"workdir","mountPath":"/work-dir"},{"name":"config","mountPath":"/etc/mysql"},{"name":"default-token-au2xq","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"Always"},{"name":"bootstrap","image":"debian:jessie","command":["/work-dir/peer-finder"],"args":["-on-start=\"/work-dir/on-start.sh\"","-service=galera"],"env":[{"name":"POD_NAMESPACE","valueFrom":{"fieldRef":{"apiVersion":"v1","fieldPath":"metadata.namespace"}}}],"resources":{},"volumeMounts":[{"name":"workdir","mountPath":"/work-dir"},{"name":"config","mountPath":"/etc/mysql"},{"name":"default-token-au2xq","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}]' - pod.alpha.kubernetes.io/initialized: "true" - pod.beta.kubernetes.io/hostname: mysql-0 - pod.beta.kubernetes.io/subdomain: galera - creationTimestamp: 2016-07-27T02:41:09Z - generateName: mysql- - labels: - app: mysql - name: mysql-0 - namespace: default - resourceVersion: "7191" - selfLink: /api/v1/namespaces/default/pods/mysql-0 - uid: 92e49e79-53a3-11e6-b45a-080027242396 - spec: - containers: - - args: - - --defaults-file=/etc/mysql/my-galera.cnf - - --user=root - image: erkules/galera:basic - imagePullPolicy: IfNotPresent - name: mysql - ports: - - containerPort: 3306 - name: mysql - protocol: TCP - - containerPort: 4444 - name: sst - protocol: TCP - - containerPort: 4567 - name: replication - protocol: TCP - - containerPort: 4568 - name: ist - protocol: TCP - readinessProbe: - exec: - command: - - sh - - -c - - mysql -u root -e 'show databases;' - failureThreshold: 3 - initialDelaySeconds: 15 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 5 - resources: {} - securityContext: - capabilities: - drop: - - MKNOD - - SYS_CHROOT - privileged: false - seLinuxOptions: - level: s0:c5,c0 - terminationMessagePath: /dev/termination-log - volumeMounts: - - mountPath: /var/lib/ - name: datadir - - mountPath: /etc/mysql - name: config - - mountPath: /var/run/secrets/kubernetes.io/serviceaccount - name: default-token-au2xq - readOnly: true - dnsPolicy: ClusterFirst - host: localhost.localdomain - imagePullSecrets: - - name: default-dockercfg-pzhsj - nodeName: localhost.localdomain - restartPolicy: Always - securityContext: - seLinuxOptions: - level: s0:c5,c0 - serviceAccount: default - serviceAccountName: default - terminationGracePeriodSeconds: 30 - volumes: - - name: datadir - persistentVolumeClaim: - claimName: datadir-mysql-0 - - emptyDir: {} - name: config - - emptyDir: {} - name: workdir - - name: default-token-au2xq - secret: - secretName: default-token-au2xq - status: - conditions: - - lastProbeTime: null - lastTransitionTime: 2016-07-27T02:41:15Z - status: "True" - type: Initialized - - lastProbeTime: null - lastTransitionTime: 2016-07-27T03:00:47Z - status: "True" - type: Ready - - lastProbeTime: null - lastTransitionTime: 2016-07-27T02:41:09Z - status: "True" - type: PodScheduled - containerStatuses: - - containerID: docker://f2406b0f697c525df44b64aec6b1f6024ab88d9df80256426247dc6e9a92cb30 - image: erkules/galera:basic - imageID: docker://sha256:b4780e247a38c12612f539ce1ac8e0988e1781d56fddf719c80fb8d4d7b8bbde - lastState: {} - name: mysql - ready: true - restartCount: 0 - state: - running: - startedAt: 2016-07-27T02:41:16Z - hostIP: 10.0.2.15 - phase: Running - podIP: 172.17.0.2 - startTime: 2016-07-27T02:41:09Z -- apiVersion: v1 - kind: Pod - metadata: - annotations: - kubernetes.io/created-by: | - {"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"StatefulSet","namespace":"default","name":"mysql","uid":"3900c985-4f5b-11e6-b8a1-080027242396","apiVersion":"apps","resourceVersion":"6790"}} - openshift.io/scc: anyuid - pod.alpha.kubernetes.io/init-container-statuses: '[{"name":"install","state":{"terminated":{"exitCode":0,"reason":"Completed","startedAt":"2016-07-27T02:41:42Z","finishedAt":"2016-07-27T02:41:42Z","containerID":"docker://2538c65f65557955c02745ef4021181cf322c8dc0db62144dd1e1f8ea9f7fa54"}},"lastState":{},"ready":true,"restartCount":0,"image":"gcr.io/google_containers/galera-install:0.1","imageID":"docker://sha256:56ef857005d0ce479f2db0e4ee0ece05e0766ebfa7e79e27e1513915262a18ec","containerID":"docker://2538c65f65557955c02745ef4021181cf322c8dc0db62144dd1e1f8ea9f7fa54"},{"name":"bootstrap","state":{"terminated":{"exitCode":0,"reason":"Completed","startedAt":"2016-07-27T02:41:44Z","finishedAt":"2016-07-27T02:41:45Z","containerID":"docker://4df7188d37033c182e675d45179941766bd1e6a013469038f43fa3fecc2cc06d"}},"lastState":{},"ready":true,"restartCount":0,"image":"debian:jessie","imageID":"docker://sha256:1b088884749bd93867ddb48ff404d4bbff09a17af8d95bc863efa5d133f87b78","containerID":"docker://4df7188d37033c182e675d45179941766bd1e6a013469038f43fa3fecc2cc06d"}]' - pod.alpha.kubernetes.io/init-containers: '[{"name":"install","image":"gcr.io/google_containers/galera-install:0.1","args":["--work-dir=/work-dir"],"resources":{},"volumeMounts":[{"name":"workdir","mountPath":"/work-dir"},{"name":"config","mountPath":"/etc/mysql"},{"name":"default-token-au2xq","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"Always"},{"name":"bootstrap","image":"debian:jessie","command":["/work-dir/peer-finder"],"args":["-on-start=\"/work-dir/on-start.sh\"","-service=galera"],"env":[{"name":"POD_NAMESPACE","valueFrom":{"fieldRef":{"apiVersion":"v1","fieldPath":"metadata.namespace"}}}],"resources":{},"volumeMounts":[{"name":"workdir","mountPath":"/work-dir"},{"name":"config","mountPath":"/etc/mysql"},{"name":"default-token-au2xq","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}]' - pod.alpha.kubernetes.io/initialized: "true" - pod.beta.kubernetes.io/hostname: mysql-1 - pod.beta.kubernetes.io/subdomain: galera - creationTimestamp: 2016-07-27T02:41:39Z - generateName: mysql- - labels: - app: mysql - name: mysql-1 - namespace: default - resourceVersion: "7195" - selfLink: /api/v1/namespaces/default/pods/mysql-1 - uid: a4da4725-53a3-11e6-b45a-080027242396 - spec: - containers: - - args: - - --defaults-file=/etc/mysql/my-galera.cnf - - --user=root - image: erkules/galera:basic - imagePullPolicy: IfNotPresent - name: mysql - ports: - - containerPort: 3306 - name: mysql - protocol: TCP - - containerPort: 4444 - name: sst - protocol: TCP - - containerPort: 4567 - name: replication - protocol: TCP - - containerPort: 4568 - name: ist - protocol: TCP - readinessProbe: - exec: - command: - - sh - - -c - - mysql -u root -e 'show databases;' - failureThreshold: 3 - initialDelaySeconds: 15 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 5 - resources: {} - securityContext: - capabilities: - drop: - - MKNOD - - SYS_CHROOT - privileged: false - seLinuxOptions: - level: s0:c5,c0 - terminationMessagePath: /dev/termination-log - volumeMounts: - - mountPath: /var/lib/ - name: datadir - - mountPath: /etc/mysql - name: config - - mountPath: /var/run/secrets/kubernetes.io/serviceaccount - name: default-token-au2xq - readOnly: true - dnsPolicy: ClusterFirst - host: localhost.localdomain - imagePullSecrets: - - name: default-dockercfg-pzhsj - nodeName: localhost.localdomain - restartPolicy: Always - securityContext: - seLinuxOptions: - level: s0:c5,c0 - serviceAccount: default - serviceAccountName: default - terminationGracePeriodSeconds: 30 - volumes: - - name: datadir - persistentVolumeClaim: - claimName: datadir-mysql-1 - - emptyDir: {} - name: config - - emptyDir: {} - name: workdir - - name: default-token-au2xq - secret: - secretName: default-token-au2xq - status: - conditions: - - lastProbeTime: null - lastTransitionTime: 2016-07-27T02:41:46Z - status: "True" - type: Initialized - - lastProbeTime: null - lastTransitionTime: 2016-07-27T03:00:58Z - status: "True" - type: Ready - - lastProbeTime: null - lastTransitionTime: 2016-07-27T02:41:39Z - status: "True" - type: PodScheduled - containerStatuses: - - containerID: docker://be1d5be42ab23d1db23f4552141e9068e2385ba19c3e84596e047eb6d2762d1c - image: erkules/galera:basic - imageID: docker://sha256:b4780e247a38c12612f539ce1ac8e0988e1781d56fddf719c80fb8d4d7b8bbde - lastState: - terminated: - containerID: docker://9a662fa5b74a962fa362c6a5d632fe3642b12fefde36c8158ab1a50d8fa4e33e - exitCode: 1 - finishedAt: 2016-07-27T02:51:40Z - reason: Error - startedAt: 2016-07-27T02:51:05Z - name: mysql - ready: true - restartCount: 7 - state: - running: - startedAt: 2016-07-27T03:00:39Z - hostIP: 10.0.2.15 - phase: Running - podIP: 172.17.0.3 - startTime: 2016-07-27T02:41:39Z -- apiVersion: v1 - kind: Pod - metadata: - annotations: - kubernetes.io/created-by: | - {"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"StatefulSet","namespace":"default","name":"mysql","uid":"3900c985-4f5b-11e6-b8a1-080027242396","apiVersion":"apps","resourceVersion":"6790"}} - openshift.io/scc: anyuid - pod.alpha.kubernetes.io/init-container-statuses: '[{"name":"install","state":{"terminated":{"exitCode":0,"reason":"Completed","startedAt":"2016-07-27T03:01:01Z","finishedAt":"2016-07-27T03:01:01Z","containerID":"docker://af008b4ce59d36695fbabf40ae2f7431b51441eb2e9c6962378937c06ac69a35"}},"lastState":{},"ready":true,"restartCount":0,"image":"gcr.io/google_containers/galera-install:0.1","imageID":"docker://sha256:56ef857005d0ce479f2db0e4ee0ece05e0766ebfa7e79e27e1513915262a18ec","containerID":"docker://af008b4ce59d36695fbabf40ae2f7431b51441eb2e9c6962378937c06ac69a35"},{"name":"bootstrap","state":{"terminated":{"exitCode":0,"reason":"Completed","startedAt":"2016-07-27T03:01:02Z","finishedAt":"2016-07-27T03:01:03Z","containerID":"docker://ee97005854130335b54a65429865956260b7729e51e6363ab05e63d5c7c9ee48"}},"lastState":{},"ready":true,"restartCount":0,"image":"debian:jessie","imageID":"docker://sha256:1b088884749bd93867ddb48ff404d4bbff09a17af8d95bc863efa5d133f87b78","containerID":"docker://ee97005854130335b54a65429865956260b7729e51e6363ab05e63d5c7c9ee48"}]' - pod.alpha.kubernetes.io/init-containers: '[{"name":"install","image":"gcr.io/google_containers/galera-install:0.1","args":["--work-dir=/work-dir"],"resources":{},"volumeMounts":[{"name":"workdir","mountPath":"/work-dir"},{"name":"config","mountPath":"/etc/mysql"},{"name":"default-token-au2xq","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"Always"},{"name":"bootstrap","image":"debian:jessie","command":["/work-dir/peer-finder"],"args":["-on-start=\"/work-dir/on-start.sh\"","-service=galera"],"env":[{"name":"POD_NAMESPACE","valueFrom":{"fieldRef":{"apiVersion":"v1","fieldPath":"metadata.namespace"}}}],"resources":{},"volumeMounts":[{"name":"workdir","mountPath":"/work-dir"},{"name":"config","mountPath":"/etc/mysql"},{"name":"default-token-au2xq","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}]' - pod.alpha.kubernetes.io/initialized: "true" - pod.beta.kubernetes.io/hostname: mysql-2 - pod.beta.kubernetes.io/subdomain: galera - creationTimestamp: 2016-07-27T03:00:58Z - generateName: mysql- - labels: - app: mysql - name: mysql-2 - namespace: default - resourceVersion: "7226" - selfLink: /api/v1/namespaces/default/pods/mysql-2 - uid: 57e618f1-53a6-11e6-b215-080027242396 - spec: - containers: - - args: - - --defaults-file=/etc/mysql/my-galera.cnf - - --user=root - image: erkules/galera:basic - imagePullPolicy: IfNotPresent - name: mysql - ports: - - containerPort: 3306 - name: mysql - protocol: TCP - - containerPort: 4444 - name: sst - protocol: TCP - - containerPort: 4567 - name: replication - protocol: TCP - - containerPort: 4568 - name: ist - protocol: TCP - readinessProbe: - exec: - command: - - sh - - -c - - mysql -u root -e 'show databases;' - failureThreshold: 3 - initialDelaySeconds: 15 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 5 - resources: {} - securityContext: - capabilities: - drop: - - MKNOD - - SYS_CHROOT - privileged: false - seLinuxOptions: - level: s0:c5,c0 - terminationMessagePath: /dev/termination-log - volumeMounts: - - mountPath: /var/lib/ - name: datadir - - mountPath: /etc/mysql - name: config - - mountPath: /var/run/secrets/kubernetes.io/serviceaccount - name: default-token-au2xq - readOnly: true - dnsPolicy: ClusterFirst - host: localhost.localdomain - imagePullSecrets: - - name: default-dockercfg-pzhsj - nodeName: localhost.localdomain - restartPolicy: Always - securityContext: - seLinuxOptions: - level: s0:c5,c0 - serviceAccount: default - serviceAccountName: default - terminationGracePeriodSeconds: 30 - volumes: - - name: datadir - persistentVolumeClaim: - claimName: datadir-mysql-2 - - emptyDir: {} - name: config - - emptyDir: {} - name: workdir - - name: default-token-au2xq - secret: - secretName: default-token-au2xq - status: - conditions: - - lastProbeTime: null - lastTransitionTime: 2016-07-27T03:01:03Z - status: "True" - type: Initialized - - lastProbeTime: null - lastTransitionTime: 2016-07-27T03:01:28Z - status: "True" - type: Ready - - lastProbeTime: null - lastTransitionTime: 2016-07-27T03:00:58Z - status: "True" - type: PodScheduled - containerStatuses: - - containerID: docker://82b774855cdb5d12d98e7bc34f4f9d4e88e757e9cc2da1593e2e2f66e3241e5f - image: erkules/galera:basic - imageID: docker://sha256:b4780e247a38c12612f539ce1ac8e0988e1781d56fddf719c80fb8d4d7b8bbde - lastState: {} - name: mysql - ready: true - restartCount: 0 - state: - running: - startedAt: 2016-07-27T03:01:04Z - hostIP: 10.0.2.15 - phase: Running - podIP: 172.17.0.4 - startTime: 2016-07-27T03:00:58Z -- apiVersion: apps/v1 - kind: StatefulSet - metadata: - creationTimestamp: 2016-07-21T15:53:09Z - generation: 3 - labels: - app: mysql - name: mysql - namespace: default - resourceVersion: "6790" - selfLink: /apis/apps/v1/namespaces/default/statefulsets/mysql - uid: 3900c985-4f5b-11e6-b8a1-080027242396 - spec: - replicas: 3 - selector: - matchLabels: - app: mysql - serviceName: galera - template: - metadata: - annotations: - pod.alpha.kubernetes.io/init-containers: '[{"name":"install","image":"gcr.io/google_containers/galera-install:0.1","args":["--work-dir=/work-dir"],"resources":{},"volumeMounts":[{"name":"workdir","mountPath":"/work-dir"},{"name":"config","mountPath":"/etc/mysql"}],"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"Always"},{"name":"bootstrap","image":"debian:jessie","command":["/work-dir/peer-finder"],"args":["-on-start=\"/work-dir/on-start.sh\"","-service=galera"],"env":[{"name":"POD_NAMESPACE","valueFrom":{"fieldRef":{"apiVersion":"v1","fieldPath":"metadata.namespace"}}}],"resources":{},"volumeMounts":[{"name":"workdir","mountPath":"/work-dir"},{"name":"config","mountPath":"/etc/mysql"}],"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}]' - pod.alpha.kubernetes.io/initialized: "true" - creationTimestamp: null - labels: - app: mysql - spec: - containers: - - args: - - --defaults-file=/etc/mysql/my-galera.cnf - - --user=root - image: erkules/galera:basic - imagePullPolicy: IfNotPresent - name: mysql - ports: - - containerPort: 3306 - name: mysql - protocol: TCP - - containerPort: 4444 - name: sst - protocol: TCP - - containerPort: 4567 - name: replication - protocol: TCP - - containerPort: 4568 - name: ist - protocol: TCP - readinessProbe: - exec: - command: - - sh - - -c - - mysql -u root -e 'show databases;' - failureThreshold: 3 - initialDelaySeconds: 15 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 5 - resources: {} - terminationMessagePath: /dev/termination-log - volumeMounts: - - mountPath: /var/lib/ - name: datadir - - mountPath: /etc/mysql - name: config - dnsPolicy: ClusterFirst - restartPolicy: Always - securityContext: {} - terminationGracePeriodSeconds: 30 - volumes: - - emptyDir: {} - name: config - - emptyDir: {} - name: workdir - volumeClaimTemplates: - - metadata: - annotations: - volume.alpha.kubernetes.io/storage-class: anything - creationTimestamp: null - name: datadir - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi - status: - phase: Pending - status: - replicas: 3 -kind: List -metadata: {} +os::test::junit::declare_suite_start "cmd/templates/process" +# This test validates oc process +# fail to process two templates by name +os::cmd::expect_failure_and_text 'oc process name1 name2' 'template name must be specified only once' +# fail to pass a filename or template by name +os::cmd::expect_failure_and_text 'oc process' 'Must pass a filename or name of stored template' +# can't ask for parameters and try process the template +os::cmd::expect_failure_and_text 'oc process template-name --parameters --param=someval' '\-\-parameters flag does not process the template, can.t be used with \-\-param' +os::cmd::expect_failure_and_text 'oc process template-name --parameters -p someval' '\-\-parameters flag does not process the template, can.t be used with \-\-param' +os::cmd::expect_failure_and_text 'oc process template-name --parameters --labels=someval' '\-\-parameters flag does not process the template, can.t be used with \-\-labels' +os::cmd::expect_failure_and_text 'oc process template-name --parameters -l someval' '\-\-parameters flag does not process the template, can.t be used with \-\-labels' +os::cmd::expect_failure_and_text 'oc process template-name --parameters --output=yaml' '\-\-parameters flag does not process the template, can.t be used with \-\-output' +os::cmd::expect_failure_and_text 'oc process template-name --parameters -o yaml' '\-\-parameters flag does not process the template, can.t be used with \-\-output' +os::cmd::expect_failure_and_text 'oc process template-name --parameters --raw' '\-\-parameters flag does not process the template, can.t be used with \-\-raw' +os::cmd::expect_failure_and_text 'oc process template-name --parameters --template=someval' '\-\-parameters flag does not process the template, can.t be used with \-\-template' +# providing a value more than once should fail +os::cmd::expect_failure_and_text 'oc process template-name key=value key=value' 'provided more than once: key' +os::cmd::expect_failure_and_text 'oc process template-name --param=key=value --param=key=value' 'provided more than once: key' +os::cmd::expect_failure_and_text 'oc process template-name key=value --param=key=value' 'provided more than once: key' +os::cmd::expect_failure_and_text 'oc process template-name key=value other=foo --param=key=value --param=other=baz' 'provided more than once: key, other' +required_params="${TEST_DATA}/templates/template_required_params.yaml" +# providing something other than a template is not OK +os::cmd::expect_failure_and_text "oc process -f '${TEST_DATA}/templates/basic-users-binding.json'" 'not a valid Template but' +# not providing required parameter should fail +os::cmd::expect_failure_and_text "oc process -f '${required_params}'" 'parameter required_param is required and must be specified' +# not providing an optional param is OK +os::cmd::expect_success "oc process -f '${required_params}' --param=required_param=someval" +os::cmd::expect_success "oc process -f '${required_params}' -p required_param=someval | oc create -f -" +# parameters with multiple equal signs are OK +os::cmd::expect_success "oc process -f '${required_params}' required_param=someval=moreval | oc create -f -" +os::cmd::expect_success "oc process -f '${required_params}' -p required_param=someval=moreval2 | oc create -f -" +os::cmd::expect_success "oc process -f '${required_params}' -p required_param=someval=moreval3 | oc create -f -" +# we should have overwritten the template param +os::cmd::expect_success_and_text 'oc get user someval -o jsonpath={.metadata.name}' 'someval' +os::cmd::expect_success_and_text 'oc get user someval=moreval -o jsonpath={.metadata.name}' 'someval=moreval' +os::cmd::expect_success_and_text 'oc get user someval=moreval2 -o jsonpath={.metadata.name}' 'someval=moreval2' +os::cmd::expect_success_and_text 'oc get user someval=moreval3 -o jsonpath={.metadata.name}' 'someval=moreval3' +# providing a value not in the template should fail +os::cmd::expect_failure_and_text "oc process -f '${required_params}' --param=required_param=someval --param=other_param=otherval" 'unknown parameter name "other_param"' +# failure on values fails the entire call +os::cmd::expect_failure_and_text "oc process -f '${required_params}' --param=required_param=someval --param=optional_param" 'invalid parameter assignment in' +# failure on labels fails the entire call +os::cmd::expect_failure_and_text "oc process -f '${required_params}' --param=required_param=someval --labels======" 'error parsing labels' +# values are not split on commas, required parameter is not recognized +os::cmd::expect_failure_and_text "oc process -f '${required_params}' --param=optional_param=a,required_param=b" 'parameter required_param is required and must be specified' +# warning is printed iff --value/--param looks like two k-v pairs separated by comma +os::cmd::expect_success_and_text "oc process -f '${required_params}' --param=required_param=a,b=c,d" 'no longer accepts comma-separated list' +os::cmd::expect_success_and_not_text "oc process -f '${required_params}' --param=required_param=a_b_c_d" 'no longer accepts comma-separated list' +os::cmd::expect_success_and_not_text "oc process -f '${required_params}' --param=required_param=a,b,c,d" 'no longer accepts comma-separated list' +# warning is not printed for template values passed as positional arguments +os::cmd::expect_success_and_not_text "oc process -f '${required_params}' required_param=a,b=c,d" 'no longer accepts comma-separated list' +# set template parameter to contents of file +os::cmd::expect_success_and_text "oc process -f '${required_params}' --param=required_param='` + "`" + `cat ${TEST_DATA}/templates/multiline.txt` + "`" + `'" 'also,with=commas' +echo "process: ok" +os::test::junit::declare_suite_end + +os::test::junit::declare_suite_end `) -func testExtendedTestdataCmdTestCmdTestdataAppScenariosPetsetYamlBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataAppScenariosPetsetYaml, nil +func testExtendedTestdataCmdTestCmdTemplatesShBytes() ([]byte, error) { + return _testExtendedTestdataCmdTestCmdTemplatesSh, nil } -func testExtendedTestdataCmdTestCmdTestdataAppScenariosPetsetYaml() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataAppScenariosPetsetYamlBytes() +func testExtendedTestdataCmdTestCmdTemplatesSh() (*asset, error) { + bytes, err := testExtendedTestdataCmdTestCmdTemplatesShBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/petset.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/templates.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -38946,7 +33659,7 @@ var _testExtendedTestdataCmdTestCmdTestdataApplicationTemplateCustombuildJson = "containers": [ { "name": "ruby-helloworld-database", - "image": "centos/mysql-57-centos7:latest", + "image": "image-registry.openshift-image-registry.svc:5000/openshift/mysql:5.7", "ports": [ { "containerPort": 3306, @@ -39408,7 +34121,7 @@ var _testExtendedTestdataCmdTestCmdTestdataApplicationTemplateDockerbuildJson = "containers": [ { "name": "ruby-helloworld-database", - "image": "centos/mysql-57-centos7:latest", + "image": "image-registry.openshift-image-registry.svc:5000/openshift/mysql:5.7", "ports": [ { "containerPort": 3306, @@ -39915,7 +34628,7 @@ var _testExtendedTestdataCmdTestCmdTestdataApplicationTemplateStibuildJson = []b "containers": [ { "name": "ruby-helloworld-database", - "image": "centos/mysql-57-centos7:latest", + "image": "image-registry.openshift-image-registry.svc:5000/openshift/mysql:5.7", "ports": [ { "containerPort": 3306, @@ -40164,7 +34877,8 @@ var _testExtendedTestdataCmdTestCmdTestdataHelloOpenshiftHelloPodJson = []byte(` "containers": [ { "name": "hello-openshift", - "image": "openshift/hello-openshift", + "image": "k8s.gcr.io/e2e-test-images/agnhost:2.20", + "args": ["netexec"], "ports": [ { "containerPort": 8080, @@ -40233,7 +34947,7 @@ spec: deploymentconfig: idling-echo spec: containers: - - image: openshift/origin-base + - image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest name: idling-tcp-echo command: - /usr/bin/socat @@ -40242,7 +34956,7 @@ spec: ports: - containerPort: 8675 protocol: TCP - - image: openshift/origin-base + - image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest name: idling-udp-echo command: - /usr/bin/socat @@ -40367,56 +35081,59 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = "tags": [ { "annotations": { - "description": "Build and run .NET Core applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.1/build/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of .NET Core available on OpenShift, including major versions updates.", + "description": "Build and run .NET Core applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of .NET Core available on OpenShift, including major versions updates.", "iconClass": "icon-dotnet", "openshift.io/display-name": ".NET Core (Latest)", "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.1", + "sampleRef": "dotnetcore-3.1", "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", "supports": "dotnet", "tags": "builder,.net,dotnet,dotnetcore" }, "from": { "kind": "ImageStreamTag", - "name": "2.1" + "name": "3.1" }, - "name": "latest" + "name": "latest", + "referencePolicy": { + "type": "Local" + } }, { "annotations": { - "description": "Build and run .NET Core 2.1 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.0/build/README.md.", + "description": "Build and run .NET Core 2.2 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/blob/master/2.2/build/README.md.", "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 2.1", + "openshift.io/display-name": ".NET Core 2.2", "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.1", + "sampleRef": "dotnetcore-2.2", "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:2.1,dotnet", + "supports": "dotnet:2.2,dotnet", "tags": "builder,.net,dotnet,dotnetcore,rh-dotnet21", - "version": "2.1" + "version": "2.2" }, "from": { "kind": "DockerImage", - "name": "registry.centos.org/dotnet/dotnet-21-centos7:latest" + "name": "registry.centos.org/dotnet/dotnet-22-centos7:latest" }, - "name": "2.1" + "name": "2.2" }, { "annotations": { - "description": "RETIRED: Build and run .NET Core 2.0 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.0/build/README.md.", + "description": "Build and run .NET Core 3.1 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/blob/master/3.1/build/README.md.", "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 2.0", + "openshift.io/display-name": ".NET Core 3.1", "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.0", + "sampleRef": "dotnetcore-3.1", "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:2.0,dotnet", - "tags": "hidden,builder,.net,dotnet,dotnetcore,rh-dotnet20", - "version": "2.0" + "supports": "dotnet:3.1,dotnet", + "tags": "builder,.net,dotnet,dotnetcore,rh-dotnet21", + "version": "3.1" }, "from": { "kind": "DockerImage", - "name": "registry.centos.org/dotnet/dotnet-20-centos7:latest" + "name": "registry.centos.org/dotnet/dotnet-31-centos7:latest" }, - "name": "2.0" + "name": "3.1" } ] } @@ -40434,7 +35151,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = "tags": [ { "annotations": { - "description": "Build and serve static content via Apache HTTP Server (httpd) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/httpd-container/blob/master/2.4/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Httpd available on OpenShift, including major versions updates.", + "description": "Build and serve static content via Apache HTTP Server (httpd) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/httpd-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Httpd available on OpenShift, including major versions updates.", "iconClass": "icon-apache", "openshift.io/display-name": "Apache HTTP Server (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -40464,7 +35181,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/httpd-24-centos7:latest" + "name": "registry.centos.org/centos/httpd-24-centos7:latest" }, "name": "2.4", "referencePolicy": { @@ -40536,7 +35253,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = "tags": [ { "annotations": { - "description": "Provides a MariaDB database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.2/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MariaDB available on OpenShift, including major versions updates.", + "description": "Provides a MariaDB database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/blob/master/10.2/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MariaDB available on OpenShift, including major versions updates.", "iconClass": "icon-mariadb", "openshift.io/display-name": "MariaDB (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -40553,7 +35270,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, { "annotations": { - "description": "Provides a MariaDB 10.1 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.1/README.md.", + "description": "Provides a MariaDB 10.1 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/blob/master/10.1/README.md.", "iconClass": "icon-mariadb", "openshift.io/display-name": "MariaDB 10.1", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -40562,7 +35279,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mariadb-101-centos7:latest" + "name": "registry.centos.org/centos/mariadb-101-centos7:latest" }, "name": "10.1", "referencePolicy": { @@ -40571,7 +35288,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, { "annotations": { - "description": "Provides a MariaDB 10.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.2/README.md.", + "description": "Provides a MariaDB 10.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/blob/master/10.2/README.md.", "iconClass": "icon-mariadb", "openshift.io/display-name": "MariaDB 10.2", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -40580,7 +35297,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mariadb-102-centos7:latest" + "name": "registry.centos.org/centos/mariadb-102-centos7:latest" }, "name": "10.2", "referencePolicy": { @@ -40603,7 +35320,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = "tags": [ { "annotations": { - "description": "Provides a MongoDB database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.4/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MongoDB available on OpenShift, including major versions updates.", + "description": "Provides a MongoDB database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MongoDB available on OpenShift, including major versions updates.", "iconClass": "icon-mongodb", "openshift.io/display-name": "MongoDB (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -40611,7 +35328,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "ImageStreamTag", - "name": "3.6" + "name": "3.4" }, "name": "latest", "referencePolicy": { @@ -40629,7 +35346,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mongodb-26-centos7:latest" + "name": "registry.centos.org/centos/mongodb-26-centos7:latest" }, "name": "2.7", "referencePolicy": { @@ -40638,7 +35355,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, { "annotations": { - "description": "Provides a MongoDB 3.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.2/README.md.", + "description": "Provides a MongoDB 3.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/blob/master/3.2/README.md.", "iconClass": "icon-mongodb", "openshift.io/display-name": "MongoDB 3.2", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -40647,7 +35364,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mongodb-32-centos7:latest" + "name": "registry.centos.org/centos/mongodb-32-centos7:latest" }, "name": "3.2", "referencePolicy": { @@ -40656,7 +35373,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, { "annotations": { - "description": "Provides a MongoDB 3.4 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.4/README.md.", + "description": "Provides a MongoDB 3.4 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/blob/master/3.4/README.md.", "iconClass": "icon-mongodb", "openshift.io/display-name": "MongoDB 3.4", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -40665,30 +35382,12 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mongodb-34-centos7:latest" + "name": "registry.centos.org/centos/mongodb-34-centos7:latest" }, "name": "3.4", "referencePolicy": { "type": "Local" } - }, - { - "annotations": { - "description": "Provides a MongoDB 3.6 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.6/README.md.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB 3.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,mongodb", - "version": "3.6" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/mongodb-36-centos7:latest" - }, - "name": "3.6", - "referencePolicy": { - "type": "Local" - } } ] } @@ -40721,24 +35420,6 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = "type": "Local" } }, - { - "annotations": { - "description": "Provides a MySQL 5.5 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/README.md.", - "iconClass": "icon-mysql-database", - "openshift.io/display-name": "MySQL 5.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,mysql", - "version": "5.5" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/mysql-55-centos7:latest" - }, - "name": "5.5", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Provides a MySQL 5.6 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/README.md.", @@ -40750,7 +35431,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mysql-56-centos7:latest" + "name": "registry.centos.org/centos/mysql-56-centos7:latest" }, "name": "5.6", "referencePolicy": { @@ -40768,7 +35449,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mysql-57-centos7:latest" + "name": "registry.centos.org/centos/mysql-57-centos7:latest" }, "name": "5.7", "referencePolicy": { @@ -40791,60 +35472,40 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = "tags": [ { "annotations": { - "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.8/README.md.", + "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.14/README.md.", "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.8", + "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.14", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/sclorg/nginx-ex.git", "supports": "nginx", "tags": "builder,nginx", - "version": "1.8" + "version": "1.14" }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/nginx-18-centos7:latest" + "name": "registry.centos.org/centos/nginx-114-centos7:latest" }, - "name": "1.8", + "name": "1.14", "referencePolicy": { "type": "Local" } }, { "annotations": { - "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.10/README.md.", + "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.16/README.md.", "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.10", + "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.16", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/sclorg/nginx-ex.git", "supports": "nginx", "tags": "builder,nginx", - "version": "1.10" + "version": "1.16" }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/nginx-110-centos7:latest" + "name": "registry.centos.org/centos/nginx-116-centos7:latest" }, - "name": "1.10", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.12/README.md.", - "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.12", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nginx-ex.git", - "supports": "nginx", - "tags": "builder,nginx", - "version": "1.12" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/nginx-112-centos7:latest" - }, - "name": "1.12", + "name": "1.16", "referencePolicy": { "type": "Local" } @@ -40861,7 +35522,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "ImageStreamTag", - "name": "1.12" + "name": "1.16" }, "name": "latest", "referencePolicy": { @@ -40894,7 +35555,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "ImageStreamTag", - "name": "11" + "name": "12" }, "name": "latest", "referencePolicy": { @@ -40903,105 +35564,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, { "annotations": { - "description": "DEPRECATED: Build and run Node.js 0.10 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/0.10/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 0.10", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:0.10,nodejs:0.1,nodejs", - "tags": "hidden,nodejs", - "version": "0.10" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/nodejs-010-centos7:latest" - }, - "name": "0.10", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 4 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/4/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:4,nodejs", - "tags": "hidden,builder,nodejs", - "version": "4" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/nodejs-4-centos7:latest" - }, - "name": "4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 6 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/6/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:6,nodejs", - "tags": "builder,nodejs", - "version": "6" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/nodejs-6-centos7:latest" - }, - "name": "6", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 8 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/8/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 8", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "tags": "builder,nodejs", - "version": "8" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/nodejs-8-centos7:latest" - }, - "name": "8", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 8 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 8 (RHOAR)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "tags": "builder,nodejs", - "version": "8" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/nodeshift/centos7-s2i-nodejs:8.x" - }, - "name": "8-RHOAR", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 10 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.", + "description": "Build and run Node.js 10 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/10/README.md.", "iconClass": "icon-nodejs", "openshift.io/display-name": "Node.js 10", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -41011,7 +35574,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/nodeshift/centos7-s2i-nodejs:10.x" + "name": "registry.centos.org/centos/nodejs-10-centos7:latest" }, "name": "10", "referencePolicy": { @@ -41020,19 +35583,19 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, { "annotations": { - "description": "Build and run Node.js 11 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.", + "description": "Build and run Node.js 12 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/12/README.md.", "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 11", + "openshift.io/display-name": "Node.js 12", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", "tags": "builder,nodejs", - "version": "11" + "version": "12" }, "from": { "kind": "DockerImage", - "name": "docker.io/nodeshift/centos7-s2i-nodejs:11.x" + "name": "registry.centos.org/centos/nodejs-12-centos7:latest" }, - "name": "11", + "name": "12", "referencePolicy": { "type": "Local" } @@ -41070,46 +35633,6 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = "type": "Local" } }, - { - "annotations": { - "description": "Build and run Perl 5.16 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.16/README.md.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl 5.16", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl:5.16,perl", - "tags": "hidden,builder,perl", - "version": "5.16" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/perl-516-centos7:latest" - }, - "name": "5.16", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Perl 5.20 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.20/README.md.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl 5.20", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl:5.20,perl", - "tags": "hidden,builder,perl", - "version": "5.20" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/perl-520-centos7:latest" - }, - "name": "5.20", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Build and run Perl 5.24 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.24/README.md.", @@ -41123,7 +35646,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/perl-524-centos7:latest" + "name": "registry.centos.org/centos/perl-524-centos7:latest" }, "name": "5.24", "referencePolicy": { @@ -41143,7 +35666,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/perl-526-centos7:latest" + "name": "registry.centos.org/centos/perl-526-centos7:latest" }, "name": "5.26", "referencePolicy": { @@ -41183,46 +35706,6 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = "type": "Local" } }, - { - "annotations": { - "description": "Build and run PHP 5.5 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/5.5/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP 5.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php:5.5,php", - "tags": "hidden,builder,php", - "version": "5.5" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/php-55-centos7:latest" - }, - "name": "5.5", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run PHP 5.6 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/5.6/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP 5.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php:5.6,php", - "tags": "hidden,builder,php", - "version": "5.6" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/php-56-centos7:latest" - }, - "name": "5.6", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Build and run PHP 7.0 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/7.0/README.md.", @@ -41236,7 +35719,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/php-70-centos7:latest" + "name": "registry.centos.org/centos/php-70-centos7:latest" }, "name": "7.0", "referencePolicy": { @@ -41256,7 +35739,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/php-71-centos7:latest" + "name": "registry.centos.org/centos/php-71-centos7:latest" }, "name": "7.1", "referencePolicy": { @@ -41287,49 +35770,13 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "ImageStreamTag", - "name": "10" + "name": "9.6" }, "name": "latest", "referencePolicy": { "type": "Local" } }, - { - "annotations": { - "description": "Provides a PostgreSQL 9.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 9.2", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,postgresql", - "version": "9.2" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/postgresql-92-centos7:latest" - }, - "name": "9.2", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 9.4 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 9.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,database,postgresql", - "version": "9.4" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/postgresql-94-centos7:latest" - }, - "name": "9.4", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Provides a PostgreSQL 9.5 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", @@ -41341,7 +35788,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/postgresql-95-centos7:latest" + "name": "registry.centos.org/centos/postgresql-95-centos7:latest" }, "name": "9.5", "referencePolicy": { @@ -41359,30 +35806,12 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/postgresql-96-centos7:latest" + "name": "registry.centos.org/centos/postgresql-96-centos7:latest" }, "name": "9.6", "referencePolicy": { "type": "Local" } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 10 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 10", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,postgresql", - "version": "10" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/postgresql-10-centos7:latest" - }, - "name": "10", - "referencePolicy": { - "type": "Local" - } } ] } @@ -41417,26 +35846,6 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = "type": "Local" } }, - { - "annotations": { - "description": "Build and run Python 3.3 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.3/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.3", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.3,python", - "tags": "hidden,builder,python", - "version": "3.3" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/python-33-centos7:latest" - }, - "name": "3.3", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Build and run Python 2.7 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/2.7/README.md.", @@ -41450,53 +35859,13 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/python-27-centos7:latest" + "name": "registry.centos.org/centos/python-27-centos7:latest" }, "name": "2.7", "referencePolicy": { "type": "Local" } }, - { - "annotations": { - "description": "Build and run Python 3.4 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.4/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.4,python", - "tags": "hidden,builder,python", - "version": "3.4" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/python-34-centos7:latest" - }, - "name": "3.4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Python 3.5 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.5/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.5,python", - "tags": "builder,python", - "version": "3.5" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/python-35-centos7:latest" - }, - "name": "3.5", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Build and run Python 3.6 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.6/README.md.", @@ -41510,7 +35879,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/python-36-centos7:latest" + "name": "registry.centos.org/centos/python-36-centos7:latest" }, "name": "3.6", "referencePolicy": { @@ -41533,7 +35902,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = "tags": [ { "annotations": { - "description": "Provides a Redis database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/tree/master/3.2/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Redis available on OpenShift, including major versions updates.", + "description": "Provides a Redis database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Redis available on OpenShift, including major versions updates.", "iconClass": "icon-redis", "openshift.io/display-name": "Redis (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -41541,7 +35910,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "ImageStreamTag", - "name": "3.2" + "name": "5" }, "name": "latest", "referencePolicy": { @@ -41550,18 +35919,18 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, { "annotations": { - "description": "Provides a Redis 3.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/tree/master/3.2/README.md.", + "description": "Provides a Redis 5 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/blob/master/5/README.md.", "iconClass": "icon-redis", - "openshift.io/display-name": "Redis 3.2", + "openshift.io/display-name": "Redis 5", "openshift.io/provider-display-name": "Red Hat, Inc.", "tags": "redis", - "version": "3.2" + "version": "5" }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/redis-32-centos7:latest" + "name": "registry.centos.org/centos/redis-5-centos7:latest" }, - "name": "3.2", + "name": "5", "referencePolicy": { "type": "Local" } @@ -41582,7 +35951,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = "tags": [ { "annotations": { - "description": "Build and run Ruby applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/tree/master/2.3/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Ruby available on OpenShift, including major versions updates.", + "description": "Build and run Ruby applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Ruby available on OpenShift, including major versions updates.", "iconClass": "icon-ruby", "openshift.io/display-name": "Ruby (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -41647,7 +36016,7 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, "from": { "kind": "ImageStreamTag", - "name": "15.0" + "name": "21.0" }, "name": "latest", "referencePolicy": { @@ -41656,180 +36025,40 @@ var _testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json = }, { "annotations": { - "description": "Build and run WildFly 8.1 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 8.1", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:8.1,jee,java", - "tags": "builder,wildfly,java", - "version": "8.1" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-81-centos7:latest" - }, - "name": "8.1", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 9.0 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 9.0", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:9.0,jee,java", - "tags": "builder,wildfly,java", - "version": "9.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-90-centos7:latest" - }, - "name": "9.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 10.0 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 10.0", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:10.0,jee,java", - "tags": "builder,wildfly,java", - "version": "10.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-100-centos7:latest" - }, - "name": "10.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 10.1 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 10.1", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:10.1,jee,java", - "tags": "builder,wildfly,java", - "version": "10.1" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-101-centos7:latest" - }, - "name": "10.1", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 11 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 11", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:11,jee,java", - "tags": "builder,wildfly,java", - "version": "11.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-110-centos7:latest" - }, - "name": "11.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 12 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 12", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:12,jee,java", - "tags": "builder,wildfly,java", - "version": "12.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-120-centos7:latest" - }, - "name": "12.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 13 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 13", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:13,jee,java", - "tags": "builder,wildfly,java", - "version": "13.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-130-centos7:latest" - }, - "name": "13.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 14 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", + "description": "Build and run WildFly 20 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 14", + "openshift.io/display-name": "WildFly 20", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:14,jee,java", + "supports": "wildfly:20,jee,java", "tags": "builder,wildfly,java", - "version": "14.0" + "version": "20.0" }, "from": { "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-140-centos7:latest" + "name": "quay.io/wildfly/wildfly-centos7:20.0" }, - "name": "14.0", + "name": "20.0", "referencePolicy": { "type": "Local" } }, { "annotations": { - "description": "Build and run WildFly 15 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", + "description": "Build and run WildFly 21 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 15", + "openshift.io/display-name": "WildFly 21", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:15,jee,java", + "supports": "wildfly:21,jee,java", "tags": "builder,wildfly,java", - "version": "15.0" + "version": "21.0" }, "from": { "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-150-centos7:latest" + "name": "quay.io/wildfly/wildfly-centos7:21.0.0" }, - "name": "15.0", + "name": "21.0", "referencePolicy": { "type": "Local" } @@ -42205,7 +36434,7 @@ items: run: v1-job spec: containers: - - image: openshift/hello-openshift + - image: k8s.gcr.io/e2e-test-images/agnhost:2.20 name: hello-container restartPolicy: Never @@ -42222,6 +36451,7 @@ items: kind: DockerImage dockerImageMetadataVersion: "1.0" dockerImageReference: registry/namespace/name + dockerImageLayers: [] kind: Image metadata: annotations: @@ -44609,183 +38839,6 @@ func testExtendedTestdataCmdTestCmdTestdataResourceBuilderYmlNoExtension() (*ass return a, nil } -var _testExtendedTestdataCmdTestCmdTestdataRolesEmptyRoleYaml = []byte(`apiVersion: v1 -kind: Role -metadata: - name: empty-role -`) - -func testExtendedTestdataCmdTestCmdTestdataRolesEmptyRoleYamlBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataRolesEmptyRoleYaml, nil -} - -func testExtendedTestdataCmdTestCmdTestdataRolesEmptyRoleYaml() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataRolesEmptyRoleYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/roles/empty-role.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataCmdTestCmdTestdataRolesPolicyClusterrolesYaml = []byte(`apiVersion: v1 -items: -- apiVersion: v1 - kind: ClusterRole - metadata: - creationTimestamp: null - name: basic-user2 - rules: - - apiGroups: null - attributeRestrictions: null - resourceNames: - - "~" - resources: - - users - verbs: - - get - - apiGroups: null - attributeRestrictions: null - resources: - - projectrequests - verbs: - - list - - apiGroups: null - attributeRestrictions: null - resources: - - clusterroles - verbs: - - get - - list - - apiGroups: null - attributeRestrictions: null - resources: - - projects - verbs: - - list - - apiGroups: - - authorization.k8s.io - attributeRestrictions: null - resources: - - selfsubjectaccessreviews - verbs: - - create -- apiVersion: v1 - groupNames: - - system:authenticated - kind: ClusterRoleBinding - metadata: - creationTimestamp: null - name: basic-users2 - roleRef: - name: basic-user2 - subjects: - - kind: SystemGroup - name: system:authenticated - userNames: null -kind: List -metadata: {} -`) - -func testExtendedTestdataCmdTestCmdTestdataRolesPolicyClusterrolesYamlBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataRolesPolicyClusterrolesYaml, nil -} - -func testExtendedTestdataCmdTestCmdTestdataRolesPolicyClusterrolesYaml() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataRolesPolicyClusterrolesYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/roles/policy-clusterroles.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataCmdTestCmdTestdataRolesPolicyRolesYaml = []byte(`kind: Template -apiVersion: v1 -metadata: - name: "policy-roles-template" -labels: - createdBy: "policy-roles-template" -parameters: - - description: "The namespace to create roles in." - name: NAMESPACE - required: true -objects: - - apiVersion: v1 - kind: Role - metadata: - creationTimestamp: null - name: basic-user - rules: - - apiGroups: null - attributeRestrictions: null - resourceNames: - - "~" - resources: - - users - verbs: - - get - - apiGroups: null - attributeRestrictions: null - resources: - - projectrequests - verbs: - - list - - apiGroups: null - attributeRestrictions: null - resources: - - clusterroles - verbs: - - get - - list - - apiGroups: null - attributeRestrictions: null - resources: - - projects - verbs: - - list - - apiGroups: - - authorization.k8s.io - attributeRestrictions: null - resources: - - selfsubjectaccessreviews - verbs: - - create - - apiVersion: v1 - groupNames: - - system:authenticated - kind: RoleBinding - metadata: - creationTimestamp: null - name: basic-users - roleRef: - name: basic-user - namespace: ${NAMESPACE} - subjects: - - kind: SystemGroup - name: system:authenticated - userNames: null -`) - -func testExtendedTestdataCmdTestCmdTestdataRolesPolicyRolesYamlBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataRolesPolicyRolesYaml, nil -} - -func testExtendedTestdataCmdTestCmdTestdataRolesPolicyRolesYaml() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataRolesPolicyRolesYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/roles/policy-roles.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - var _testExtendedTestdataCmdTestCmdTestdataRollingupdateDaemonsetYaml = []byte(`apiVersion: apps/v1 kind: DaemonSet metadata: @@ -44815,7 +38868,8 @@ spec: namespaces: [] containers: - name: kubernetes-pause - image: gcr.io/google-containers/pause:2.0 + image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest + command: ["/bin/sleep", "84600"] `) func testExtendedTestdataCmdTestCmdTestdataRollingupdateDaemonsetYamlBytes() ([]byte, error) { @@ -44942,112 +38996,6 @@ func testExtendedTestdataCmdTestCmdTestdataSimpleDeploymentYaml() (*asset, error return a, nil } -var _testExtendedTestdataCmdTestCmdTestdataStableBusyboxYaml = []byte(`kind: List -apiVersion: v1 -metadata: {} -items: - - apiVersion: v1 - dockerImageConfig: '{"architecture":"amd64","config":{"Hostname":"55cd1f8f6e5b","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["sh"],"Image":"sha256:e732471cb81a564575aad46b9510161c5945deaf18e9be3db344333d72f0b4b2","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"container":"764ef4448baa9a1ce19e4ae95f8cdd4eda7a1186c512773e56dc634dff208a59","container_config":{"Hostname":"55cd1f8f6e5b","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) - CMD [\"sh\"]"],"Image":"sha256:e732471cb81a564575aad46b9510161c5945deaf18e9be3db344333d72f0b4b2","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2016-06-23T23:23:37.198943461Z","docker_version":"1.10.3","history":[{"created":"2016-06-23T23:23:36.73131105Z","created_by":"/bin/sh - -c #(nop) ADD file:9ca60502d646bdd815bb51e612c458e2d447b597b95cf435f9673f0966d41c1a - in /"},{"created":"2016-06-23T23:23:37.198943461Z","created_by":"/bin/sh -c #(nop) - CMD [\"sh\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:8ac8bfaff55af948c796026ee867448c5b5b5d9dd3549f4006d9759b25d4a893"]}}' - dockerImageLayers: - - mediaType: application/vnd.docker.image.rootfs.diff.tar.gzip - name: sha256:8ddc19f16526912237dd8af81971d5e4dd0587907234be2b83e249518d5b673f - size: 667590 - dockerImageManifest: |- - { - "schemaVersion": 2, - "mediaType": "application/vnd.docker.distribution.manifest.v2+json", - "config": { - "mediaType": "application/octet-stream", - "size": 1459, - "digest": "sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749" - }, - "layers": [ - { - "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", - "size": 667590, - "digest": "sha256:8ddc19f16526912237dd8af81971d5e4dd0587907234be2b83e249518d5b673f" - } - ] - } - dockerImageManifestMediaType: application/vnd.docker.distribution.manifest.v2+json - dockerImageMetadata: - Architecture: amd64 - Config: - Cmd: - - sh - Env: - - PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - Hostname: 55cd1f8f6e5b - Image: sha256:e732471cb81a564575aad46b9510161c5945deaf18e9be3db344333d72f0b4b2 - Container: 764ef4448baa9a1ce19e4ae95f8cdd4eda7a1186c512773e56dc634dff208a59 - ContainerConfig: - Cmd: - - /bin/sh - - -c - - '#(nop) CMD ["sh"]' - Env: - - PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - Hostname: 55cd1f8f6e5b - Image: sha256:e732471cb81a564575aad46b9510161c5945deaf18e9be3db344333d72f0b4b2 - Created: 2016-06-23T23:23:37Z - DockerVersion: 1.10.3 - Id: sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749 - Size: 669049 - apiVersion: "1.0" - kind: DockerImage - dockerImageMetadataVersion: "1.0" - dockerImageReference: busybox@sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6 - kind: Image - metadata: - creationTimestamp: 2016-07-27T15:12:10Z - name: sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6 - resourceVersion: "504" - selfLink: /oapi/v1/images/sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6 - uid: 7d6849b4-540c-11e6-809f-525400f25e34 - - apiVersion: v1 - kind: ImageStream - metadata: - annotations: - openshift.io/image.dockerRepositoryCheck: 2016-07-27T16:08:39Z - generation: 1 - name: busybox - namespace: default - resourceVersion: "505" - selfLink: /oapi/v1/namespaces/default/imagestreams/busybox - uid: 7d687e72-540c-11e6-809f-525400f25e34 - - apiVersion: v1 - kind: ImageStreamMapping - metadata: - name: busybox - namespace: default - tag: latest - image: - apiVersion: v1 - kind: Image - metadata: - name: sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6 - dockerImageReference: busybox@sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6 -`) - -func testExtendedTestdataCmdTestCmdTestdataStableBusyboxYamlBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTestdataStableBusyboxYaml, nil -} - -func testExtendedTestdataCmdTestCmdTestdataStableBusyboxYaml() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTestdataStableBusyboxYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/testdata/stable-busybox.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - var _testExtendedTestdataCmdTestCmdTestdataStatefulsetYaml = []byte(`apiVersion: apps/v1 kind: StatefulSet metadata: @@ -45128,7 +39076,7 @@ items: spec: containers: - name: hello-openshift - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 - kind: Route apiVersion: v1 metadata: @@ -45919,7 +39867,7 @@ var _testExtendedTestdataCmdTestCmdTestdataTemplatesTemplateTypePrecisionJson = "containers": [ { "name": "test", - "image": "busybox", + "image": "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest", "imagePullPolicy": "IfNotPresent" } ], @@ -46011,7 +39959,7 @@ spec: runPolicy: Serial source: git: - uri: git://github.com/openshift/ruby-hello-world.git + uri: https://github.com/openshift/ruby-hello-world.git secrets: null type: Git strategy: @@ -46081,7 +40029,7 @@ var _testExtendedTestdataCmdTestCmdTestdataTestBuildcliJson = []byte(`{ "source": { "type": "Git", "git": { - "uri": "git://github.com/openshift/ruby-hello-world.git" + "uri": "https://github.com/openshift/ruby-hello-world.git" } }, "strategy": { @@ -46123,7 +40071,7 @@ var _testExtendedTestdataCmdTestCmdTestdataTestBuildcliJson = []byte(`{ "source": { "type": "Git", "git": { - "uri": "git://github.com/openshift/ruby-hello-world.git" + "uri": "https://github.com/openshift/ruby-hello-world.git" } }, "strategy": { @@ -46192,7 +40140,7 @@ spec: name: test-deployment spec: containers: - - image: openshift/origin-pod + - image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest imagePullPolicy: IfNotPresent name: ruby-helloworld ports: @@ -46209,7 +40157,6 @@ spec: name: vol1 triggers: - type: ConfigChange -status: {} `) func testExtendedTestdataCmdTestCmdTestdataTestDeploymentConfigYamlBytes() ([]byte, error) { @@ -46242,14 +40189,14 @@ var _testExtendedTestdataCmdTestCmdTestdataTestDockerBuildJson = []byte(`{ "git": { "uri":"https://github.com/sclorg/nodejs-ex" }, - "dockerfile": "FROM docker.io/busybox:latest" + "dockerfile": "FROM image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" }, "strategy":{ "type":"Docker", "dockerStrategy":{ "from":{ "kind":"DockerImage", - "name":"docker.io/busybox:latest" + "name":"image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" } } }, @@ -46338,6 +40285,7 @@ var _testExtendedTestdataCmdTestCmdTestdataTestImageJson = []byte(`{ "ContainerConfig": {}, "Config": {} }, + "dockerImageLayers": [], "dockerImageMetadataVersion": "1.0" } `) @@ -46415,7 +40363,7 @@ spec: deploymentconfig: test-deployment spec: containers: - - image: openshift/origin-pod + - image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest imagePullPolicy: IfNotPresent name: ruby-helloworld ports: @@ -46630,45 +40578,6 @@ func testExtendedTestdataCmdTestCmdTestdataTestStreamYaml() (*asset, error) { return a, nil } -var _testExtendedTestdataCmdTestCmdTimeoutSh = []byte(`#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT - -# Cleanup cluster resources created by this test -( - set +e - oc delete all,templates --all - exit 0 -) &>/dev/null - - -os::test::junit::declare_suite_start "cmd/request-timeout" -# This test validates the global request-timeout option -os::cmd::expect_success 'oc create deploymentconfig testdc --image=busybox' -os::cmd::expect_success_and_text 'oc get dc/testdc -w -v=5 --request-timeout=1s 2>&1' 'request canceled' -os::cmd::expect_success_and_text 'oc get dc/testdc --request-timeout=1s' 'testdc' -os::cmd::expect_success_and_text 'oc get dc/testdc --request-timeout=1' 'testdc' -os::cmd::expect_success_and_text 'oc get pods --watch -v=5 --request-timeout=1s 2>&1' 'request canceled' - -echo "request-timeout: ok" -os::test::junit::declare_suite_end -`) - -func testExtendedTestdataCmdTestCmdTimeoutShBytes() ([]byte, error) { - return _testExtendedTestdataCmdTestCmdTimeoutSh, nil -} - -func testExtendedTestdataCmdTestCmdTimeoutSh() (*asset, error) { - bytes, err := testExtendedTestdataCmdTestCmdTimeoutShBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/cmd/test/cmd/timeout.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - var _testExtendedTestdataCmdTestCmdTriggersSh = []byte(`#!/bin/bash source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" trap os::test::junit::reconcile_output EXIT @@ -46764,7 +40673,7 @@ os::test::junit::declare_suite_end os::test::junit::declare_suite_start "cmd/triggers/deploymentconfigs" ## Deployment configs -os::cmd::expect_success 'oc create deploymentconfig testdc --image=busybox' +os::cmd::expect_success 'oc create deploymentconfig testdc --image=image-registry.openshift-image-registry.svc:5000/openshift/tools:latest' # error conditions os::cmd::expect_failure_and_text 'oc set triggers dc/testdc --from-github' 'deployment configs do not support GitHub web hooks' @@ -46792,7 +40701,7 @@ os::test::junit::declare_suite_end os::test::junit::declare_suite_start "cmd/triggers/annotations" ## Deployment -os::cmd::expect_success 'oc create deployment test --image=busybox' +os::cmd::expect_success 'oc create deployment test --image=image-registry.openshift-image-registry.svc:5000/openshift/tools:latest' # error conditions os::cmd::expect_failure_and_text 'oc set triggers deploy/test --from-github' 'does not support GitHub web hooks' @@ -46800,7 +40709,7 @@ os::cmd::expect_failure_and_text 'oc set triggers deploy/test --from-webhook' 'd os::cmd::expect_failure_and_text 'oc set triggers deploy/test --from-gitlab' 'does not support GitLab web hooks' os::cmd::expect_failure_and_text 'oc set triggers deploy/test --from-bitbucket' 'does not support Bitbucket web hooks' os::cmd::expect_failure_and_text 'oc set triggers deploy/test --from-image=test:latest' 'you must specify --containers when setting --from-image' -os::cmd::expect_failure_and_text 'oc set triggers deploy/test --from-image=test:latest --containers=other' 'not all container names exist: other \(accepts: busybox\)' +os::cmd::expect_failure_and_text 'oc set triggers deploy/test --from-image=test:latest --containers=other' 'not all container names exist: other \(accepts: tools\)' # print os::cmd::expect_success_and_text 'oc set triggers deploy/test' 'config.*true' os::cmd::expect_success_and_not_text 'oc set triggers deploy/test' 'webhook|github|gitlab|bitbucket' @@ -46813,8 +40722,8 @@ os::cmd::expect_success_and_text 'oc set triggers deploy/test' 'config.*false' # auto os::cmd::expect_success_and_text 'oc set triggers deploy/test --auto' 'updated' os::cmd::expect_success_and_text 'oc set triggers deploy/test' 'config.*true' -os::cmd::expect_success_and_text 'oc set triggers deploy/test --from-image=ruby-hello-world:latest -c busybox' 'updated' -os::cmd::expect_success_and_text 'oc set triggers deploy/test' 'image.*ruby-hello-world:latest \(busybox\).*true' +os::cmd::expect_success_and_text 'oc set triggers deploy/test --from-image=ruby-hello-world:latest -c tools' 'updated' +os::cmd::expect_success_and_text 'oc set triggers deploy/test' 'image.*ruby-hello-world:latest \(tools\).*true' os::test::junit::declare_suite_end os::test::junit::declare_suite_end @@ -47005,7 +40914,7 @@ items: jnlp - openshift/jenkins-slave-maven-centos7 + image-registry.openshift-image-registry.svc:5000/openshift/jenkins-agent-maven:latest false false /tmp @@ -47049,487 +40958,6 @@ func testExtendedTestdataConfigMapJenkinsSlavePodsYaml() (*asset, error) { return a, nil } -var _testExtendedTestdataCsiAwsEbsInstallTemplateYaml = []byte(`# Installation of AWS EBS CSI driver into OpenShift. -# Source: https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/e727882eae38614ec3246b243255e536aeef5a0f/deploy/kubernetes/manifest.yaml -# Tailored for OCP: -# - Run controllers with hostNetwork: true to access AWS instance metadata (https://bugzilla.redhat.com/show_bug.cgi?id=1734600) -# - Removed livenessprobe for this -# - Scaled controllers to 1 -# - Run in kube-system and use aws-creds secrets there - -# Controller Service -apiVersion: v1 -kind: ServiceAccount -metadata: - name: ebs-csi-controller-sa - namespace: kube-system - ---- - -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: ebs-external-provisioner-role -rules: - - apiGroups: [""] - resources: ["persistentvolumes"] - verbs: ["get", "list", "watch", "create", "delete"] - - apiGroups: [""] - resources: ["persistentvolumeclaims"] - verbs: ["get", "list", "watch", "update"] - - apiGroups: ["storage.k8s.io"] - resources: ["storageclasses"] - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["events"] - verbs: ["get", "list", "watch", "create", "update", "patch"] - - apiGroups: ["storage.k8s.io"] - resources: ["csinodes"] - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["nodes"] - verbs: ["get", "list", "watch"] - ---- - -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: ebs-csi-provisioner-binding -subjects: - - kind: ServiceAccount - name: ebs-csi-controller-sa - namespace: kube-system -roleRef: - kind: ClusterRole - name: ebs-external-provisioner-role - apiGroup: rbac.authorization.k8s.io - ---- - -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: ebs-external-attacher-role -rules: - - apiGroups: [""] - resources: ["persistentvolumes"] - verbs: ["get", "list", "watch", "update", "patch"] - - apiGroups: [""] - resources: ["nodes"] - verbs: ["get", "list", "watch"] - - apiGroups: ["csi.storage.k8s.io"] - resources: ["csinodeinfos"] - verbs: ["get", "list", "watch"] - - apiGroups: ["storage.k8s.io"] - resources: ["volumeattachments"] - verbs: ["get", "list", "watch", "update", "patch"] - ---- - -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: ebs-csi-attacher-binding -subjects: - - kind: ServiceAccount - name: ebs-csi-controller-sa - namespace: kube-system -roleRef: - kind: ClusterRole - name: ebs-external-attacher-role - apiGroup: rbac.authorization.k8s.io - ---- -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: ebs-external-resizer-role -rules: - - apiGroups: [""] - resources: ["persistentvolumes"] - verbs: ["get", "list", "watch", "update", "patch"] - - apiGroups: [""] - resources: ["persistentvolumeclaims"] - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["persistentvolumeclaims/status"] - verbs: ["update", "patch"] - - apiGroups: ["storage.k8s.io"] - resources: ["storageclasses"] - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["events"] - verbs: ["list", "watch", "create", "update", "patch"] - ---- - -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: ebs-csi-resizer-binding -subjects: - - kind: ServiceAccount - name: ebs-csi-controller-sa - namespace: kube-system -roleRef: - kind: ClusterRole - name: ebs-external-resizer-role - apiGroup: rbac.authorization.k8s.io - ---- - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: ebs-external-snapshotter-role -rules: -- apiGroups: [""] - resources: ["persistentvolumes"] - verbs: ["get", "list", "watch"] -- apiGroups: [""] - resources: ["persistentvolumeclaims"] - verbs: ["get", "list", "watch"] -- apiGroups: ["storage.k8s.io"] - resources: ["storageclasses"] - verbs: ["get", "list", "watch"] -- apiGroups: [""] - resources: ["events"] - verbs: ["list", "watch", "create", "update", "patch"] -- apiGroups: [""] - resources: ["secrets"] - verbs: ["get", "list"] -- apiGroups: ["snapshot.storage.k8s.io"] - resources: ["volumesnapshotclasses"] - verbs: ["get", "list", "watch"] -- apiGroups: ["snapshot.storage.k8s.io"] - resources: ["volumesnapshotcontents"] - verbs: ["create", "get", "list", "watch", "update", "delete"] -- apiGroups: ["snapshot.storage.k8s.io"] - resources: ["volumesnapshotcontents/status"] - verbs: ["update"] -- apiGroups: ["snapshot.storage.k8s.io"] - resources: ["volumesnapshots"] - verbs: ["get", "list", "watch", "update"] -- apiGroups: ["apiextensions.k8s.io"] - resources: ["customresourcedefinitions"] - verbs: ["create", "list", "watch", "delete"] -- apiGroups: ["coordination.k8s.io"] - resources: ["leases"] - verbs: ["get", "watch", "list", "delete", "update", "create"] - ---- - -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: ebs-csi-snapshotter-binding -subjects: - - kind: ServiceAccount - name: ebs-csi-controller-sa - namespace: kube-system -roleRef: - kind: ClusterRole - name: ebs-external-snapshotter-role - apiGroup: rbac.authorization.k8s.io - ---- - -kind: StatefulSet -apiVersion: apps/v1 -metadata: - name: ebs-csi-controller - namespace: kube-system -spec: - selector: - matchLabels: - app: ebs-csi-controller - serviceName: ebs-csi-controller - replicas: 1 - template: - metadata: - labels: - app: ebs-csi-controller - spec: - hostNetwork: true - serviceAccount: ebs-csi-controller-sa - priorityClassName: system-cluster-critical - tolerations: - - key: CriticalAddonsOnly - operator: Exists - containers: - - name: ebs-plugin - image: amazon/aws-ebs-csi-driver:latest - args: - - --endpoint=$(CSI_ENDPOINT) - - --logtostderr - - --v=5 - env: - - name: CSI_ENDPOINT - value: unix:///var/lib/csi/sockets/pluginproxy/csi.sock - - name: AWS_ACCESS_KEY_ID - valueFrom: - secretKeyRef: - name: aws-creds - key: aws_access_key_id - optional: true - - name: AWS_SECRET_ACCESS_KEY - valueFrom: - secretKeyRef: - name: aws-creds - key: aws_secret_access_key - optional: true - ports: - - name: healthz - containerPort: 19808 - protocol: TCP - volumeMounts: - - name: socket-dir - mountPath: /var/lib/csi/sockets/pluginproxy/ - - name: csi-provisioner - image: {{.ProvisionerImage}} - args: - - --provisioner=ebs.csi.aws.com - - --csi-address=$(ADDRESS) - - --v=5 - - --feature-gates=Topology=true - env: - - name: ADDRESS - value: /var/lib/csi/sockets/pluginproxy/csi.sock - volumeMounts: - - name: socket-dir - mountPath: /var/lib/csi/sockets/pluginproxy/ - - name: csi-attacher - image: {{.AttacherImage}} - args: - - --csi-address=$(ADDRESS) - - --v=5 - env: - - name: ADDRESS - value: /var/lib/csi/sockets/pluginproxy/csi.sock - volumeMounts: - - name: socket-dir - mountPath: /var/lib/csi/sockets/pluginproxy/ - - name: csi-resizer - image: {{.ResizerImage}} - args: - - --csi-address=$(ADDRESS) - - --v=5 - env: - - name: ADDRESS - value: /var/lib/csi/sockets/pluginproxy/csi.sock - volumeMounts: - - name: socket-dir - mountPath: /var/lib/csi/sockets/pluginproxy/ - - name: csi-snapshotter - image: {{.SnapshotterImage}} - args: - - --csi-address=$(ADDRESS) - - --v=5 - env: - - name: ADDRESS - value: /var/lib/csi/sockets/pluginproxy/csi.sock - volumeMounts: - - mountPath: /var/lib/csi/sockets/pluginproxy/ - name: socket-dir - volumes: - - name: socket-dir - emptyDir: {} - ---- - -# Node Service -kind: DaemonSet -apiVersion: apps/v1 -metadata: - name: ebs-csi-node - namespace: kube-system -spec: - selector: - matchLabels: - app: ebs-csi-node - template: - metadata: - labels: - app: ebs-csi-node - spec: - hostNetwork: true - priorityClassName: system-node-critical - tolerations: - - key: CriticalAddonsOnly - operator: Exists - containers: - - name: ebs-plugin - securityContext: - privileged: true - image: amazon/aws-ebs-csi-driver:latest - args: - - --endpoint=$(CSI_ENDPOINT) - - --logtostderr - - --v=5 - env: - - name: CSI_ENDPOINT - value: unix:/csi/csi.sock - volumeMounts: - - name: kubelet-dir - mountPath: /var/lib/kubelet - mountPropagation: "Bidirectional" - - name: plugin-dir - mountPath: /csi - - name: device-dir - mountPath: /dev - ports: - - name: healthz - containerPort: 9808 - protocol: TCP - livenessProbe: - httpGet: - path: /healthz - port: healthz - initialDelaySeconds: 10 - timeoutSeconds: 3 - periodSeconds: 10 - failureThreshold: 5 - - name: node-driver-registrar - securityContext: - privileged: true - image: {{.NodeDriverRegistrarImage}} - args: - - --csi-address=$(ADDRESS) - - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH) - - --v=5 - lifecycle: - preStop: - exec: - command: ["/bin/sh", "-c", "rm -rf /registration/ebs.csi.aws.com-reg.sock /csi/csi.sock"] - env: - - name: ADDRESS - value: /csi/csi.sock - - name: DRIVER_REG_SOCK_PATH - value: /var/lib/kubelet/plugins/ebs.csi.aws.com/csi.sock - volumeMounts: - - name: plugin-dir - mountPath: /csi - - name: registration-dir - mountPath: /registration - - name: liveness-probe - image: {{.LivenessProbeImage}} - args: - - --csi-address=/csi/csi.sock - - --probe-timeout=3s - volumeMounts: - - name: plugin-dir - mountPath: /csi - volumes: - - name: kubelet-dir - hostPath: - path: /var/lib/kubelet - type: Directory - - name: plugin-dir - hostPath: - path: /var/lib/kubelet/plugins/ebs.csi.aws.com/ - type: DirectoryOrCreate - - name: registration-dir - hostPath: - path: /var/lib/kubelet/plugins_registry/ - type: Directory - - name: device-dir - hostPath: - path: /dev - type: Directory - ---- - -apiVersion: storage.k8s.io/v1beta1 -kind: CSIDriver -metadata: - name: ebs.csi.aws.com -spec: - attachRequired: true - podInfoOnMount: false -`) - -func testExtendedTestdataCsiAwsEbsInstallTemplateYamlBytes() ([]byte, error) { - return _testExtendedTestdataCsiAwsEbsInstallTemplateYaml, nil -} - -func testExtendedTestdataCsiAwsEbsInstallTemplateYaml() (*asset, error) { - bytes, err := testExtendedTestdataCsiAwsEbsInstallTemplateYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/csi/aws-ebs/install-template.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataCsiAwsEbsManifestYaml = []byte(`# Test manifest for https://github.com/kubernetes/kubernetes/tree/master/test/e2e/storage/external -ShortName: ebs -StorageClass: - FromFile: storageclass.yaml -SnapshotClass: - FromName: true -DriverInfo: - Name: ebs.csi.aws.com - SupportedSizeRange: - Min: 1Gi - Max: 16Ti - SupportedFsType: - xfs: {} - ext4: {} - SupportedMountOption: - dirsync: {} - TopologyKeys: ["topology.ebs.csi.aws.com/zone"] - Capabilities: - persistence: true - fsGroup: true - block: true - exec: true - volumeLimits: false - controllerExpansion: true - nodeExpansion: true - snapshotDataSource: true -`) - -func testExtendedTestdataCsiAwsEbsManifestYamlBytes() ([]byte, error) { - return _testExtendedTestdataCsiAwsEbsManifestYaml, nil -} - -func testExtendedTestdataCsiAwsEbsManifestYaml() (*asset, error) { - bytes, err := testExtendedTestdataCsiAwsEbsManifestYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/csi/aws-ebs/manifest.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataCsiAwsEbsStorageclassYaml = []byte(`kind: StorageClass -apiVersion: storage.k8s.io/v1 -metadata: - name: ebs.csi.aws.com -provisioner: ebs.csi.aws.com -volumeBindingMode: WaitForFirstConsumer -`) - -func testExtendedTestdataCsiAwsEbsStorageclassYamlBytes() ([]byte, error) { - return _testExtendedTestdataCsiAwsEbsStorageclassYaml, nil -} - -func testExtendedTestdataCsiAwsEbsStorageclassYaml() (*asset, error) { - bytes, err := testExtendedTestdataCsiAwsEbsStorageclassYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/csi/aws-ebs/storageclass.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - var _testExtendedTestdataCustomSecretBuilderDockerfile = []byte(`FROM openshift/origin-custom-docker-builder # Override the default build script ADD build.sh /tmp/build.sh @@ -47651,7 +41079,7 @@ spec: spec: terminationGracePeriodSeconds: 0 containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: myapp command: @@ -47758,7 +41186,7 @@ spec: name: history-limit spec: containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: myapp command: @@ -47801,7 +41229,7 @@ spec: spec: terminationGracePeriodSeconds: 0 containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: myapp command: @@ -47833,13 +41261,13 @@ spec: - name: pullthrough from: kind: DockerImage - name: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + name: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" referencePolicy: type: Local - name: direct from: kind: DockerImage - name: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + name: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" referencePolicy: type: Source `) @@ -47937,7 +41365,7 @@ spec: spec: terminationGracePeriodSeconds: 0 containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: myapp command: @@ -47977,7 +41405,7 @@ spec: name: deployment-simple spec: containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent command: - /bin/sleep @@ -48081,7 +41509,7 @@ spec: name: deployment-simple spec: containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" command: [ "/bin/bash", "-c", "sleep infinity" ] imagePullPolicy: IfNotPresent name: myapp @@ -48127,7 +41555,7 @@ spec: name: hook spec: containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" command: - /bin/sleep - infinity @@ -48175,7 +41603,7 @@ spec: name: generation-test spec: containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: myapp command: @@ -48273,7 +41701,7 @@ spec: name: paused spec: containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: myapp command: @@ -48315,7 +41743,7 @@ spec: - command: - /bin/sleep - "infinity" - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: never-ready readinessProbe: @@ -48365,9 +41793,11 @@ spec: labels: name: tag-images spec: + terminationGracePeriodSeconds: 1 containers: - - image: openshift/origin-pod + - image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest imagePullPolicy: IfNotPresent + command: ["/bin/sh", "-c", "sleep 300"] name: sample-name ports: - containerPort: 8080 @@ -48416,7 +41846,7 @@ spec: name: brokendeployment spec: containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: myapp command: @@ -48469,7 +41899,7 @@ spec: spec: terminationGracePeriodSeconds: 0 containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: myapp command: @@ -48495,525 +41925,6 @@ func testExtendedTestdataDeploymentsTestDeploymentTestYaml() (*asset, error) { return a, nil } -var _testExtendedTestdataDisasterRecoveryRestoreEtcdSh = []byte(`#!/bin/bash -set -euo pipefail - -if [ -z "${BASTION_HOST}" ]; then exit 1; fi -if [ -z "${MASTERHOSTS}" ]; then exit 1; fi -if [ -z "${KUBE_SSH_KEY_PATH}" ]; then exit 1; fi - -MASTERS=(${MASTERHOSTS}) -FIRST_MASTER="${MASTERS[0]}" - -function retry() { - local ATTEMPTS="${1}" - local rc=0 - shift - for i in $(seq 0 $((ATTEMPTS-1))); do - echo "--> ${@}" - set +e - "${@}" - rc="$?" - set -e - echo "--> exit code: $rc" - test "${rc}" = 0 && break - sleep 10 - done - return "${rc}" -} - -function bastion_ssh() { - retry 60 \ - ssh -o LogLevel=error -o ConnectionAttempts=100 -o ConnectTimeout=30 -o StrictHostKeyChecking=no \ - -o ProxyCommand="ssh -A -o StrictHostKeyChecking=no -o LogLevel=error -o ServerAliveInterval=30 -o ConnectionAttempts=100 -o ConnectTimeout=30 -W %h:%p core@${BASTION_HOST} 2>/dev/null" \ - $@ -} - -echo "Distribute snapshot across all masters" -for master in "${MASTERS[@]}" -do - scp -o StrictHostKeyChecking=no -o ProxyCommand="ssh -A -o StrictHostKeyChecking=no -o ServerAliveInterval=30 -W %h:%p core@${BASTION_HOST}" ${KUBE_SSH_KEY_PATH} "core@${master}":/home/core/.ssh/id_rsa - bastion_ssh "core@${master}" "sudo -i chmod 0600 /home/core/.ssh/id_rsa" - bastion_ssh "core@${FIRST_MASTER}" "scp -o StrictHostKeyChecking=no /tmp/snapshot.db core@${master}:/tmp/snapshot.db" -done - -echo "Collect etcd names" -for master in "${MASTERS[@]}" -do - bastion_ssh "core@${master}" 'echo "etcd-member-$(hostname -f)" > /tmp/etcd_name && source /run/etcd/environment && echo "https://${ETCD_DNS_NAME}:2380" > /tmp/etcd_uri' - bastion_ssh "core@${FIRST_MASTER}" "mkdir -p /tmp/etcd/${master} && scp -o StrictHostKeyChecking=no core@${master}:/tmp/etcd_name /tmp/etcd/${master}/etcd_name && scp -o StrictHostKeyChecking=no core@${master}:/tmp/etcd_uri /tmp/etcd/${master}/etcd_uri" - bastion_ssh "core@${FIRST_MASTER}" "cat /tmp/etcd/${master}/etcd_name" - bastion_ssh "core@${FIRST_MASTER}" "cat /tmp/etcd/${master}/etcd_uri" -done - -echo "Assemble etcd connection string" -bastion_ssh "core@${FIRST_MASTER}" 'rm -rf /tmp/etcd/connstring && mapfile -t MASTERS < <(ls /tmp/etcd) && echo ${MASTERS[@]} && for master in "${MASTERS[@]}"; do echo -n "$(cat /tmp/etcd/${master}/etcd_name)=$(cat /tmp/etcd/${master}/etcd_uri)," >> /tmp/etcd/connstring; done && sed -i '"'$ s/.$//'"' /tmp/etcd/connstring' - -echo "Restore etcd cluster from snapshot" -for master in "${MASTERS[@]}" -do - echo "Running /usr/local/bin/etcd-snapshot-restore.sh on ${master}" - bastion_ssh "core@${FIRST_MASTER}" "scp -o StrictHostKeyChecking=no /tmp/etcd/connstring core@${master}:/tmp/etcd_connstring" - bastion_ssh "core@${master}" 'sudo -i /bin/bash -x /usr/local/bin/etcd-snapshot-restore.sh /tmp/snapshot.db $(cat /tmp/etcd_connstring)' -done -`) - -func testExtendedTestdataDisasterRecoveryRestoreEtcdShBytes() ([]byte, error) { - return _testExtendedTestdataDisasterRecoveryRestoreEtcdSh, nil -} - -func testExtendedTestdataDisasterRecoveryRestoreEtcdSh() (*asset, error) { - bytes, err := testExtendedTestdataDisasterRecoveryRestoreEtcdShBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/disaster-recovery/restore-etcd.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataDisasterRecoveryRollbackAYaml = []byte(`apiVersion: machineconfiguration.openshift.io/v1 -kind: MachineConfig -metadata: - labels: - machineconfiguration.openshift.io/role: master - name: 99-rollback-test -spec: - config: - ignition: - version: 2.2.0 - storage: - files: - - contents: - source: data:,A - filesystem: root - mode: 420 - path: /etc/rollback-test -`) - -func testExtendedTestdataDisasterRecoveryRollbackAYamlBytes() ([]byte, error) { - return _testExtendedTestdataDisasterRecoveryRollbackAYaml, nil -} - -func testExtendedTestdataDisasterRecoveryRollbackAYaml() (*asset, error) { - bytes, err := testExtendedTestdataDisasterRecoveryRollbackAYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/disaster-recovery/rollback-A.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataDisasterRecoveryRollbackBYaml = []byte(`apiVersion: machineconfiguration.openshift.io/v1 -kind: MachineConfig -metadata: - labels: - machineconfiguration.openshift.io/role: master - name: 99-rollback-test -spec: - config: - ignition: - version: 2.2.0 - storage: - files: - - contents: - source: data:,B - filesystem: root - mode: 420 - path: /etc/rollback-test -`) - -func testExtendedTestdataDisasterRecoveryRollbackBYamlBytes() ([]byte, error) { - return _testExtendedTestdataDisasterRecoveryRollbackBYaml, nil -} - -func testExtendedTestdataDisasterRecoveryRollbackBYaml() (*asset, error) { - bytes, err := testExtendedTestdataDisasterRecoveryRollbackBYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/disaster-recovery/rollback-B.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataDisasterRecoverySshBastionClusterroleYaml = []byte(`apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: ssh-bastion -rules: -- apiGroups: - - "machineconfiguration.openshift.io" - resources: - - "machineconfigs" - verbs: - - get -- apiGroups: - - "" - resources: - - "nodes" - verbs: - - list - - get -`) - -func testExtendedTestdataDisasterRecoverySshBastionClusterroleYamlBytes() ([]byte, error) { - return _testExtendedTestdataDisasterRecoverySshBastionClusterroleYaml, nil -} - -func testExtendedTestdataDisasterRecoverySshBastionClusterroleYaml() (*asset, error) { - bytes, err := testExtendedTestdataDisasterRecoverySshBastionClusterroleYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/disaster-recovery/ssh-bastion/clusterrole.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataDisasterRecoverySshBastionClusterrolebindingYaml = []byte(`apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: - openshift.io/description: Allows ssh-pod to read nodes and machineconfigs - name: ssh-bastion -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: ssh-bastion -subjects: -- apiGroup: rbac.authorization.k8s.io - kind: User - name: system:serviceaccount:ssh-bastion:ssh-bastion -`) - -func testExtendedTestdataDisasterRecoverySshBastionClusterrolebindingYamlBytes() ([]byte, error) { - return _testExtendedTestdataDisasterRecoverySshBastionClusterrolebindingYaml, nil -} - -func testExtendedTestdataDisasterRecoverySshBastionClusterrolebindingYaml() (*asset, error) { - bytes, err := testExtendedTestdataDisasterRecoverySshBastionClusterrolebindingYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/disaster-recovery/ssh-bastion/clusterrolebinding.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataDisasterRecoverySshBastionDeploymentYaml = []byte(`apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - run: ssh-bastion - name: ssh-bastion - namespace: ssh-bastion -spec: - replicas: 1 - selector: - matchLabels: - run: ssh-bastion - template: - metadata: - labels: - run: ssh-bastion - spec: - serviceAccountName: "ssh-bastion" - containers: - - image: quay.io/eparis/ssh:latest - imagePullPolicy: Always - name: ssh-bastion - ports: - - containerPort: 22 - name: ssh - protocol: TCP - volumeMounts: - - name: ssh-host-keys - mountPath: "/etc/ssh/" - readOnly: true - securityContext: - privileged: true - volumes: - - name: ssh-host-keys - secret: - secretName: ssh-host-keys - items: - - key: ssh_host_rsa_key - path: ssh_host_rsa_key - mode: 256 - - key: ssh_host_ecdsa_key - path: ssh_host_ecdsa_key - mode: 256 - - key: ssh_host_ed25519_key - path: ssh_host_ed25519_key - mode: 256 - - key: sshd_config - path: sshd_config - restartPolicy: Always -`) - -func testExtendedTestdataDisasterRecoverySshBastionDeploymentYamlBytes() ([]byte, error) { - return _testExtendedTestdataDisasterRecoverySshBastionDeploymentYaml, nil -} - -func testExtendedTestdataDisasterRecoverySshBastionDeploymentYaml() (*asset, error) { - bytes, err := testExtendedTestdataDisasterRecoverySshBastionDeploymentYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/disaster-recovery/ssh-bastion/deployment.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataDisasterRecoverySshBastionNamespaceYaml = []byte(`apiVersion: v1 -kind: Namespace -metadata: - name: ssh-bastion - labels: - openshift.io/run-level: "0" - -`) - -func testExtendedTestdataDisasterRecoverySshBastionNamespaceYamlBytes() ([]byte, error) { - return _testExtendedTestdataDisasterRecoverySshBastionNamespaceYaml, nil -} - -func testExtendedTestdataDisasterRecoverySshBastionNamespaceYaml() (*asset, error) { - bytes, err := testExtendedTestdataDisasterRecoverySshBastionNamespaceYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/disaster-recovery/ssh-bastion/namespace.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataDisasterRecoverySshBastionRoleYaml = []byte(`apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: ssh-bastion - namespace: ssh-bastion -rules: -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use - resourceNames: - - privileged -`) - -func testExtendedTestdataDisasterRecoverySshBastionRoleYamlBytes() ([]byte, error) { - return _testExtendedTestdataDisasterRecoverySshBastionRoleYaml, nil -} - -func testExtendedTestdataDisasterRecoverySshBastionRoleYaml() (*asset, error) { - bytes, err := testExtendedTestdataDisasterRecoverySshBastionRoleYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/disaster-recovery/ssh-bastion/role.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataDisasterRecoverySshBastionRolebindingYaml = []byte(`apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - annotations: - openshift.io/description: Allows ssh-pod to run as root - name: ssh-bastion - namespace: ssh-bastion -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: ssh-bastion -subjects: -- apiGroup: rbac.authorization.k8s.io - kind: User - name: system:serviceaccount:ssh-bastion:ssh-bastion -`) - -func testExtendedTestdataDisasterRecoverySshBastionRolebindingYamlBytes() ([]byte, error) { - return _testExtendedTestdataDisasterRecoverySshBastionRolebindingYaml, nil -} - -func testExtendedTestdataDisasterRecoverySshBastionRolebindingYaml() (*asset, error) { - bytes, err := testExtendedTestdataDisasterRecoverySshBastionRolebindingYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/disaster-recovery/ssh-bastion/rolebinding.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataDisasterRecoverySshBastionServiceYaml = []byte(`apiVersion: v1 -kind: Service -metadata: - labels: - run: ssh-bastion - name: ssh-bastion - namespace: ssh-bastion -spec: - externalTrafficPolicy: Local - ports: - - name: ssh - port: 22 - protocol: TCP - targetPort: ssh - selector: - run: ssh-bastion - type: LoadBalancer -`) - -func testExtendedTestdataDisasterRecoverySshBastionServiceYamlBytes() ([]byte, error) { - return _testExtendedTestdataDisasterRecoverySshBastionServiceYaml, nil -} - -func testExtendedTestdataDisasterRecoverySshBastionServiceYaml() (*asset, error) { - bytes, err := testExtendedTestdataDisasterRecoverySshBastionServiceYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/disaster-recovery/ssh-bastion/service.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataDisasterRecoverySshBastionServiceaccountYaml = []byte(`apiVersion: v1 -kind: ServiceAccount -metadata: - name: ssh-bastion - namespace: ssh-bastion -`) - -func testExtendedTestdataDisasterRecoverySshBastionServiceaccountYamlBytes() ([]byte, error) { - return _testExtendedTestdataDisasterRecoverySshBastionServiceaccountYaml, nil -} - -func testExtendedTestdataDisasterRecoverySshBastionServiceaccountYaml() (*asset, error) { - bytes, err := testExtendedTestdataDisasterRecoverySshBastionServiceaccountYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/disaster-recovery/ssh-bastion/serviceaccount.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataDisasterRecoverySshBastionSshd_config = []byte(`HostKey /etc/ssh/ssh_host_rsa_key -HostKey /etc/ssh/ssh_host_ecdsa_key -HostKey /etc/ssh/ssh_host_ed25519_key -SyslogFacility AUTHPRIV -PermitRootLogin no -AuthorizedKeysFile /home/core/.ssh/authorized_keys -PasswordAuthentication no -ChallengeResponseAuthentication no -GSSAPIAuthentication yes -GSSAPICleanupCredentials no -UsePAM yes -X11Forwarding yes -PrintMotd no -AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES -AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT -AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE -AcceptEnv XMODIFIERS -Subsystem sftp /usr/libexec/openssh/sftp-server -`) - -func testExtendedTestdataDisasterRecoverySshBastionSshd_configBytes() ([]byte, error) { - return _testExtendedTestdataDisasterRecoverySshBastionSshd_config, nil -} - -func testExtendedTestdataDisasterRecoverySshBastionSshd_config() (*asset, error) { - bytes, err := testExtendedTestdataDisasterRecoverySshBastionSshd_configBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/disaster-recovery/ssh-bastion/sshd_config", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataDisasterRecoveryUpdate_route_53Py = []byte(`import boto3 -import os -import sys -from time import sleep - -if len(sys.argv) < 4: - print("Usage: ./update_route_53.py ") - sys.exit(1) - -attempts = 10 -pause = 10 - -domain = sys.argv[1] -record = sys.argv[2] -ip = sys.argv[3] -print("record: %s" % record) -print("ip: %s" % ip) - -client = boto3.client('route53') -r = client.list_hosted_zones_by_name(DNSName=domain, MaxItems="1") -zone_id = r['HostedZones'][0]['Id'].split('/')[-1] - -response = client.change_resource_record_sets( - HostedZoneId=zone_id, - ChangeBatch= { - 'Comment': 'add %s -> %s' % (record, ip), - 'Changes': [ - { - 'Action': 'UPSERT', - 'ResourceRecordSet': { - 'Name': record, - 'Type': 'A', - 'TTL': 60, - 'ResourceRecords': [{'Value': ip}] - } - }] -}) -for i in range(attempts): - print('response: %s' % response) - changeID = response['ChangeInfo']['Id'] - if response['ChangeInfo']['Status'] == "INSYNC": - print('insync found, response: %s' % response) - break - print('waiting for response to complete') - sleep(pause) - response = client.get_change(Id=changeID) -`) - -func testExtendedTestdataDisasterRecoveryUpdate_route_53PyBytes() ([]byte, error) { - return _testExtendedTestdataDisasterRecoveryUpdate_route_53Py, nil -} - -func testExtendedTestdataDisasterRecoveryUpdate_route_53Py() (*asset, error) { - bytes, err := testExtendedTestdataDisasterRecoveryUpdate_route_53PyBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/disaster-recovery/update_route_53.py", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - var _testExtendedTestdataForcepullTestJson = []byte(`{ "kind": "List", "apiVersion": "v1", @@ -50512,6 +43423,7 @@ var _testExtendedTestdataImageTestImageJson = []byte(`{ "ContainerConfig": {}, "Config": {} }, + "dockerImageLayers": [], "dockerImageMetadataVersion": "1.0" } `) @@ -50956,8 +43868,9 @@ metadata: spec: tags: - from: - kind: DockerImage - name: docker.io/openshift/jenkins-slave-maven-centos7:latest + kind: ImageStreamTag + name: jenkins-agent-maven:latest + namespace: openshift name: base - from: kind: ImageStreamTag @@ -50987,8 +43900,9 @@ metadata: spec: tags: - from: - kind: DockerImage - name: quay.io/openshift/origin-jenkins-agent-maven:latest + kind: ImageStreamTag + name: jenkins-agent-maven:latest + namespace: openshift name: base - annotations: role: jenkins-slave @@ -52324,7 +45238,7 @@ spec: spec: containers: - name: simplev1 - image: docker.io/busybox + image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest command: ["/bin/sh", "-c", "exit 0"] restartPolicy: Never `) @@ -54697,6 +47611,224 @@ func testExtendedTestdataLdapGroupsyncRfc2307Whitelist_openshiftTxt() (*asset, e return a, nil } +var _testExtendedTestdataLdapGroupsyncSh = []byte(`#!/bin/bash +# +# This scripts starts the OpenShift server with a default configuration. +# The OpenShift Docker registry and router are installed. +# It will run all tests that are imported into test/extended. +source "/usr/hack/lib/init.sh" +os::util::environment::setup_time_vars +os::build::setup_env + +export KUBECONFIG="${ADMIN_KUBECONFIG}" +LDAP_SERVICE_IP="${LDAP_SERVICE}" + +function cleanup() { + return_code=$? + os::test::junit::generate_report + os::cleanup::all + os::util::describe_return_code "${return_code}" + exit "${return_code}" +} +trap "cleanup" EXIT + +function compare_and_cleanup() { + validation_file=$1 + actual_file=actual-${validation_file} + rm -f ${WORKINGDIR}/${actual_file} + oc get groups --no-headers | awk '{print $1}' | sort | xargs -I{} oc get --export group {} -o yaml >> ${WORKINGDIR}/${actual_file} + os::util::sed '/sync-time/d' ${WORKINGDIR}/${actual_file} + diff ${validation_file} ${WORKINGDIR}/${actual_file} + oc delete groups --all + echo -e "\tSUCCESS" +} + +os::log::info "Running extended tests" + +schema=('rfc2307' 'ad' 'augmented-ad') + +for (( i=0; i<${#schema[@]}; i++ )); do + current_schema=${schema[$i]} + os::log::info "Testing schema: ${current_schema}" + os::test::junit::declare_suite_start "extended/ldap-groups/${current_schema}" + + WORKINGDIR=${BASETMPDIR}/${current_schema} + mkdir ${WORKINGDIR} + + os::log::info "working dir ${WORKINGDIR}" + # create a temp copy of the test files + cp /tmp/ldap/${current_schema}/* ${WORKINGDIR} + pushd ${WORKINGDIR} > /dev/null + + # load OpenShift and LDAP group UIDs, needed for literal whitelists + # use awk instead of sed for compatibility (see os::util::sed) + group1_ldapuid=$(awk 'NR == 1 {print $0}' ldapgroupuids.txt) + group2_ldapuid=$(awk 'NR == 2 {print $0}' ldapgroupuids.txt) + group3_ldapuid=$(awk 'NR == 3 {print $0}' ldapgroupuids.txt) + + group1_osuid=$(awk 'NR == 1 {print $0}' osgroupuids.txt) + group2_osuid=$(awk 'NR == 2 {print $0}' osgroupuids.txt) + group3_osuid=$(awk 'NR == 3 {print $0}' osgroupuids.txt) + + # update sync-configs and validation files with the LDAP server's IP + config_files=sync-config*.yaml + validation_files=valid*.yaml + for config in ${config_files} ${validation_files} + do + os::util::sed "s/LDAP_SERVICE_IP/${LDAP_SERVICE_IP}/g" ${config} + os::util::sed "s@LDAP_CA@${LDAP_CA}@g" ${config} + done + + echo -e "\tTEST: Sync all LDAP groups from LDAP server" + oc adm groups sync --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_all_ldap_sync.yaml + + + # WHITELISTS + echo -e "\tTEST: Sync subset of LDAP groups from LDAP server using whitelist file" + oc adm groups sync --whitelist=whitelist_ldap.txt --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_whitelist_sync.yaml + + echo -e "\tTEST: Sync subset of LDAP groups from LDAP server using literal whitelist" + oc adm groups sync ${group1_ldapuid} --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_whitelist_sync.yaml + + echo -e "\tTEST: Sync subset of LDAP groups from LDAP server using union of literal whitelist and whitelist file" + oc adm groups sync ${group2_ldapuid} --whitelist=whitelist_ldap.txt --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_whitelist_union_sync.yaml + + echo -e "\tTEST: Sync subset of OpenShift groups from LDAP server using whitelist file" + oc adm groups sync ${group1_ldapuid} --sync-config=sync-config.yaml --confirm + oc patch group ${group1_osuid} -p 'users: []' + oc adm groups sync --type=openshift --whitelist=whitelist_openshift.txt --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_whitelist_sync.yaml + + echo -e "\tTEST: Sync subset of OpenShift groups from LDAP server using literal whitelist" + # sync group from LDAP + oc adm groups sync ${group1_ldapuid} --sync-config=sync-config.yaml --confirm + oc patch group ${group1_osuid} -p 'users: []' + oc adm groups sync --type=openshift ${group1_osuid} --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_whitelist_sync.yaml + + echo -e "\tTEST: Sync subset of OpenShift groups from LDAP server using union of literal whitelist and whitelist file" + # sync groups from LDAP + oc adm groups sync ${group1_ldapuid} ${group2_ldapuid} --sync-config=sync-config.yaml --confirm + oc patch group ${group1_osuid} -p 'users: []' + oc patch group ${group2_osuid} -p 'users: []' + oc adm groups sync --type=openshift group/${group2_osuid} --whitelist=whitelist_openshift.txt --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_whitelist_union_sync.yaml + + + # BLACKLISTS + echo -e "\tTEST: Sync subset of LDAP groups from LDAP server using whitelist and blacklist file" + # oc adm groups sync --whitelist=ldapgroupuids.txt --blacklist=blacklist_ldap.txt --blacklist-group="${group1_ldapuid}" --sync-config=sync-config.yaml --confirm + oc adm groups sync --whitelist=ldapgroupuids.txt --blacklist=blacklist_ldap.txt --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_all_blacklist_sync.yaml + + echo -e "\tTEST: Sync subset of LDAP groups from LDAP server using blacklist" + # oc adm groups sync --blacklist=blacklist_ldap.txt --blacklist-group=${group1_ldapuid} --sync-config=sync-config.yaml --confirm + oc adm groups sync --blacklist=blacklist_ldap.txt --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_all_blacklist_sync.yaml + + echo -e "\tTEST: Sync subset of OpenShift groups from LDAP server using whitelist and blacklist file" + oc adm groups sync --sync-config=sync-config.yaml --confirm + oc get group -o name --no-headers | xargs -n 1 oc patch -p 'users: []' + # oc adm groups sync --type=openshift --whitelist=osgroupuids.txt --blacklist=blacklist_openshift.txt --blacklist-group=${group1_osuid} --sync-config=sync-config.yaml --confirm + oc adm groups sync --type=openshift --whitelist=osgroupuids.txt --blacklist=blacklist_openshift.txt --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_all_openshift_blacklist_sync.yaml + + + # MAPPINGS + echo -e "\tTEST: Sync all LDAP groups from LDAP server using a user-defined mapping" + oc adm groups sync --sync-config=sync-config-user-defined.yaml --confirm + compare_and_cleanup valid_all_ldap_sync_user_defined.yaml + + echo -e "\tTEST: Sync all LDAP groups from LDAP server using a partially user-defined mapping" + oc adm groups sync --sync-config=sync-config-partially-user-defined.yaml --confirm + compare_and_cleanup valid_all_ldap_sync_partially_user_defined.yaml + + echo -e "\tTEST: Sync based on OpenShift groups respecting OpenShift mappings" + oc adm groups sync --sync-config=sync-config-user-defined.yaml --confirm + oc get group -o name --no-headers | xargs -n 1 oc patch -p 'users: []' + oc adm groups sync --type=openshift --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_all_ldap_sync_user_defined.yaml + + echo -e "\tTEST: Sync all LDAP groups from LDAP server using DN as attribute whenever possible" + oc adm groups sync --sync-config=sync-config-dn-everywhere.yaml --confirm + compare_and_cleanup valid_all_ldap_sync_dn_everywhere.yaml + + echo -e "\tTEST: Sync based on OpenShift groups respecting OpenShift mappings and whitelist file" + os::cmd::expect_success_and_text 'oc adm groups sync --whitelist=ldapgroupuids.txt --sync-config=sync-config-user-defined.yaml --confirm' 'group/' + os::cmd::expect_success_and_text 'oc get group -o jsonpath={.items[*].metadata.name}' 'firstgroup secondgroup thirdgroup' + os::cmd::expect_success_and_text 'oc adm groups sync --type=openshift --whitelist=ldapgroupuids.txt --sync-config=sync-config-user-defined.yaml --confirm' 'group/' + os::cmd::expect_success_and_text 'oc get group -o jsonpath={.items[*].metadata.name}' 'firstgroup secondgroup thirdgroup' + os::cmd::expect_success_and_text 'oc delete groups --all' 'deleted' + os::cmd::expect_success_and_text 'oc get group -o jsonpath={.items[*].metadata.name} | wc -l' '0' + + # PRUNING + echo -e "\tTEST: Sync all LDAP groups from LDAP server, change LDAP UID, then prune OpenShift groups" + oc adm groups sync --sync-config=sync-config.yaml --confirm + oc patch group ${group2_osuid} -p "{\"metadata\":{\"annotations\":{\"openshift.io/ldap.uid\":\"cn=garbage,${group2_ldapuid}\"}}}" + oc adm groups prune --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_all_ldap_sync_prune.yaml + + echo -e "\tTEST: Sync all LDAP groups from LDAP server using whitelist file, then prune OpenShift groups using the same whitelist file" + os::cmd::expect_success_and_text 'oc adm groups sync --whitelist=ldapgroupuids.txt --sync-config=sync-config-user-defined.yaml --confirm' 'group/' + os::cmd::expect_success_and_text 'oc get group -o jsonpath={.items[*].metadata.name}' 'firstgroup secondgroup thirdgroup' + os::cmd::expect_success_and_text 'oc adm groups prune --whitelist=ldapgroupuids.txt --sync-config=sync-config-user-defined.yaml --confirm | wc -l' '0' + os::cmd::expect_success_and_text 'oc get group -o jsonpath={.items[*].metadata.name}' 'firstgroup secondgroup thirdgroup' + os::cmd::expect_success_and_text 'oc patch group secondgroup -p "{\"metadata\":{\"annotations\":{\"openshift.io/ldap.uid\":\"cn=garbage\"}}}"' 'group.user.openshift.io/secondgroup patched' + os::cmd::expect_success_and_text 'oc adm groups prune --whitelist=ldapgroupuids.txt --sync-config=sync-config-user-defined.yaml --confirm' 'group/secondgroup' + os::cmd::expect_success_and_text 'oc get group -o jsonpath={.items[*].metadata.name}' 'firstgroup thirdgroup' + os::cmd::expect_success_and_text 'oc delete groups --all' 'deleted' + os::cmd::expect_success_and_text 'oc get group -o jsonpath={.items[*].metadata.name} | wc -l' '0' + + + # PAGING + echo -e "\tTEST: Sync all LDAP groups from LDAP server using paged queries" + oc adm groups sync --sync-config=sync-config-paging.yaml --confirm + compare_and_cleanup valid_all_ldap_sync.yaml + + + os::test::junit::declare_suite_end + popd > /dev/null +done + +# special test for RFC2307 +pushd ${BASETMPDIR}/rfc2307 > /dev/null +echo -e "\tTEST: Sync groups from LDAP server, tolerating errors" +oc adm groups sync --sync-config=sync-config-tolerating.yaml --confirm 2>"${LOG_DIR}/tolerated-output.txt" +grep 'For group "cn=group1,ou=groups,ou=incomplete\-rfc2307,dc=example,dc=com", ignoring member "cn=INVALID,ou=people,ou=rfc2307,dc=example,dc=com"' "${LOG_DIR}/tolerated-output.txt" +grep 'For group "cn=group2,ou=groups,ou=incomplete\-rfc2307,dc=example,dc=com", ignoring member "cn=OUTOFSCOPE,ou=people,ou=OUTOFSCOPE,dc=example,dc=com"' "${LOG_DIR}/tolerated-output.txt" +grep 'For group "cn=group3,ou=groups,ou=incomplete\-rfc2307,dc=example,dc=com", ignoring member "cn=INVALID,ou=people,ou=rfc2307,dc=example,dc=com"' "${LOG_DIR}/tolerated-output.txt" +grep 'For group "cn=group3,ou=groups,ou=incomplete\-rfc2307,dc=example,dc=com", ignoring member "cn=OUTOFSCOPE,ou=people,ou=OUTOFSCOPE,dc=example,dc=com"' "${LOG_DIR}/tolerated-output.txt" +compare_and_cleanup valid_all_ldap_sync_tolerating.yaml +popd > /dev/null + +# special test for augmented-ad +pushd ${BASETMPDIR}/augmented-ad > /dev/null +echo -e "\tTEST: Sync all LDAP groups from LDAP server, remove LDAP group metadata entry, then prune OpenShift groups" +oc adm groups sync --sync-config=sync-config.yaml --confirm +ldapdelete -x -h $LDAP_SERVICE_IP -p 389 -D cn=Manager,dc=example,dc=com -w admin "${group1_ldapuid}" +oc adm groups prune --sync-config=sync-config.yaml --confirm +compare_and_cleanup valid_all_ldap_sync_delete_prune.yaml +popd > /dev/null`) + +func testExtendedTestdataLdapGroupsyncShBytes() ([]byte, error) { + return _testExtendedTestdataLdapGroupsyncSh, nil +} + +func testExtendedTestdataLdapGroupsyncSh() (*asset, error) { + bytes, err := testExtendedTestdataLdapGroupsyncShBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/extended/testdata/ldap/groupsync.sh", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + var _testExtendedTestdataLdapLdapserverConfigCmYaml = []byte(`--- apiVersion: v1 kind: ConfigMap @@ -55346,7 +48478,7 @@ var _testExtendedTestdataLong_namesFixtureJson = []byte(`{ "source": { "type": "Git", "git": { - "uri": "git://github.com/openshift/ruby-hello-world.git" + "uri": "https://github.com/openshift/ruby-hello-world.git" } }, "strategy": { @@ -55375,7 +48507,7 @@ var _testExtendedTestdataLong_namesFixtureJson = []byte(`{ "source": { "type": "Git", "git": { - "uri": "git://github.com/openshift/ruby-hello-world.git" + "uri": "https://github.com/openshift/ruby-hello-world.git" } }, "strategy": { @@ -56262,15 +49394,27 @@ func testExtendedTestdataRolesEmptyRoleYaml() (*asset, error) { return a, nil } -var _testExtendedTestdataRolesPolicyClusterrolesYaml = []byte(`apiVersion: v1 -items: -- apiVersion: v1 +var _testExtendedTestdataRolesPolicyClusterrolesYaml = []byte(`kind: Template +apiVersion: v1 +metadata: + name: "policy-roles-template" +labels: + createdBy: "policy-roles-template" +parameters: + - description: "The name for the cluster role." + name: ROLE_NAME + required: true + - description: "The name for the cluster role binding." + name: BINDING_NAME + required: true +objects: +- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - creationTimestamp: null - name: basic-user2 + name: ${ROLE_NAME} rules: - - apiGroups: null + - apiGroups: + - "" attributeRestrictions: null resourceNames: - "~" @@ -56278,20 +49422,23 @@ items: - users verbs: - get - - apiGroups: null + - apiGroups: + - project.openshift.io attributeRestrictions: null resources: - projectrequests verbs: - list - - apiGroups: null + - apiGroups: + - rbac.authorization.k8s.io attributeRestrictions: null resources: - clusterroles verbs: - get - list - - apiGroups: null + - apiGroups: + - project.openshift.io attributeRestrictions: null resources: - projects @@ -56304,21 +49451,18 @@ items: - selfsubjectaccessreviews verbs: - create -- apiVersion: v1 - groupNames: - - system:authenticated +- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - creationTimestamp: null - name: basic-users2 + name: ${BINDING_NAME} roleRef: - name: basic-user2 + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: ${ROLE_NAME} subjects: - - kind: SystemGroup + - apiGroup: rbac.authorization.k8s.io + kind: Group name: system:authenticated - userNames: null -kind: List -metadata: {} `) func testExtendedTestdataRolesPolicyClusterrolesYamlBytes() ([]byte, error) { @@ -56347,13 +49491,13 @@ parameters: name: NAMESPACE required: true objects: - - apiVersion: v1 + - apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - creationTimestamp: null name: basic-user rules: - - apiGroups: null + - apiGroups: + - "" attributeRestrictions: null resourceNames: - "~" @@ -56361,20 +49505,23 @@ objects: - users verbs: - get - - apiGroups: null + - apiGroups: + - project.openshift.io attributeRestrictions: null resources: - projectrequests verbs: - list - - apiGroups: null + - apiGroups: + - rbac.authorization.k8s.io attributeRestrictions: null resources: - clusterroles verbs: - get - list - - apiGroups: null + - apiGroups: + - project.openshift.io attributeRestrictions: null resources: - projects @@ -56387,18 +49534,20 @@ objects: - selfsubjectaccessreviews verbs: - create - - apiVersion: v1 + - apiVersion: rbac.authorization.k8s.io/v1 groupNames: - system:authenticated kind: RoleBinding metadata: - creationTimestamp: null + namespace: ${NAMESPACE} name: basic-users roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role name: basic-user - namespace: ${NAMESPACE} subjects: - - kind: SystemGroup + - apiGroup: rbac.authorization.k8s.io + kind: Group name: system:authenticated userNames: null `) @@ -56499,7 +49648,8 @@ items: terminationGracePeriodSeconds: 1 containers: - name: test - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] ports: - containerPort: 8080 name: http @@ -56516,7 +49666,8 @@ items: terminationGracePeriodSeconds: 1 containers: - name: test - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] ports: - containerPort: 8080 name: http @@ -56550,7 +49701,7 @@ items: app: serving-cert spec: containers: - - image: nginx:1.15.3 + - image: docker.io/library/nginx:1.15-alpine name: serve command: - /usr/sbin/nginx @@ -56748,8 +49899,8 @@ objects: terminationGracePeriodSeconds: 1 containers: - name: test - image: openshift/hello-openshift - # image: openshift/deployment-example:v1 + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] ports: - containerPort: 8080 name: http @@ -56910,7 +50061,8 @@ objects: terminationGracePeriodSeconds: 1 containers: - name: test - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] ports: - containerPort: 8080 name: http @@ -56924,7 +50076,7 @@ objects: app: secure-endpoint spec: containers: - - image: nginx:1.15.3 + - image: docker.io/library/nginx:1.15-alpine name: serve command: - /usr/sbin/nginx @@ -57765,7 +50917,7 @@ items: deploymentconfig: router-http-echo spec: containers: - - image: openshift/origin-node + - image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest name: router-http-echo command: - /usr/bin/socat @@ -58143,8 +51295,8 @@ items: - name: weightedendpoints2 kind: Service weight: 50 - ports: - - targetPort: 8080 + port: + targetPort: 8080 # a route that has multiple services but all weights are zero - apiVersion: v1 @@ -58164,364 +51316,8 @@ items: - name: weightedendpoints2 kind: Service weight: 0 - ports: - - targetPort: 8080 - -# two services that can be routed to -- apiVersion: v1 - kind: Service - metadata: - name: weightedendpoints1 - labels: - test: router - spec: - selector: - test: weightedrouter1 - endpoints: weightedrouter1 - ports: - - port: 8080 -- apiVersion: v1 - kind: Service - metadata: - name: weightedendpoints2 - labels: - test: router - spec: - selector: - test: weightedrouter2 - endpoints: weightedrouter2 - ports: - - port: 8080 -# two pods that serves a response -- apiVersion: v1 - kind: Pod - metadata: - name: endpoint-1 - labels: - test: weightedrouter1 - endpoints: weightedrouter1 - spec: - terminationGracePeriodSeconds: 1 - containers: - - name: test - image: openshift/hello-openshift - ports: - - containerPort: 8080 - name: http - - containerPort: 100 - protocol: UDP -- apiVersion: v1 - kind: Pod - metadata: - name: endpoint-2 - labels: - test: weightedrouter2 - endpoints: weightedrouter2 - spec: - terminationGracePeriodSeconds: 1 - containers: - - name: test - image: openshift/hello-openshift - ports: - - containerPort: 8080 - name: http - - containerPort: 100 - protocol: UDP -`) - -func testExtendedTestdataRouterRouterMetricsYamlBytes() ([]byte, error) { - return _testExtendedTestdataRouterRouterMetricsYaml, nil -} - -func testExtendedTestdataRouterRouterMetricsYaml() (*asset, error) { - bytes, err := testExtendedTestdataRouterRouterMetricsYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/router/router-metrics.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataRouterRouterOverrideDomainsYaml = []byte(`apiVersion: v1 -kind: Template -parameters: -- name: IMAGE - value: openshift/origin-haproxy-router:latest -objects: - -# a router that overrides domains -- apiVersion: v1 - kind: Pod - metadata: - name: router-override-domains - labels: - test: router-override-domains - spec: - terminationGracePeriodSeconds: 1 - containers: - - name: router - image: ${IMAGE} - imagePullPolicy: IfNotPresent - env: - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - args: - - "--name=test-override-domains" - - "--namespace=$(POD_NAMESPACE)" - - "-v=4" - - "--override-domains=null.ptr,void.str" - - "--hostname-template=${name}-${namespace}.apps.veto.test" - - "--stats-port=1936" - - "--metrics-type=haproxy" - hostNetwork: false - ports: - - containerPort: 80 - - containerPort: 443 - - containerPort: 1936 - name: stats - protocol: TCP - readinessProbe: - initialDelaySeconds: 10 - httpGet: - path: /healthz/ready - port: 1936 - serviceAccountName: default -`) - -func testExtendedTestdataRouterRouterOverrideDomainsYamlBytes() ([]byte, error) { - return _testExtendedTestdataRouterRouterOverrideDomainsYaml, nil -} - -func testExtendedTestdataRouterRouterOverrideDomainsYaml() (*asset, error) { - bytes, err := testExtendedTestdataRouterRouterOverrideDomainsYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/router/router-override-domains.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataRouterRouterOverrideYaml = []byte(`apiVersion: v1 -kind: Template -parameters: -- name: IMAGE - value: openshift/origin-haproxy-router:latest -objects: - -# a router that overrides host -- apiVersion: v1 - kind: Pod - metadata: - name: router-override - labels: - test: router-override - spec: - terminationGracePeriodSeconds: 1 - containers: - - name: router - image: ${IMAGE} - imagePullPolicy: IfNotPresent - env: - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - args: - - "--name=test-override" - - "--namespace=$(POD_NAMESPACE)" - - "-v=4" - - "--override-hostname" - - "--hostname-template=${name}-${namespace}.myapps.mycompany.com" - - "--stats-port=1936" - - "--metrics-type=haproxy" - hostNetwork: false - ports: - - containerPort: 80 - - containerPort: 443 - - containerPort: 1936 - name: stats - protocol: TCP - readinessProbe: - initialDelaySeconds: 10 - httpGet: - path: /healthz/ready - port: 1936 - serviceAccountName: default -`) - -func testExtendedTestdataRouterRouterOverrideYamlBytes() ([]byte, error) { - return _testExtendedTestdataRouterRouterOverrideYaml, nil -} - -func testExtendedTestdataRouterRouterOverrideYaml() (*asset, error) { - bytes, err := testExtendedTestdataRouterRouterOverrideYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/router/router-override.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataRouterRouterScopedYaml = []byte(`apiVersion: v1 -kind: Template -parameters: -- name: IMAGE - value: openshift/origin-haproxy-router:latest -- name: ROUTER_NAME - value: "test-scoped" -- name: UPDATE_STATUS - value: "true" -objects: -# a scoped router -- apiVersion: v1 - kind: Pod - metadata: - name: router-scoped - labels: - test: router-scoped - spec: - terminationGracePeriodSeconds: 1 - containers: - - name: router - image: ${IMAGE} - imagePullPolicy: IfNotPresent - env: - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - args: - - "--name=${ROUTER_NAME}" - - "--namespace=$(POD_NAMESPACE)" - - "--update-status=${UPDATE_STATUS}" - - "-v=4" - - "--labels=select=first" - - "--stats-port=1936" - - "--metrics-type=haproxy" - hostNetwork: false - ports: - - containerPort: 80 - - containerPort: 443 - - containerPort: 1936 - name: stats - protocol: TCP - readinessProbe: - initialDelaySeconds: 10 - httpGet: - path: /healthz/ready - port: 1936 - serviceAccountName: default -`) - -func testExtendedTestdataRouterRouterScopedYamlBytes() ([]byte, error) { - return _testExtendedTestdataRouterRouterScopedYaml, nil -} - -func testExtendedTestdataRouterRouterScopedYaml() (*asset, error) { - bytes, err := testExtendedTestdataRouterRouterScopedYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/router/router-scoped.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataRouterWeightedRouterYaml = []byte(`apiVersion: v1 -kind: Template -parameters: -- name: IMAGE - value: openshift/origin-haproxy-router:latest -objects: -# a weighted router -- apiVersion: v1 - kind: Pod - metadata: - name: weighted-router - labels: - test: weighted-router - spec: - terminationGracePeriodSeconds: 1 - containers: - - name: router - image: ${IMAGE} - imagePullPolicy: IfNotPresent - env: - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - args: ["--namespace=$(POD_NAMESPACE)", "-v=4", "--labels=select=weighted", "--stats-password=password", "--stats-port=1936", "--stats-user=admin"] - hostNetwork: false - ports: - - containerPort: 80 - - containerPort: 443 - - containerPort: 1936 - name: stats - protocol: TCP - serviceAccountName: default - -# ensure the router can access routes and endpoints -- apiVersion: v1 - kind: RoleBinding - metadata: - name: system-router - subjects: - - kind: ServiceAccount - name: default - roleRef: - name: system:router - -# a route that has multiple weighted services that it points to -- apiVersion: v1 - kind: Route - metadata: - name: weightedroute - labels: - test: router - select: weighted - spec: - host: weighted.example.com - to: - name: weightedendpoints1 - kind: Service - weight: 90 - alternateBackends: - - name: weightedendpoints2 - kind: Service - weight: 10 - ports: - - targetPort: 8080 - -# a route that has multiple services but all weights are zero -- apiVersion: v1 - kind: Route - metadata: - name: zeroweightroute - labels: - test: router - select: weighted - spec: - host: zeroweight.example.com - to: - name: weightedendpoints1 - kind: Service - weight: 0 - alternateBackends: - - name: weightedendpoints2 - kind: Service - weight: 0 - ports: - - targetPort: 8080 + port: + targetPort: 8080 # two services that can be routed to - apiVersion: v1 @@ -58560,7 +51356,8 @@ objects: terminationGracePeriodSeconds: 1 containers: - name: test - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] ports: - containerPort: 8080 name: http @@ -58577,24 +51374,8 @@ objects: terminationGracePeriodSeconds: 1 containers: - name: test - image: openshift/hello-openshift - ports: - - containerPort: 8080 - name: http - - containerPort: 100 - protocol: UDP -- apiVersion: v1 - kind: Pod - metadata: - name: endpoint-3 - labels: - test: weightedrouter2 - endpoints: weightedrouter2 - spec: - terminationGracePeriodSeconds: 1 - containers: - - name: test - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] ports: - containerPort: 8080 name: http @@ -58602,2488 +51383,2229 @@ objects: protocol: UDP `) -func testExtendedTestdataRouterWeightedRouterYamlBytes() ([]byte, error) { - return _testExtendedTestdataRouterWeightedRouterYaml, nil -} - -func testExtendedTestdataRouterWeightedRouterYaml() (*asset, error) { - bytes, err := testExtendedTestdataRouterWeightedRouterYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/router/weighted-router.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataRun_policyParallelBcYaml = []byte(`--- - kind: "List" - apiVersion: "v1" - metadata: {} - items: - - - kind: "ImageStream" - apiVersion: "v1" - metadata: - name: "origin-ruby-sample" - creationTimestamp: null - spec: {} - status: - dockerImageRepository: "" - - - kind: "BuildConfig" - apiVersion: "v1" - metadata: - name: "sample-parallel-build" - spec: - runPolicy: "Parallel" - triggers: - - - type: "imageChange" - imageChange: {} - source: - type: "Git" - git: - uri: "https://github.com/openshift/ruby-hello-world.git" - strategy: - type: "Source" - sourceStrategy: - from: - kind: "DockerImage" - name: "image-registry.openshift-image-registry.svc:5000/openshift/ruby:2.7" - resources: {} - status: - lastVersion: 0 -`) - -func testExtendedTestdataRun_policyParallelBcYamlBytes() ([]byte, error) { - return _testExtendedTestdataRun_policyParallelBcYaml, nil -} - -func testExtendedTestdataRun_policyParallelBcYaml() (*asset, error) { - bytes, err := testExtendedTestdataRun_policyParallelBcYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/run_policy/parallel-bc.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataRun_policySerialBcYaml = []byte(`--- - kind: "List" - apiVersion: "v1" - metadata: {} - items: - - - kind: "BuildConfig" - apiVersion: "v1" - metadata: - name: "sample-serial-build" - spec: - runPolicy: "Serial" - triggers: - - - type: "imageChange" - imageChange: {} - source: - type: "Git" - git: - uri: "https://github.com/openshift/ruby-hello-world.git" - strategy: - type: "Source" - sourceStrategy: - from: - kind: "DockerImage" - name: "image-registry.openshift-image-registry.svc:5000/openshift/ruby:2.7" - - - kind: "BuildConfig" - apiVersion: "v1" - metadata: - name: "sample-serial-build-fail" - spec: - runPolicy: "Serial" - triggers: - - - type: "imageChange" - imageChange: {} - source: - type: "Git" - git: - uri: "https://github.com/openshift/invalidrepo.git" - strategy: - type: "Source" - sourceStrategy: - from: - kind: "DockerImage" - name: "image-registry.openshift-image-registry.svc:5000/openshift/ruby:2.7" -`) - -func testExtendedTestdataRun_policySerialBcYamlBytes() ([]byte, error) { - return _testExtendedTestdataRun_policySerialBcYaml, nil -} - -func testExtendedTestdataRun_policySerialBcYaml() (*asset, error) { - bytes, err := testExtendedTestdataRun_policySerialBcYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/run_policy/serial-bc.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataRun_policySerialLatestOnlyBcYaml = []byte(`--- - kind: "List" - apiVersion: "v1" - metadata: {} - items: - - - kind: "BuildConfig" - apiVersion: "v1" - metadata: - name: "sample-serial-latest-only-build" - spec: - runPolicy: "SerialLatestOnly" - triggers: - - - type: "imageChange" - imageChange: {} - source: - type: "Git" - git: - uri: "https://github.com/openshift/ruby-hello-world.git" - strategy: - type: "Source" - sourceStrategy: - from: - kind: "DockerImage" - name: "image-registry.openshift-image-registry.svc:5000/openshift/ruby:2.7" - resources: {} - status: - lastVersion: 0 -`) - -func testExtendedTestdataRun_policySerialLatestOnlyBcYamlBytes() ([]byte, error) { - return _testExtendedTestdataRun_policySerialLatestOnlyBcYaml, nil -} - -func testExtendedTestdataRun_policySerialLatestOnlyBcYaml() (*asset, error) { - bytes, err := testExtendedTestdataRun_policySerialLatestOnlyBcYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/run_policy/serial-latest-only-bc.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataS2iDropcapsRootAccessBuildYaml = []byte(`apiVersion: v1 -items: -- apiVersion: v1 - kind: BuildConfig - metadata: - labels: - build: root-access-build - name: root-access-build - spec: - output: - to: - kind: ImageStreamTag - name: root-access-build:latest - postCommit: {} - resources: {} - source: - git: - uri: https://github.com/openshift/ruby-hello-world.git - secrets: [] - type: Git - strategy: - sourceStrategy: - from: - kind: ImageStreamTag - name: rootable-ruby:latest - type: Source - triggers: [] -- apiVersion: v1 - kind: ImageStream - metadata: - labels: - build: root-access-build - name: root-access-build - spec: {} -kind: List -metadata: {} -`) - -func testExtendedTestdataS2iDropcapsRootAccessBuildYamlBytes() ([]byte, error) { - return _testExtendedTestdataS2iDropcapsRootAccessBuildYaml, nil -} - -func testExtendedTestdataS2iDropcapsRootAccessBuildYaml() (*asset, error) { - bytes, err := testExtendedTestdataS2iDropcapsRootAccessBuildYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/s2i-dropcaps/root-access-build.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataS2iDropcapsRootableRubyDockerfile = []byte(`FROM centos/ruby-27-centos7:latest -USER root -RUN rm -f /usr/bin/ls -RUN echo "root:redhat" | chpasswd -USER 1001 -COPY ./adduser /usr/libexec/s2i/ -COPY ./assemble /usr/libexec/s2i/ -`) - -func testExtendedTestdataS2iDropcapsRootableRubyDockerfileBytes() ([]byte, error) { - return _testExtendedTestdataS2iDropcapsRootableRubyDockerfile, nil -} - -func testExtendedTestdataS2iDropcapsRootableRubyDockerfile() (*asset, error) { - bytes, err := testExtendedTestdataS2iDropcapsRootableRubyDockerfileBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/s2i-dropcaps/rootable-ruby/Dockerfile", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataS2iDropcapsRootableRubyAdduser = []byte(`#!/usr/bin/expect - -spawn su -expect "Password:" { - send "redhat\r" -} - -expect "#" { - send "adduser mytestuser\r" -} - -expect "#" { - send "exit\r" -} - -expect "$" {} -`) - -func testExtendedTestdataS2iDropcapsRootableRubyAdduserBytes() ([]byte, error) { - return _testExtendedTestdataS2iDropcapsRootableRubyAdduser, nil -} - -func testExtendedTestdataS2iDropcapsRootableRubyAdduser() (*asset, error) { - bytes, err := testExtendedTestdataS2iDropcapsRootableRubyAdduserBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/s2i-dropcaps/rootable-ruby/adduser", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataS2iDropcapsRootableRubyAssemble = []byte(`#!/bin/bash -set -e -/usr/libexec/s2i/adduser -cat /etc/passwd -grep "mytestuser" /etc/passwd -`) - -func testExtendedTestdataS2iDropcapsRootableRubyAssembleBytes() ([]byte, error) { - return _testExtendedTestdataS2iDropcapsRootableRubyAssemble, nil -} - -func testExtendedTestdataS2iDropcapsRootableRubyAssemble() (*asset, error) { - bytes, err := testExtendedTestdataS2iDropcapsRootableRubyAssembleBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/s2i-dropcaps/rootable-ruby/assemble", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataSampleImageStreamJson = []byte(`{ - "kind": "ImageStream", - "apiVersion": "v1", - "metadata": { - "name": "samplerepository", - "creationTimestamp": null - }, - "spec": {}, - "status": { - "dockerImageRepository": "" - } -}`) - -func testExtendedTestdataSampleImageStreamJsonBytes() ([]byte, error) { - return _testExtendedTestdataSampleImageStreamJson, nil +func testExtendedTestdataRouterRouterMetricsYamlBytes() ([]byte, error) { + return _testExtendedTestdataRouterRouterMetricsYaml, nil } -func testExtendedTestdataSampleImageStreamJson() (*asset, error) { - bytes, err := testExtendedTestdataSampleImageStreamJsonBytes() +func testExtendedTestdataRouterRouterMetricsYaml() (*asset, error) { + bytes, err := testExtendedTestdataRouterRouterMetricsYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/sample-image-stream.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/router/router-metrics.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataSamplepipelineWithenvsYaml = []byte(`apiVersion: v1 +var _testExtendedTestdataRouterRouterOverrideDomainsYaml = []byte(`apiVersion: v1 kind: Template -labels: - template: application-template-sample-pipeline -metadata: - annotations: - iconClass: icon-jenkins - tags: instant-app,jenkins - name: jenkins-pipeline-example parameters: +- name: IMAGE + value: openshift/origin-haproxy-router:latest objects: -- apiVersion: v1 - kind: BuildConfig - metadata: - labels: - name: sample-pipeline-withenvs - name: sample-pipeline-withenvs - spec: - strategy: - jenkinsPipelineStrategy: - env: - - name: FOO1 - value: BAR1 - jenkinsfile: |- - node() { - echo "FOO1 is ${env.FOO1}" - echo "FOO2 is ${env.FOO2}" - } - type: JenkinsPipeline -`) - -func testExtendedTestdataSamplepipelineWithenvsYamlBytes() ([]byte, error) { - return _testExtendedTestdataSamplepipelineWithenvsYaml, nil -} - -func testExtendedTestdataSamplepipelineWithenvsYaml() (*asset, error) { - bytes, err := testExtendedTestdataSamplepipelineWithenvsYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/samplepipeline-withenvs.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataServiceServingCertNginxServingCertConf = []byte(`server { - listen 443; - - ssl on; - ssl_certificate /etc/serving-cert/tls.crt; - ssl_certificate_key /etc/serving-cert/tls.key; - server_name localhost; - - #charset koi8-r; - #access_log /var/log/nginx/log/host.access.log main; - - location / { - root /usr/share/nginx/html; - index index.html index.htm; - } - - #error_page 404 /404.html; - - # redirect server error pages to the static page /50x.html - # - error_page 500 502 503 504 /50x.html; - location = /50x.html { - root /usr/share/nginx/html; - } - - # proxy the PHP scripts to Apache listening on 127.0.0.1:80 - # - #location ~ \.php$ { - # proxy_pass http://127.0.0.1; - #} - - # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 - # - #location ~ \.php$ { - # root html; - # fastcgi_pass 127.0.0.1:9000; - # fastcgi_index index.php; - # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; - # include fastcgi_params; - #} - - # deny access to .htaccess files, if Apache's document root - # concurs with nginx's one - # - #location ~ /\.ht { - # deny all; - #} -} -`) - -func testExtendedTestdataServiceServingCertNginxServingCertConfBytes() ([]byte, error) { - return _testExtendedTestdataServiceServingCertNginxServingCertConf, nil -} - -func testExtendedTestdataServiceServingCertNginxServingCertConf() (*asset, error) { - bytes, err := testExtendedTestdataServiceServingCertNginxServingCertConfBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/extended/testdata/service-serving-cert/nginx-serving-cert.conf", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testExtendedTestdataSignerBuildconfigYaml = []byte(`kind: List -apiVersion: v1 -items: - -- kind: ImageStream - apiVersion: v1 - metadata: - name: signer -- kind: BuildConfig - apiVersion: v1 +# a router that overrides domains +- apiVersion: v1 + kind: Pod metadata: - name: signer - spec: - triggers: - - type: ConfigChange - source: - dockerfile: | - FROM quay.io/openshift/origin-control-plane:latest - RUN yum-config-manager --disable origin-local-release ||: - RUN yum install -y skopeo && \ - yum clean all && mkdir -p gnupg && chmod -R 0777 /var/lib/origin - RUN echo $'%echo Generating openpgp key ...\n\ - Key-Type: DSA \n\ - Key-Length: 1024 \n\ - Subkey-Type: ELG-E \n\ - Subkey-Length: 1024 \n\ - Name-Real: Joe Tester \n\ - Name-Comment: with stupid passphrase \n\ - Name-Email: joe@foo.bar \n\ - Expire-Date: 0 \n\ - Creation-Date: 2017-01-01 \n\ - %commit \n\ - %echo done \n' >> dummy_key.conf - strategy: - type: Docker - dockerStrategy: - from: - kind: DockerImage - name: quay.io/openshift/origin-control-plane:latest - output: - to: - kind: ImageStreamTag - name: signer:latest + name: router-override-domains + labels: + test: router-override-domains + spec: + terminationGracePeriodSeconds: 1 + containers: + - name: router + image: ${IMAGE} + imagePullPolicy: IfNotPresent + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + args: + - "--name=test-override-domains" + - "--namespace=$(POD_NAMESPACE)" + - "-v=4" + - "--override-domains=null.ptr,void.str" + - "--hostname-template=${name}-${namespace}.apps.veto.test" + - "--stats-port=1936" + - "--metrics-type=haproxy" + hostNetwork: false + ports: + - containerPort: 80 + - containerPort: 443 + - containerPort: 1936 + name: stats + protocol: TCP + readinessProbe: + initialDelaySeconds: 10 + httpGet: + path: /healthz/ready + port: 1936 + serviceAccountName: default `) -func testExtendedTestdataSignerBuildconfigYamlBytes() ([]byte, error) { - return _testExtendedTestdataSignerBuildconfigYaml, nil +func testExtendedTestdataRouterRouterOverrideDomainsYamlBytes() ([]byte, error) { + return _testExtendedTestdataRouterRouterOverrideDomainsYaml, nil } -func testExtendedTestdataSignerBuildconfigYaml() (*asset, error) { - bytes, err := testExtendedTestdataSignerBuildconfigYamlBytes() +func testExtendedTestdataRouterRouterOverrideDomainsYaml() (*asset, error) { + bytes, err := testExtendedTestdataRouterRouterOverrideDomainsYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/signer-buildconfig.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/router/router-override-domains.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataTemplatesCrunchydataPodJson = []byte(`{ - "kind": "Template", - "apiVersion": "template.openshift.io/v1", - "metadata": { - "name": "node-example", - "creationTimestamp": null - }, - "objects": [ - { - "kind": "Pod", - "apiVersion": "v1", - "metadata": { - "name": "pg-standalone-1", - "creationTimestamp": null, - "labels": { - "name": "crunchy-node" - } - }, - "spec": { - "volumes": [ - { - "name": "pgdata", - "hostPath": { - "path": "/var/lib/pgsql/exampleuser" - }, - "rbd": null - } - ], - "containers": [ - { - "name": "master", - "image": "registry:5000/crunchy-node", - "ports": [ - { - "hostPort": 9000, - "containerPort": 5432, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "PG_USERNAME", - "value": "exampleuser" - }, - { - "name": "PG_PASSWORD", - "value": "example" - } - ], - "resources": {}, - "volumeMounts": [ - { - "name": "pgdata", - "mountPath": "/pgdata" - } - ], - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "capabilities": {}, - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst", - "serviceAccount": "" - }, - "status": {} - } - ] -} +var _testExtendedTestdataRouterRouterOverrideYaml = []byte(`apiVersion: v1 +kind: Template +parameters: +- name: IMAGE + value: openshift/origin-haproxy-router:latest +objects: + +# a router that overrides host +- apiVersion: v1 + kind: Pod + metadata: + name: router-override + labels: + test: router-override + spec: + terminationGracePeriodSeconds: 1 + containers: + - name: router + image: ${IMAGE} + imagePullPolicy: IfNotPresent + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + args: + - "--name=test-override" + - "--namespace=$(POD_NAMESPACE)" + - "-v=4" + - "--override-hostname" + - "--hostname-template=${name}-${namespace}.myapps.mycompany.com" + - "--stats-port=1936" + - "--metrics-type=haproxy" + hostNetwork: false + ports: + - containerPort: 80 + - containerPort: 443 + - containerPort: 1936 + name: stats + protocol: TCP + readinessProbe: + initialDelaySeconds: 10 + httpGet: + path: /healthz/ready + port: 1936 + serviceAccountName: default `) -func testExtendedTestdataTemplatesCrunchydataPodJsonBytes() ([]byte, error) { - return _testExtendedTestdataTemplatesCrunchydataPodJson, nil +func testExtendedTestdataRouterRouterOverrideYamlBytes() ([]byte, error) { + return _testExtendedTestdataRouterRouterOverrideYaml, nil } -func testExtendedTestdataTemplatesCrunchydataPodJson() (*asset, error) { - bytes, err := testExtendedTestdataTemplatesCrunchydataPodJsonBytes() +func testExtendedTestdataRouterRouterOverrideYaml() (*asset, error) { + bytes, err := testExtendedTestdataRouterRouterOverrideYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/templates/crunchydata-pod.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/router/router-override.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataTemplatesGuestbookJson = []byte(`{ - "kind": "Template", - "apiVersion": "template.openshift.io/v1", - "metadata": { - "name": "guestbook-example", - "creationTimestamp": null, - "annotations": { - "openshift.io/display-name": "Guestbook Example", - "description": "Example shows how to build a simple multi-tier application using Kubernetes and Docker" - } - }, - "message": "Your admin credentials are ${ADMIN_USERNAME}:${ADMIN_PASSWORD}", - "objects": [ - { - "kind": "Route", - "apiVersion": "v1", - "metadata": { - "name": "frontend-route", - "creationTimestamp": null - }, - "spec": { - "host": "guestbook.example.com", - "to": { - "kind": "Service", - "name": "frontend-service" - } - }, - "status": {} - }, - { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "frontend-service", - "creationTimestamp": null - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 5432, - "targetPort": 5432, - "nodePort": 0 - } - ], - "selector": { - "name": "frontend-service" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } - }, - { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "redis-master", - "creationTimestamp": null - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 10000, - "targetPort": 10000, - "nodePort": 0 - } - ], - "selector": { - "name": "redis-master" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } - }, - { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "${SLAVE_SERVICE_NAME}", - "creationTimestamp": null - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 10001, - "targetPort": 10001, - "nodePort": 0 - } - ], - "selector": { - "name": "${SLAVE_SERVICE_NAME}" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } - }, - { - "kind": "Pod", - "apiVersion": "v1", - "metadata": { - "name": "redis-master", - "creationTimestamp": null, - "labels": { - "name": "redis-master" - } - }, - "spec": { - "containers": [ - { - "name": "master", - "image": "dockerfile/redis", - "ports": [ - { - "containerPort": 6379, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "REDIS_PASSWORD", - "value": "${REDIS_PASSWORD}" - } - ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst", - "serviceAccount": "" - }, - "status": {} - }, - { - "kind": "ReplicationController", - "apiVersion": "v1", - "metadata": { - "name": "guestbook", - "creationTimestamp": null, - "labels": { - "name": "frontend-service" - } - }, - "spec": { - "replicas": 3, - "selector": { - "name": "frontend-service" - }, - "template": { - "metadata": { - "creationTimestamp": null, - "labels": { - "name": "frontend-service" - } - }, - "spec": { - "containers": [ - { - "name": "php-redis", - "image": "brendanburns/php-redis", - "ports": [ - { - "hostPort": 8000, - "containerPort": 80, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "ADMIN_USERNAME", - "value": "${ADMIN_USERNAME}" - }, - { - "name": "ADMIN_PASSWORD", - "value": "${ADMIN_PASSWORD}" - }, - { - "name": "REDIS_PASSWORD", - "value": "${REDIS_PASSWORD}" - } - ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst", - "serviceAccount": "" - } - } - }, - "status": { - "replicas": 0 - } - }, - { - "kind": "ReplicationController", - "apiVersion": "v1", - "metadata": { - "name": "${SLAVE_SERVICE_NAME}", - "creationTimestamp": null, - "labels": { - "name": "${SLAVE_SERVICE_NAME}" - } - }, - "spec": { - "replicas": 2, - "selector": { - "name": "${SLAVE_SERVICE_NAME}" - }, - "template": { - "metadata": { - "creationTimestamp": null, - "labels": { - "name": "${SLAVE_SERVICE_NAME}" - } - }, - "spec": { - "containers": [ - { - "name": "slave", - "image": "brendanburns/${SLAVE_SERVICE_NAME}", - "ports": [ - { - "hostPort": 6380, - "containerPort": 6379, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "REDIS_PASSWORD", - "value": "${REDIS_PASSWORD}" - } - ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst", - "serviceAccount": "" - } - } - }, - "status": { - "replicas": 0 - } - } - ], - "parameters": [ - { - "name": "ADMIN_USERNAME", - "description": "Guestbook administrator username", - "generate": "expression", - "from": "admin[A-Z0-9]{3}" - }, - { - "name": "ADMIN_PASSWORD", - "description": "Guestbook administrator password", - "generate": "expression", - "from": "[a-zA-Z0-9]{8}" - }, - { - "name": "REDIS_PASSWORD", - "description": "Redis password", - "generate": "expression", - "from": "[a-zA-Z0-9]{8}" - }, - { - "name": "SLAVE_SERVICE_NAME", - "description": "Slave Service name", - "value": "redis-slave" - } - ] +var _testExtendedTestdataRouterRouterScopedYaml = []byte(`apiVersion: v1 +kind: Template +parameters: +- name: IMAGE + value: openshift/origin-haproxy-router:latest +- name: ROUTER_NAME + value: "test-scoped" +- name: UPDATE_STATUS + value: "true" +objects: +# a scoped router +- apiVersion: v1 + kind: Pod + metadata: + name: router-scoped + labels: + test: router-scoped + spec: + terminationGracePeriodSeconds: 1 + containers: + - name: router + image: ${IMAGE} + imagePullPolicy: IfNotPresent + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + args: + - "--name=${ROUTER_NAME}" + - "--namespace=$(POD_NAMESPACE)" + - "--update-status=${UPDATE_STATUS}" + - "-v=4" + - "--labels=select=first" + - "--stats-port=1936" + - "--metrics-type=haproxy" + hostNetwork: false + ports: + - containerPort: 80 + - containerPort: 443 + - containerPort: 1936 + name: stats + protocol: TCP + readinessProbe: + initialDelaySeconds: 10 + httpGet: + path: /healthz/ready + port: 1936 + serviceAccountName: default +`) + +func testExtendedTestdataRouterRouterScopedYamlBytes() ([]byte, error) { + return _testExtendedTestdataRouterRouterScopedYaml, nil +} + +func testExtendedTestdataRouterRouterScopedYaml() (*asset, error) { + bytes, err := testExtendedTestdataRouterRouterScopedYamlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/extended/testdata/router/router-scoped.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil } + +var _testExtendedTestdataRouterWeightedRouterYaml = []byte(`apiVersion: v1 +kind: Template +parameters: +- name: IMAGE + value: openshift/origin-haproxy-router:latest +objects: +# a weighted router +- apiVersion: v1 + kind: Pod + metadata: + name: weighted-router + labels: + test: weighted-router + spec: + terminationGracePeriodSeconds: 1 + containers: + - name: router + image: ${IMAGE} + imagePullPolicy: IfNotPresent + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + args: ["--namespace=$(POD_NAMESPACE)", "-v=4", "--labels=select=weighted", "--stats-password=password", "--stats-port=1936", "--stats-user=admin"] + hostNetwork: false + ports: + - containerPort: 80 + - containerPort: 443 + - containerPort: 1936 + name: stats + protocol: TCP + serviceAccountName: default + +# ensure the router can access routes and endpoints +- apiVersion: v1 + kind: RoleBinding + metadata: + name: system-router + subjects: + - kind: ServiceAccount + name: default + roleRef: + name: system:router + +# a route that has multiple weighted services that it points to +- apiVersion: v1 + kind: Route + metadata: + name: weightedroute + labels: + test: router + select: weighted + spec: + host: weighted.example.com + to: + name: weightedendpoints1 + kind: Service + weight: 90 + alternateBackends: + - name: weightedendpoints2 + kind: Service + weight: 10 + ports: + - targetPort: 8080 + +# a route that has multiple services but all weights are zero +- apiVersion: v1 + kind: Route + metadata: + name: zeroweightroute + labels: + test: router + select: weighted + spec: + host: zeroweight.example.com + to: + name: weightedendpoints1 + kind: Service + weight: 0 + alternateBackends: + - name: weightedendpoints2 + kind: Service + weight: 0 + ports: + - targetPort: 8080 + +# two services that can be routed to +- apiVersion: v1 + kind: Service + metadata: + name: weightedendpoints1 + labels: + test: router + spec: + selector: + test: weightedrouter1 + endpoints: weightedrouter1 + ports: + - port: 8080 +- apiVersion: v1 + kind: Service + metadata: + name: weightedendpoints2 + labels: + test: router + spec: + selector: + test: weightedrouter2 + endpoints: weightedrouter2 + ports: + - port: 8080 +# two pods that serves a response +- apiVersion: v1 + kind: Pod + metadata: + name: endpoint-1 + labels: + test: weightedrouter1 + endpoints: weightedrouter1 + spec: + terminationGracePeriodSeconds: 1 + containers: + - name: test + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] + ports: + - containerPort: 8080 + name: http + - containerPort: 100 + protocol: UDP +- apiVersion: v1 + kind: Pod + metadata: + name: endpoint-2 + labels: + test: weightedrouter2 + endpoints: weightedrouter2 + spec: + terminationGracePeriodSeconds: 1 + containers: + - name: test + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] + ports: + - containerPort: 8080 + name: http + - containerPort: 100 + protocol: UDP +- apiVersion: v1 + kind: Pod + metadata: + name: endpoint-3 + labels: + test: weightedrouter2 + endpoints: weightedrouter2 + spec: + terminationGracePeriodSeconds: 1 + containers: + - name: test + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] + ports: + - containerPort: 8080 + name: http + - containerPort: 100 + protocol: UDP `) -func testExtendedTestdataTemplatesGuestbookJsonBytes() ([]byte, error) { - return _testExtendedTestdataTemplatesGuestbookJson, nil +func testExtendedTestdataRouterWeightedRouterYamlBytes() ([]byte, error) { + return _testExtendedTestdataRouterWeightedRouterYaml, nil } -func testExtendedTestdataTemplatesGuestbookJson() (*asset, error) { - bytes, err := testExtendedTestdataTemplatesGuestbookJsonBytes() +func testExtendedTestdataRouterWeightedRouterYaml() (*asset, error) { + bytes, err := testExtendedTestdataRouterWeightedRouterYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/templates/guestbook.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/router/weighted-router.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataTemplatesGuestbook_listJson = []byte(`{ - "kind": "Template", - "apiVersion": "template.openshift.io/v1", - "metadata": { - "name": "guestbook-example", - "creationTimestamp": null, - "annotations": { - "openshift.io/display-name": "Guestbook Example", - "description": "Example shows how to build a simple multi-tier application using Kubernetes and Docker" - } - }, - "message": "Your admin credentials are adminQ3H:dwNJiJwW", - "objects": [ - { - "apiVersion": "route.openshift.io/v1", - "kind": "Route", - "metadata": { - "creationTimestamp": null, - "name": "frontend-route" - }, - "spec": { - "host": "guestbook.example.com", - "to": { - "kind": "Service", - "name": "frontend-service" - } - }, - "status": {} - }, - { - "apiVersion": "v1", - "kind": "Service", - "metadata": { - "creationTimestamp": null, - "name": "frontend-service" - }, - "spec": { - "ports": [ - { - "nodePort": 0, - "port": 5432, - "protocol": "TCP", - "targetPort": 5432 - } - ], - "selector": { - "name": "frontend-service" - }, - "sessionAffinity": "None", - "type": "ClusterIP" - }, - "status": { - "loadBalancer": {} - } - }, - { - "apiVersion": "v1", - "kind": "Service", - "metadata": { - "creationTimestamp": null, - "name": "redis-master" - }, - "spec": { - "ports": [ - { - "nodePort": 0, - "port": 10000, - "protocol": "TCP", - "targetPort": 10000 - } - ], - "selector": { - "name": "redis-master" - }, - "sessionAffinity": "None", - "type": "ClusterIP" - }, - "status": { - "loadBalancer": {} - } - }, - { - "apiVersion": "v1", - "kind": "Service", - "metadata": { - "creationTimestamp": null, - "name": "redis-slave" - }, - "spec": { - "ports": [ - { - "nodePort": 0, - "port": 10001, - "protocol": "TCP", - "targetPort": 10001 - } - ], - "selector": { - "name": "redis-slave" - }, - "sessionAffinity": "None", - "type": "ClusterIP" - }, - "status": { - "loadBalancer": {} - } - }, - { - "apiVersion": "v1", - "kind": "Pod", - "metadata": { - "creationTimestamp": null, - "labels": { - "name": "redis-master" - }, - "name": "redis-master" - }, - "spec": { - "containers": [ - { - "capabilities": {}, - "env": [ - { - "name": "REDIS_PASSWORD", - "value": "P8vxbV4C" - } - ], - "image": "dockerfile/redis", - "imagePullPolicy": "IfNotPresent", - "name": "master", - "ports": [ - { - "containerPort": 6379, - "protocol": "TCP" - } - ], - "resources": {}, - "securityContext": { - "capabilities": {}, - "privileged": false - }, - "terminationMessagePath": "/dev/termination-log" - } - ], - "dnsPolicy": "ClusterFirst", - "restartPolicy": "Always", - "serviceAccount": "" - }, - "status": {} - }, - { - "apiVersion": "v1", - "kind": "ReplicationController", - "metadata": { - "creationTimestamp": null, - "labels": { - "name": "frontend-service" - }, - "name": "guestbook" - }, - "spec": { - "replicas": 3, - "selector": { - "name": "frontend-service" - }, - "template": { - "metadata": { - "creationTimestamp": null, - "labels": { - "name": "frontend-service" - } - }, - "spec": { - "containers": [ - { - "capabilities": {}, - "env": [ - { - "name": "ADMIN_USERNAME", - "value": "adminQ3H" - }, - { - "name": "ADMIN_PASSWORD", - "value": "dwNJiJwW" - }, - { - "name": "REDIS_PASSWORD", - "value": "P8vxbV4C" - } - ], - "image": "brendanburns/php-redis", - "imagePullPolicy": "IfNotPresent", - "name": "php-redis", - "ports": [ - { - "containerPort": 80, - "hostPort": 8000, - "protocol": "TCP" - } - ], - "resources": {}, - "securityContext": { - "capabilities": {}, - "privileged": false - }, - "terminationMessagePath": "/dev/termination-log" - } - ], - "dnsPolicy": "ClusterFirst", - "restartPolicy": "Always", - "serviceAccount": "" - } - } - }, - "status": { - "replicas": 0 - } - }, - { - "apiVersion": "v1", - "kind": "ReplicationController", - "metadata": { - "creationTimestamp": null, - "labels": { - "name": "redis-slave" - }, - "name": "redis-slave" - }, - "spec": { - "replicas": 2, - "selector": { - "name": "redis-slave" - }, - "template": { - "metadata": { - "creationTimestamp": null, - "labels": { - "name": "redis-slave" - } - }, - "spec": { - "containers": [ - { - "capabilities": {}, - "env": [ - { - "name": "REDIS_PASSWORD", - "value": "P8vxbV4C" - } - ], - "image": "brendanburns/redis-slave", - "imagePullPolicy": "IfNotPresent", - "name": "slave", - "ports": [ - { - "containerPort": 6379, - "hostPort": 6380, - "protocol": "TCP" - } - ], - "resources": {}, - "securityContext": { - "capabilities": {}, - "privileged": false - }, - "terminationMessagePath": "/dev/termination-log" - } - ], - "dnsPolicy": "ClusterFirst", - "restartPolicy": "Always", - "serviceAccount": "" - } - } - }, - "status": { - "replicas": 0 - } - } - ], - "parameters": [ - { - "name": "ADMIN_USERNAME", - "description": "Guestbook administrator username", - "value": "adminQ3H", - "generate": "expression", - "from": "admin[A-Z0-9]{3}" - }, - { - "name": "ADMIN_PASSWORD", - "description": "Guestbook administrator password", - "value": "dwNJiJwW", - "generate": "expression", - "from": "[a-zA-Z0-9]{8}" - }, - { - "name": "REDIS_PASSWORD", - "description": "Redis password", - "value": "P8vxbV4C", - "generate": "expression", - "from": "[a-zA-Z0-9]{8}" - }, - { - "name": "SLAVE_SERVICE_NAME", - "description": "Slave Service name", - "value": "redis-slave" - }, - { - "name": "CUSTOM_PARAM1", - "value": "1" - } - ] +var _testExtendedTestdataRun_policyParallelBcYaml = []byte(`--- + kind: "List" + apiVersion: "v1" + metadata: {} + items: + - + kind: "ImageStream" + apiVersion: "v1" + metadata: + name: "origin-ruby-sample" + creationTimestamp: null + spec: {} + status: + dockerImageRepository: "" + - + kind: "BuildConfig" + apiVersion: "v1" + metadata: + name: "sample-parallel-build" + spec: + runPolicy: "Parallel" + triggers: + - + type: "imageChange" + imageChange: {} + source: + type: "Git" + git: + uri: "https://github.com/openshift/ruby-hello-world.git" + strategy: + type: "Source" + sourceStrategy: + from: + kind: "DockerImage" + name: "image-registry.openshift-image-registry.svc:5000/openshift/ruby:2.7" + resources: {} + status: + lastVersion: 0 +`) + +func testExtendedTestdataRun_policyParallelBcYamlBytes() ([]byte, error) { + return _testExtendedTestdataRun_policyParallelBcYaml, nil +} + +func testExtendedTestdataRun_policyParallelBcYaml() (*asset, error) { + bytes, err := testExtendedTestdataRun_policyParallelBcYamlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/extended/testdata/run_policy/parallel-bc.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil } + +var _testExtendedTestdataRun_policySerialBcYaml = []byte(`--- + kind: "List" + apiVersion: "v1" + metadata: {} + items: + - + kind: "BuildConfig" + apiVersion: "v1" + metadata: + name: "sample-serial-build" + spec: + runPolicy: "Serial" + triggers: + - + type: "imageChange" + imageChange: {} + source: + type: "Git" + git: + uri: "https://github.com/openshift/ruby-hello-world.git" + strategy: + type: "Source" + sourceStrategy: + from: + kind: "DockerImage" + name: "image-registry.openshift-image-registry.svc:5000/openshift/ruby:2.7" + - + kind: "BuildConfig" + apiVersion: "v1" + metadata: + name: "sample-serial-build-fail" + spec: + runPolicy: "Serial" + triggers: + - + type: "imageChange" + imageChange: {} + source: + type: "Git" + git: + uri: "https://github.com/openshift/invalidrepo.git" + strategy: + type: "Source" + sourceStrategy: + from: + kind: "DockerImage" + name: "image-registry.openshift-image-registry.svc:5000/openshift/ruby:2.7" `) -func testExtendedTestdataTemplatesGuestbook_listJsonBytes() ([]byte, error) { - return _testExtendedTestdataTemplatesGuestbook_listJson, nil +func testExtendedTestdataRun_policySerialBcYamlBytes() ([]byte, error) { + return _testExtendedTestdataRun_policySerialBcYaml, nil } -func testExtendedTestdataTemplatesGuestbook_listJson() (*asset, error) { - bytes, err := testExtendedTestdataTemplatesGuestbook_listJsonBytes() +func testExtendedTestdataRun_policySerialBcYaml() (*asset, error) { + bytes, err := testExtendedTestdataRun_policySerialBcYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/templates/guestbook_list.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/run_policy/serial-bc.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataTemplatesTemplateinstance_badobjectYaml = []byte(`kind: List -apiVersion: v1 -items: -- kind: TemplateInstance - apiVersion: template.openshift.io/v1 - metadata: - name: invalidtemplateinstance - spec: - template: - kind: Template - apiVersion: v1 +var _testExtendedTestdataRun_policySerialLatestOnlyBcYaml = []byte(`--- + kind: "List" + apiVersion: "v1" + metadata: {} + items: + - + kind: "BuildConfig" + apiVersion: "v1" metadata: - name: template - objects: - - kind: Deployment - apiVersion: apps/v1 - metadata: - name: "invalidname!@#$%^&*" - spec: - replicas: 0 - selector: - matchLabels: - key: value - template: - metadata: - labels: - key: value - spec: - containers: - - name: hello-openshift - image: openshift/hello-openshift + name: "sample-serial-latest-only-build" + spec: + runPolicy: "SerialLatestOnly" + triggers: + - + type: "imageChange" + imageChange: {} + source: + type: "Git" + git: + uri: "https://github.com/openshift/ruby-hello-world.git" + strategy: + type: "Source" + sourceStrategy: + from: + kind: "DockerImage" + name: "image-registry.openshift-image-registry.svc:5000/openshift/ruby:2.7" + resources: {} + status: + lastVersion: 0 `) -func testExtendedTestdataTemplatesTemplateinstance_badobjectYamlBytes() ([]byte, error) { - return _testExtendedTestdataTemplatesTemplateinstance_badobjectYaml, nil +func testExtendedTestdataRun_policySerialLatestOnlyBcYamlBytes() ([]byte, error) { + return _testExtendedTestdataRun_policySerialLatestOnlyBcYaml, nil } -func testExtendedTestdataTemplatesTemplateinstance_badobjectYaml() (*asset, error) { - bytes, err := testExtendedTestdataTemplatesTemplateinstance_badobjectYamlBytes() +func testExtendedTestdataRun_policySerialLatestOnlyBcYaml() (*asset, error) { + bytes, err := testExtendedTestdataRun_policySerialLatestOnlyBcYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/templates/templateinstance_badobject.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/run_policy/serial-latest-only-bc.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataTemplatesTemplateinstance_objectkindsYaml = []byte(`kind: List -apiVersion: v1 +var _testExtendedTestdataS2iDropcapsRootAccessBuildYaml = []byte(`apiVersion: v1 items: -- kind: Secret - apiVersion: v1 - metadata: - name: configsecret - stringData: - NAME: template -- kind: TemplateInstance - apiVersion: template.openshift.io/v1 +- apiVersion: v1 + kind: BuildConfig metadata: - name: templateinstance + labels: + build: root-access-build + name: root-access-build spec: - template: - kind: Template - apiVersion: v1 - metadata: - name: template - objects: - - kind: Secret - apiVersion: v1 - metadata: - name: secret - labels: - foo: bar - - kind: Deployment - apiVersion: apps/v1 - metadata: - name: deployment - spec: - replicas: 0 - selector: - matchLabels: - key: value - template: - metadata: - labels: - key: value - spec: - containers: - - name: hello-openshift - image: openshift/hello-openshift - - kind: Route - apiVersion: v1 - metadata: - name: route - spec: - to: - name: foo - - kind: Route - apiVersion: route.openshift.io/v1 - metadata: - name: newroute - spec: - to: - name: foo - parameters: - - name: NAME - value: ${NAME} - secret: - name: configsecret + output: + to: + kind: ImageStreamTag + name: root-access-build:latest + postCommit: {} + resources: {} + source: + git: + uri: https://github.com/openshift/ruby-hello-world.git + secrets: [] + type: Git + strategy: + sourceStrategy: + from: + kind: ImageStreamTag + name: rootable-ruby:latest + type: Source + triggers: [] +- apiVersion: v1 + kind: ImageStream + metadata: + labels: + build: root-access-build + name: root-access-build + spec: {} +kind: List +metadata: {} `) -func testExtendedTestdataTemplatesTemplateinstance_objectkindsYamlBytes() ([]byte, error) { - return _testExtendedTestdataTemplatesTemplateinstance_objectkindsYaml, nil +func testExtendedTestdataS2iDropcapsRootAccessBuildYamlBytes() ([]byte, error) { + return _testExtendedTestdataS2iDropcapsRootAccessBuildYaml, nil } -func testExtendedTestdataTemplatesTemplateinstance_objectkindsYaml() (*asset, error) { - bytes, err := testExtendedTestdataTemplatesTemplateinstance_objectkindsYamlBytes() +func testExtendedTestdataS2iDropcapsRootAccessBuildYaml() (*asset, error) { + bytes, err := testExtendedTestdataS2iDropcapsRootAccessBuildYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/templates/templateinstance_objectkinds.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/s2i-dropcaps/root-access-build.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataTemplatesTemplateinstance_readinessYaml = []byte(`kind: Template -apiVersion: v1 +var _testExtendedTestdataS2iDropcapsRootableRubyDockerfile = []byte(`FROM centos/ruby-27-centos7:latest +USER root +RUN rm -f /usr/bin/ls +RUN echo "root:redhat" | chpasswd +USER 1001 +COPY ./adduser /usr/libexec/s2i/ +COPY ./assemble /usr/libexec/s2i/ +`) + +func testExtendedTestdataS2iDropcapsRootableRubyDockerfileBytes() ([]byte, error) { + return _testExtendedTestdataS2iDropcapsRootableRubyDockerfile, nil +} + +func testExtendedTestdataS2iDropcapsRootableRubyDockerfile() (*asset, error) { + bytes, err := testExtendedTestdataS2iDropcapsRootableRubyDockerfileBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/extended/testdata/s2i-dropcaps/rootable-ruby/Dockerfile", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _testExtendedTestdataS2iDropcapsRootableRubyAdduser = []byte(`#!/usr/bin/expect + +spawn su +expect "Password:" { + send "redhat\r" +} + +expect "#" { + send "adduser mytestuser\r" +} + +expect "#" { + send "exit\r" +} + +expect "$" {} +`) + +func testExtendedTestdataS2iDropcapsRootableRubyAdduserBytes() ([]byte, error) { + return _testExtendedTestdataS2iDropcapsRootableRubyAdduser, nil +} + +func testExtendedTestdataS2iDropcapsRootableRubyAdduser() (*asset, error) { + bytes, err := testExtendedTestdataS2iDropcapsRootableRubyAdduserBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/extended/testdata/s2i-dropcaps/rootable-ruby/adduser", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _testExtendedTestdataS2iDropcapsRootableRubyAssemble = []byte(`#!/bin/bash +set -e +/usr/libexec/s2i/adduser +cat /etc/passwd +grep "mytestuser" /etc/passwd +`) + +func testExtendedTestdataS2iDropcapsRootableRubyAssembleBytes() ([]byte, error) { + return _testExtendedTestdataS2iDropcapsRootableRubyAssemble, nil +} + +func testExtendedTestdataS2iDropcapsRootableRubyAssemble() (*asset, error) { + bytes, err := testExtendedTestdataS2iDropcapsRootableRubyAssembleBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/extended/testdata/s2i-dropcaps/rootable-ruby/assemble", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _testExtendedTestdataSampleImageStreamJson = []byte(`{ + "kind": "ImageStream", + "apiVersion": "v1", + "metadata": { + "name": "samplerepository", + "creationTimestamp": null + }, + "spec": {}, + "status": { + "dockerImageRepository": "" + } +}`) + +func testExtendedTestdataSampleImageStreamJsonBytes() ([]byte, error) { + return _testExtendedTestdataSampleImageStreamJson, nil +} + +func testExtendedTestdataSampleImageStreamJson() (*asset, error) { + bytes, err := testExtendedTestdataSampleImageStreamJsonBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/extended/testdata/sample-image-stream.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _testExtendedTestdataSamplepipelineWithenvsYaml = []byte(`apiVersion: v1 +kind: Template +labels: + template: application-template-sample-pipeline metadata: - name: simple-example annotations: + iconClass: icon-jenkins + tags: instant-app,jenkins + name: jenkins-pipeline-example +parameters: objects: -- kind: Service - apiVersion: v1 - metadata: - name: "${NAME}" - annotations: - description: Exposes and load balances the application pods - spec: - ports: - - name: web - port: 8080 - targetPort: 8080 - selector: - name: "${NAME}" -- kind: Route - apiVersion: v1 +- apiVersion: v1 + kind: BuildConfig metadata: - name: "${NAME}" + labels: + name: sample-pipeline-withenvs + name: sample-pipeline-withenvs spec: - host: "${APPLICATION_DOMAIN}" - to: - kind: Service - name: "${NAME}" + strategy: + jenkinsPipelineStrategy: + env: + - name: FOO1 + value: BAR1 + jenkinsfile: |- + node() { + echo "FOO1 is ${env.FOO1}" + echo "FOO2 is ${env.FOO2}" + } + type: JenkinsPipeline +`) + +func testExtendedTestdataSamplepipelineWithenvsYamlBytes() ([]byte, error) { + return _testExtendedTestdataSamplepipelineWithenvsYaml, nil +} + +func testExtendedTestdataSamplepipelineWithenvsYaml() (*asset, error) { + bytes, err := testExtendedTestdataSamplepipelineWithenvsYamlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/extended/testdata/samplepipeline-withenvs.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _testExtendedTestdataServiceServingCertNginxServingCertConf = []byte(`server { + listen 443; + + ssl on; + ssl_certificate /etc/serving-cert/tls.crt; + ssl_certificate_key /etc/serving-cert/tls.key; + server_name localhost; + + #charset koi8-r; + #access_log /var/log/nginx/log/host.access.log main; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + } + + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + # + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + + # proxy the PHP scripts to Apache listening on 127.0.0.1:80 + # + #location ~ \.php$ { + # proxy_pass http://127.0.0.1; + #} + + # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + # + #location ~ \.php$ { + # root html; + # fastcgi_pass 127.0.0.1:9000; + # fastcgi_index index.php; + # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; + # include fastcgi_params; + #} + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + # + #location ~ /\.ht { + # deny all; + #} +} +`) + +func testExtendedTestdataServiceServingCertNginxServingCertConfBytes() ([]byte, error) { + return _testExtendedTestdataServiceServingCertNginxServingCertConf, nil +} + +func testExtendedTestdataServiceServingCertNginxServingCertConf() (*asset, error) { + bytes, err := testExtendedTestdataServiceServingCertNginxServingCertConfBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/extended/testdata/service-serving-cert/nginx-serving-cert.conf", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _testExtendedTestdataSignerBuildconfigYaml = []byte(`kind: List +apiVersion: v1 +items: + - kind: ImageStream apiVersion: v1 metadata: - name: "${NAME}" - annotations: - description: Keeps track of changes in the application image + name: signer + - kind: BuildConfig apiVersion: v1 metadata: - name: "${NAME}" - annotations: - description: Defines how to build the application - template.alpha.openshift.io/wait-for-ready: 'true' + name: signer spec: + triggers: + - type: ConfigChange source: - type: Git - git: - uri: ${SOURCE_REPOSITORY_URL} + dockerfile: | + FROM quay.io/openshift/origin-control-plane:latest + RUN yum-config-manager --disable origin-local-release ||: + RUN yum install -y skopeo && \ + yum clean all && mkdir -p gnupg && chmod -R 0777 /var/lib/origin + RUN echo $'%echo Generating openpgp key ...\n\ + Key-Type: DSA \n\ + Key-Length: 1024 \n\ + Subkey-Type: ELG-E \n\ + Subkey-Length: 1024 \n\ + Name-Real: Joe Tester \n\ + Name-Comment: with stupid passphrase \n\ + Name-Email: joe@foo.bar \n\ + Expire-Date: 0 \n\ + Creation-Date: 2017-01-01 \n\ + %commit \n\ + %echo done \n' >> dummy_key.conf strategy: - type: Source - sourceStrategy: + type: Docker + dockerStrategy: from: kind: DockerImage - name: quay.io/redhat-developer/test-build-simples2i:latest + name: quay.io/openshift/origin-control-plane:latest output: to: kind: ImageStreamTag - name: "${NAME}:latest" - triggers: - - type: ConfigChange -- kind: DeploymentConfig - apiVersion: v1 - metadata: - name: "${NAME}" - annotations: - description: Defines how to deploy the application server - template.alpha.openshift.io/wait-for-ready: 'true' - spec: - strategy: - type: Rolling - triggers: - - type: ImageChange - imageChangeParams: - automatic: true - containerNames: - - simple-example - from: - kind: ImageStreamTag - name: "${NAME}:latest" - - type: ConfigChange - replicas: 1 - selector: - name: "${NAME}" - template: - metadata: - name: "${NAME}" - labels: - name: "${NAME}" - spec: - containers: - - name: simple-example - image: " " - ports: - - containerPort: 8080 -parameters: -- name: NAME - displayName: Name - description: The name assigned to all of the frontend objects defined in this template. - required: true - value: simple-example -- name: SOURCE_REPOSITORY_URL - displayName: sourceurl - required: true - value: https://github.com/sclorg/nodejs-ex -- name: APPLICATION_DOMAIN - displayName: Application Hostname - description: The exposed hostname that will route to the Node.js service, if left - blank a value will be defaulted. - value: '' + name: signer:latest `) -func testExtendedTestdataTemplatesTemplateinstance_readinessYamlBytes() ([]byte, error) { - return _testExtendedTestdataTemplatesTemplateinstance_readinessYaml, nil +func testExtendedTestdataSignerBuildconfigYamlBytes() ([]byte, error) { + return _testExtendedTestdataSignerBuildconfigYaml, nil } -func testExtendedTestdataTemplatesTemplateinstance_readinessYaml() (*asset, error) { - bytes, err := testExtendedTestdataTemplatesTemplateinstance_readinessYamlBytes() +func testExtendedTestdataSignerBuildconfigYaml() (*asset, error) { + bytes, err := testExtendedTestdataSignerBuildconfigYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/templates/templateinstance_readiness.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/signer-buildconfig.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataTemplatesTemplateservicebroker_bindYaml = []byte(`apiVersion: v1 -kind: Template -metadata: - name: tsbtemplate -objects: -- apiVersion: v1 - kind: Secret - metadata: - name: aadda50d-d92c-402d-bd29-5ed2095aad2c - namespace: ${NAMESPACE} - -- apiVersion: template.openshift.io/v1 - kind: TemplateInstance - metadata: - name: aadda50d-d92c-402d-bd29-5ed2095aad2c - namespace: ${NAMESPACE} - spec: - template: +var _testExtendedTestdataStableBusyboxYaml = []byte(`kind: List +apiVersion: v1 +metadata: {} +items: + - apiVersion: v1 + dockerImageConfig: '{"architecture":"amd64","config":{"Hostname":"55cd1f8f6e5b","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["sh"],"Image":"sha256:e732471cb81a564575aad46b9510161c5945deaf18e9be3db344333d72f0b4b2","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"container":"764ef4448baa9a1ce19e4ae95f8cdd4eda7a1186c512773e56dc634dff208a59","container_config":{"Hostname":"55cd1f8f6e5b","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) + CMD [\"sh\"]"],"Image":"sha256:e732471cb81a564575aad46b9510161c5945deaf18e9be3db344333d72f0b4b2","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2016-06-23T23:23:37.198943461Z","docker_version":"1.10.3","history":[{"created":"2016-06-23T23:23:36.73131105Z","created_by":"/bin/sh + -c #(nop) ADD file:9ca60502d646bdd815bb51e612c458e2d447b597b95cf435f9673f0966d41c1a + in /"},{"created":"2016-06-23T23:23:37.198943461Z","created_by":"/bin/sh -c #(nop) + CMD [\"sh\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:8ac8bfaff55af948c796026ee867448c5b5b5d9dd3549f4006d9759b25d4a893"]}}' + dockerImageLayers: + - mediaType: application/vnd.docker.image.rootfs.diff.tar.gzip + name: sha256:8ddc19f16526912237dd8af81971d5e4dd0587907234be2b83e249518d5b673f + size: 667590 + dockerImageManifest: |- + { + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/octet-stream", + "size": 1459, + "digest": "sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 667590, + "digest": "sha256:8ddc19f16526912237dd8af81971d5e4dd0587907234be2b83e249518d5b673f" + } + ] + } + dockerImageManifestMediaType: application/vnd.docker.distribution.manifest.v2+json + dockerImageLayers: [] + dockerImageMetadata: + Architecture: amd64 + Config: + Cmd: + - sh + Env: + - PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + Hostname: 55cd1f8f6e5b + Image: sha256:e732471cb81a564575aad46b9510161c5945deaf18e9be3db344333d72f0b4b2 + Container: 764ef4448baa9a1ce19e4ae95f8cdd4eda7a1186c512773e56dc634dff208a59 + ContainerConfig: + Cmd: + - /bin/sh + - -c + - '#(nop) CMD ["sh"]' + Env: + - PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + Hostname: 55cd1f8f6e5b + Image: sha256:e732471cb81a564575aad46b9510161c5945deaf18e9be3db344333d72f0b4b2 + Created: 2016-06-23T23:23:37Z + DockerVersion: 1.10.3 + Id: sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749 + Size: 669049 + apiVersion: "1.0" + kind: DockerImage + dockerImageMetadataVersion: "1.0" + dockerImageReference: busybox@sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6 + kind: Image + metadata: + creationTimestamp: 2016-07-27T15:12:10Z + name: sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6 + resourceVersion: "504" + selfLink: /oapi/v1/images/sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6 + uid: 7d6849b4-540c-11e6-809f-525400f25e34 + - apiVersion: v1 + kind: ImageStream + metadata: + annotations: + openshift.io/image.dockerRepositoryCheck: 2016-07-27T16:08:39Z + generation: 1 + name: busybox + namespace: default + resourceVersion: "505" + selfLink: /oapi/v1/namespaces/default/imagestreams/busybox + uid: 7d687e72-540c-11e6-809f-525400f25e34 + - apiVersion: v1 + kind: ImageStreamMapping + metadata: + name: busybox + namespace: default + tag: latest + image: apiVersion: v1 - kind: Template + kind: Image metadata: - uid: d261a5c9-db37-40b5-ac0f-5709e0e3aac4 - objects: - - apiVersion: v1 - data: - username: configmap-username - kind: ConfigMap - metadata: - annotations: - template.openshift.io/expose-configmap-username: "{.data['username']}" - name: configmap - - apiVersion: v1 - kind: Secret - metadata: - annotations: - template.openshift.io/base64-expose-secret-password: "{.data['password']}" - template.openshift.io/expose-secret-username: "{.data['username']}" - name: secret - stringData: - password: secret-password - username: secret-username - - apiVersion: v1 - kind: Service - metadata: - annotations: - template.openshift.io/expose-service-uri: http://{.spec.clusterIP}:{.spec.ports[?(.name=="port")].port} - name: service - spec: - ports: - - name: port - port: 1234 - - apiVersion: v1 - kind: Route - metadata: - annotations: - template.openshift.io/expose-route-uri: http://{.spec.host}{.spec.path} - name: route - spec: - host: host - path: /path - to: - kind: Service - name: service + name: sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6 + dockerImageReference: busybox@sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6 +`) -- apiVersion: template.openshift.io/v1 - kind: BrokerTemplateInstance - metadata: - name: aadda50d-d92c-402d-bd29-5ed2095aad2c - spec: - templateInstance: - apiVersion: template.openshift.io/v1 - kind: TemplateInstance - name: aadda50d-d92c-402d-bd29-5ed2095aad2c - namespace: ${NAMESPACE} +func testExtendedTestdataStableBusyboxYamlBytes() ([]byte, error) { + return _testExtendedTestdataStableBusyboxYaml, nil +} - secret: - apiVersion: v1 - kind: Secret - name: aadda50d-d92c-402d-bd29-5ed2095aad2c - namespace: ${NAMESPACE} +func testExtendedTestdataStableBusyboxYaml() (*asset, error) { + bytes, err := testExtendedTestdataStableBusyboxYamlBytes() + if err != nil { + return nil, err + } -parameters: -- name: NAMESPACE - required: true + info := bindataFileInfo{name: "test/extended/testdata/stable-busybox.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _testExtendedTestdataTemplatesCrunchydataPodJson = []byte(`{ + "kind": "Template", + "apiVersion": "template.openshift.io/v1", + "metadata": { + "name": "node-example", + "creationTimestamp": null + }, + "objects": [ + { + "kind": "Pod", + "apiVersion": "v1", + "metadata": { + "name": "pg-standalone-1", + "creationTimestamp": null, + "labels": { + "name": "crunchy-node" + } + }, + "spec": { + "volumes": [ + { + "name": "pgdata", + "hostPath": { + "path": "/var/lib/pgsql/exampleuser" + }, + "rbd": null + } + ], + "containers": [ + { + "name": "master", + "image": "registry:5000/crunchy-node", + "ports": [ + { + "hostPort": 9000, + "containerPort": 5432, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "PG_USERNAME", + "value": "exampleuser" + }, + { + "name": "PG_PASSWORD", + "value": "example" + } + ], + "resources": {}, + "volumeMounts": [ + { + "name": "pgdata", + "mountPath": "/pgdata" + } + ], + "terminationMessagePath": "/dev/termination-log", + "imagePullPolicy": "IfNotPresent", + "capabilities": {}, + "securityContext": { + "capabilities": {}, + "privileged": false + } + } + ], + "restartPolicy": "Always", + "dnsPolicy": "ClusterFirst", + "serviceAccount": "" + }, + "status": {} + } + ] +} `) -func testExtendedTestdataTemplatesTemplateservicebroker_bindYamlBytes() ([]byte, error) { - return _testExtendedTestdataTemplatesTemplateservicebroker_bindYaml, nil +func testExtendedTestdataTemplatesCrunchydataPodJsonBytes() ([]byte, error) { + return _testExtendedTestdataTemplatesCrunchydataPodJson, nil } -func testExtendedTestdataTemplatesTemplateservicebroker_bindYaml() (*asset, error) { - bytes, err := testExtendedTestdataTemplatesTemplateservicebroker_bindYamlBytes() +func testExtendedTestdataTemplatesCrunchydataPodJson() (*asset, error) { + bytes, err := testExtendedTestdataTemplatesCrunchydataPodJsonBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/templates/templateservicebroker_bind.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/templates/crunchydata-pod.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } - -var _testExtendedTestdataTestCliDebugYaml = []byte(`kind: List -apiVersion: v1 -items: -- kind: ImageStream - apiVersion: v1 - metadata: - name: local-busybox - -- kind: BuildConfig - apiVersion: v1 - metadata: - name: local-busybox - spec: - strategy: - type: Docker - source: - type: Git - dockerfile: "FROM busybox:latest\n" - output: - to: - kind: ImageStreamTag - name: local-busybox:latest - triggers: - - type: ConfigChange - -- kind: DeploymentConfig - apiVersion: v1 - metadata: - name: local-busybox1 - spec: - replicas: 0 - selector: - deploymentconfig: local-busybox1 - template: - metadata: - labels: - deploymentconfig: local-busybox1 - spec: - containers: - - name: local-busybox - triggers: - - type: ImageChange - imageChangeParams: - automatic: true - containerNames: - - local-busybox - from: - kind: ImageStreamTag - name: local-busybox:latest - -- kind: DeploymentConfig - apiVersion: v1 - metadata: - name: local-busybox2 - spec: - replicas: 0 - selector: - deploymentconfig: local-busybox2 - template: - metadata: - labels: - deploymentconfig: local-busybox2 - spec: - containers: - - name: local-busybox - command: - - foo - - bar - args: - - baz - - qux - triggers: - - type: ImageChange - imageChangeParams: - automatic: true - containerNames: - - local-busybox - from: - kind: ImageStreamTag - name: local-busybox:latest - -- kind: DeploymentConfig - apiVersion: v1 - metadata: - name: busybox1 - spec: - replicas: 0 - selector: - deploymentconfig: busybox1 - template: - metadata: - labels: - deploymentconfig: busybox1 - spec: - containers: - - name: busybox - image: busybox - -- kind: DeploymentConfig - apiVersion: v1 - metadata: - name: busybox2 - spec: - replicas: 0 - selector: - deploymentconfig: busybox2 - template: - metadata: - labels: - deploymentconfig: busybox2 - spec: - containers: - - name: busybox - image: busybox - command: - - foo - - bar - args: - - baz - - qux + +var _testExtendedTestdataTemplatesGuestbookJson = []byte(`{ + "kind": "Template", + "apiVersion": "template.openshift.io/v1", + "metadata": { + "name": "guestbook-example", + "creationTimestamp": null, + "annotations": { + "openshift.io/display-name": "Guestbook Example", + "description": "Example shows how to build a simple multi-tier application using Kubernetes and Docker" + } + }, + "message": "Your admin credentials are ${ADMIN_USERNAME}:${ADMIN_PASSWORD}", + "objects": [ + { + "kind": "Route", + "apiVersion": "v1", + "metadata": { + "name": "frontend-route", + "creationTimestamp": null + }, + "spec": { + "host": "guestbook.example.com", + "to": { + "kind": "Service", + "name": "frontend-service" + } + }, + "status": {} + }, + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "frontend-service", + "creationTimestamp": null + }, + "spec": { + "ports": [ + { + "protocol": "TCP", + "port": 5432, + "targetPort": 5432, + "nodePort": 0 + } + ], + "selector": { + "name": "frontend-service" + }, + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "redis-master", + "creationTimestamp": null + }, + "spec": { + "ports": [ + { + "protocol": "TCP", + "port": 10000, + "targetPort": 10000, + "nodePort": 0 + } + ], + "selector": { + "name": "redis-master" + }, + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "${SLAVE_SERVICE_NAME}", + "creationTimestamp": null + }, + "spec": { + "ports": [ + { + "protocol": "TCP", + "port": 10001, + "targetPort": 10001, + "nodePort": 0 + } + ], + "selector": { + "name": "${SLAVE_SERVICE_NAME}" + }, + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } + }, + { + "kind": "Pod", + "apiVersion": "v1", + "metadata": { + "name": "redis-master", + "creationTimestamp": null, + "labels": { + "name": "redis-master" + } + }, + "spec": { + "containers": [ + { + "name": "master", + "image": "dockerfile/redis", + "ports": [ + { + "containerPort": 6379, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "REDIS_PASSWORD", + "value": "${REDIS_PASSWORD}" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "imagePullPolicy": "IfNotPresent", + "securityContext": { + "capabilities": {}, + "privileged": false + } + } + ], + "restartPolicy": "Always", + "dnsPolicy": "ClusterFirst", + "serviceAccount": "" + }, + "status": {} + }, + { + "kind": "ReplicationController", + "apiVersion": "v1", + "metadata": { + "name": "guestbook", + "creationTimestamp": null, + "labels": { + "name": "frontend-service" + } + }, + "spec": { + "replicas": 3, + "selector": { + "name": "frontend-service" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "name": "frontend-service" + } + }, + "spec": { + "containers": [ + { + "name": "php-redis", + "image": "brendanburns/php-redis", + "ports": [ + { + "hostPort": 8000, + "containerPort": 80, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "ADMIN_USERNAME", + "value": "${ADMIN_USERNAME}" + }, + { + "name": "ADMIN_PASSWORD", + "value": "${ADMIN_PASSWORD}" + }, + { + "name": "REDIS_PASSWORD", + "value": "${REDIS_PASSWORD}" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "imagePullPolicy": "IfNotPresent", + "securityContext": { + "capabilities": {}, + "privileged": false + } + } + ], + "restartPolicy": "Always", + "dnsPolicy": "ClusterFirst", + "serviceAccount": "" + } + } + }, + "status": { + "replicas": 0 + } + }, + { + "kind": "ReplicationController", + "apiVersion": "v1", + "metadata": { + "name": "${SLAVE_SERVICE_NAME}", + "creationTimestamp": null, + "labels": { + "name": "${SLAVE_SERVICE_NAME}" + } + }, + "spec": { + "replicas": 2, + "selector": { + "name": "${SLAVE_SERVICE_NAME}" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "name": "${SLAVE_SERVICE_NAME}" + } + }, + "spec": { + "containers": [ + { + "name": "slave", + "image": "brendanburns/${SLAVE_SERVICE_NAME}", + "ports": [ + { + "hostPort": 6380, + "containerPort": 6379, + "protocol": "TCP" + } + ], + "env": [ + { + "name": "REDIS_PASSWORD", + "value": "${REDIS_PASSWORD}" + } + ], + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "imagePullPolicy": "IfNotPresent", + "securityContext": { + "capabilities": {}, + "privileged": false + } + } + ], + "restartPolicy": "Always", + "dnsPolicy": "ClusterFirst", + "serviceAccount": "" + } + } + }, + "status": { + "replicas": 0 + } + } + ], + "parameters": [ + { + "name": "ADMIN_USERNAME", + "description": "Guestbook administrator username", + "generate": "expression", + "from": "admin[A-Z0-9]{3}" + }, + { + "name": "ADMIN_PASSWORD", + "description": "Guestbook administrator password", + "generate": "expression", + "from": "[a-zA-Z0-9]{8}" + }, + { + "name": "REDIS_PASSWORD", + "description": "Redis password", + "generate": "expression", + "from": "[a-zA-Z0-9]{8}" + }, + { + "name": "SLAVE_SERVICE_NAME", + "description": "Slave Service name", + "value": "redis-slave" + } + ] +} `) -func testExtendedTestdataTestCliDebugYamlBytes() ([]byte, error) { - return _testExtendedTestdataTestCliDebugYaml, nil +func testExtendedTestdataTemplatesGuestbookJsonBytes() ([]byte, error) { + return _testExtendedTestdataTemplatesGuestbookJson, nil } -func testExtendedTestdataTestCliDebugYaml() (*asset, error) { - bytes, err := testExtendedTestdataTestCliDebugYamlBytes() +func testExtendedTestdataTemplatesGuestbookJson() (*asset, error) { + bytes, err := testExtendedTestdataTemplatesGuestbookJsonBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/test-cli-debug.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/templates/guestbook.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataTestEnvPodJson = []byte(`{ - "kind":"Pod", - "apiVersion":"v1", - "metadata":{ - "name":"test-pod", - "labels":{ - "name":"test-pod" - } - }, - "spec":{ - "containers":[ - { - "name":"test", - "image":"centos:centos7", - "env": [ - { - "name":"podname", - "valueFrom": { - "fieldRef": { - "fieldPath":"metadata.name" - } +var _testExtendedTestdataTemplatesGuestbook_listJson = []byte(`{ + "kind": "Template", + "apiVersion": "template.openshift.io/v1", + "metadata": { + "name": "guestbook-example", + "creationTimestamp": null, + "annotations": { + "openshift.io/display-name": "Guestbook Example", + "description": "Example shows how to build a simple multi-tier application using Kubernetes and Docker" + } + }, + "message": "Your admin credentials are adminQ3H:dwNJiJwW", + "objects": [ + { + "apiVersion": "route.openshift.io/v1", + "kind": "Route", + "metadata": { + "creationTimestamp": null, + "name": "frontend-route" + }, + "spec": { + "host": "guestbook.example.com", + "to": { + "kind": "Service", + "name": "frontend-service" + } + }, + "status": {} + }, + { + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "creationTimestamp": null, + "name": "frontend-service" + }, + "spec": { + "ports": [ + { + "nodePort": 0, + "port": 5432, + "protocol": "TCP", + "targetPort": 5432 + } + ], + "selector": { + "name": "frontend-service" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + }, + "status": { + "loadBalancer": {} + } + }, + { + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "creationTimestamp": null, + "name": "redis-master" + }, + "spec": { + "ports": [ + { + "nodePort": 0, + "port": 10000, + "protocol": "TCP", + "targetPort": 10000 + } + ], + "selector": { + "name": "redis-master" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + }, + "status": { + "loadBalancer": {} + } + }, + { + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "creationTimestamp": null, + "name": "redis-slave" + }, + "spec": { + "ports": [ + { + "nodePort": 0, + "port": 10001, + "protocol": "TCP", + "targetPort": 10001 + } + ], + "selector": { + "name": "redis-slave" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + }, + "status": { + "loadBalancer": {} + } + }, + { + "apiVersion": "v1", + "kind": "Pod", + "metadata": { + "creationTimestamp": null, + "labels": { + "name": "redis-master" + }, + "name": "redis-master" + }, + "spec": { + "containers": [ + { + "capabilities": {}, + "env": [ + { + "name": "REDIS_PASSWORD", + "value": "P8vxbV4C" + } + ], + "image": "dockerfile/redis", + "imagePullPolicy": "IfNotPresent", + "name": "master", + "ports": [ + { + "containerPort": 6379, + "protocol": "TCP" + } + ], + "resources": {}, + "securityContext": { + "capabilities": {}, + "privileged": false + }, + "terminationMessagePath": "/dev/termination-log" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "serviceAccount": "" + }, + "status": {} + }, + { + "apiVersion": "v1", + "kind": "ReplicationController", + "metadata": { + "creationTimestamp": null, + "labels": { + "name": "frontend-service" + }, + "name": "guestbook" + }, + "spec": { + "replicas": 3, + "selector": { + "name": "frontend-service" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "name": "frontend-service" + } + }, + "spec": { + "containers": [ + { + "capabilities": {}, + "env": [ + { + "name": "ADMIN_USERNAME", + "value": "adminQ3H" + }, + { + "name": "ADMIN_PASSWORD", + "value": "dwNJiJwW" + }, + { + "name": "REDIS_PASSWORD", + "value": "P8vxbV4C" + } + ], + "image": "brendanburns/php-redis", + "imagePullPolicy": "IfNotPresent", + "name": "php-redis", + "ports": [ + { + "containerPort": 80, + "hostPort": 8000, + "protocol": "TCP" + } + ], + "resources": {}, + "securityContext": { + "capabilities": {}, + "privileged": false + }, + "terminationMessagePath": "/dev/termination-log" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "serviceAccount": "" + } + } + }, + "status": { + "replicas": 0 } - }, - { - "name":"podname_composed", - "value":"$(podname)_composed" - }, - { - "name":"var1", - "value":"value1" - }, - { - "name":"var2", - "value":"$(var1)" - }, - { - "name":"var3", - "value":"120" - } - ], - "command": [ - "sleep", - "$(var3)" - ] - } + }, + { + "apiVersion": "v1", + "kind": "ReplicationController", + "metadata": { + "creationTimestamp": null, + "labels": { + "name": "redis-slave" + }, + "name": "redis-slave" + }, + "spec": { + "replicas": 2, + "selector": { + "name": "redis-slave" + }, + "template": { + "metadata": { + "creationTimestamp": null, + "labels": { + "name": "redis-slave" + } + }, + "spec": { + "containers": [ + { + "capabilities": {}, + "env": [ + { + "name": "REDIS_PASSWORD", + "value": "P8vxbV4C" + } + ], + "image": "brendanburns/redis-slave", + "imagePullPolicy": "IfNotPresent", + "name": "slave", + "ports": [ + { + "containerPort": 6379, + "hostPort": 6380, + "protocol": "TCP" + } + ], + "resources": {}, + "securityContext": { + "capabilities": {}, + "privileged": false + }, + "terminationMessagePath": "/dev/termination-log" + } + ], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "serviceAccount": "" + } + } + }, + "status": { + "replicas": 0 + } + } ], - "restartPolicy":"Never", - "dnsPolicy":"ClusterFirst" - } + "parameters": [ + { + "name": "ADMIN_USERNAME", + "description": "Guestbook administrator username", + "value": "adminQ3H", + "generate": "expression", + "from": "admin[A-Z0-9]{3}" + }, + { + "name": "ADMIN_PASSWORD", + "description": "Guestbook administrator password", + "value": "dwNJiJwW", + "generate": "expression", + "from": "[a-zA-Z0-9]{8}" + }, + { + "name": "REDIS_PASSWORD", + "description": "Redis password", + "value": "P8vxbV4C", + "generate": "expression", + "from": "[a-zA-Z0-9]{8}" + }, + { + "name": "SLAVE_SERVICE_NAME", + "description": "Slave Service name", + "value": "redis-slave" + }, + { + "name": "CUSTOM_PARAM1", + "value": "1" + } + ] } `) -func testExtendedTestdataTestEnvPodJsonBytes() ([]byte, error) { - return _testExtendedTestdataTestEnvPodJson, nil +func testExtendedTestdataTemplatesGuestbook_listJsonBytes() ([]byte, error) { + return _testExtendedTestdataTemplatesGuestbook_listJson, nil } -func testExtendedTestdataTestEnvPodJson() (*asset, error) { - bytes, err := testExtendedTestdataTestEnvPodJsonBytes() +func testExtendedTestdataTemplatesGuestbook_listJson() (*asset, error) { + bytes, err := testExtendedTestdataTemplatesGuestbook_listJsonBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/test-env-pod.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/templates/guestbook_list.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataTestGitserverYaml = []byte(`apiVersion: v1 -kind: Template -labels: - template: gitserver -metadata: - name: gitserver -objects: -# The gitserver is deployed as a singleton pod and uses a very small amount -# of resources. It can host or transiently serve Git repositories, as well -# as automatically integrate with builds in a namespace. -- apiVersion: v1 - kind: DeploymentConfig +var _testExtendedTestdataTemplatesTemplateinstance_badobjectYaml = []byte(`kind: List +apiVersion: v1 +items: +- kind: TemplateInstance + apiVersion: template.openshift.io/v1 metadata: - name: gitserver - labels: - app: gitserver + name: invalidtemplateinstance spec: - replicas: 1 # the gitserver is not HA and should not be scaled past 1 - selector: - run-container: gitserver template: + kind: Template + apiVersion: v1 metadata: - labels: - run-container: gitserver - spec: - containers: - - name: gitserver - image: openshift/origin-gitserver - readinessProbe: - tcpSocket: - port: 8080 - ports: - - containerPort: 8080 - - env: - # Each environment variable matching GIT_INITIAL_CLONE_* will - # be cloned when the process starts; failures will be logged. - # must be [A-Z0-9_\-\.], the cloned directory name will - # be lowercased. If the name is invalid the pod will halt. If - # the repository already exists on disk, it will be updated - # from the remote. - # - - name: GIT_INITIAL_CLONE_1 - value: https://github.com/openshift/ruby-hello-world.git;ruby-hello-world - - - # The namespace of the pod is required for implicit config - # (passing '-' to AUTOLINK_KUBECONFIG or REQUIRE_SERVER_AUTH) - # and can also be used to target a specific namespace. - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - # The URL that builds must use to access the Git repositories - # stored in this app. - # TODO: support HTTPS - - name: PUBLIC_URL - value: http://gitserver.$(POD_NAMESPACE).svc.cluster.local:8080 - # The directory to store Git repositories in. If not backed - # by a persistent volume, repositories will be lost when - # deployments occur. Use INITIAL_GIT_CLONE and AUTOLINK_* - # to remove the need to use a persistent volume. - - name: GIT_HOME - value: /var/lib/git - # The directory to use as the default hook directory for any - # cloned or autolinked directories. - - name: HOOK_PATH - value: /var/lib/git-hooks - - # Authentication and authorization - - # If 'yes', clients may push to the server with git push. - - name: ALLOW_GIT_PUSH - value: "yes" - # If 'yes', clients may set hooks via the API. However, unless - # the Git home is backed by a persistent volume, any deployment - # will result in the hooks being lost. - - name: ALLOW_GIT_HOOKS - value: "yes" - # If 'yes', clients can create new git repositories on demand - # by pushing. If the data on disk is not backed by a persistent - # volume, the Git repo will be deleted if the deployment is - # updated. - - name: ALLOW_LAZY_CREATE - value: "yes" - # If 'yes', clients can pull without being authenticated. - - name: ALLOW_ANON_GIT_PULL - - # Provides the path to a kubeconfig file in the image that - # should be used to authorize against the server. The value - # '-' will use the pod's service account. - # May not be used in combination with REQUIRE_GIT_AUTH - #- name: REQUIRE_SERVER_AUTH - # value: "-" - - # The namespace to check authorization against when - # REQUIRE_SERVICE_AUTH is used. Users must have 'get' on - # 'pods' to pull and 'create' on 'pods' to push. - - name: AUTH_NAMESPACE - value: $(POD_NAMESPACE) - # Require BASIC authentication with a username and password - # to push or pull. - # May not be used in combination with REQUIRE_SERVER_AUTH - - name: REQUIRE_GIT_AUTH - value: gituser:gituserpassword - - # Autolinking: - # - # The gitserver can automatically clone Git repositories - # associated with a build config and replace the URL with - # a link to the repo on PUBLIC_URL. The default post-receive - # hook on the cloned repo will then trigger a build. You - # may customize the hook with AUTOLINK_HOOK (path to hook). - # To autolink, the account the pod runs under must have 'edit' - # on the AUTOLINK_NAMESPACE: - # - # oc policy add-role-to-user \ - # system:serviceaccount:${namespace}:gitserver edit - # - # Links are checked every time the pod starts. - - # The location to read auth configuration from for autolinking. - # If '-', use the service account token to link. The account - # represented by this config must have the edit role on the - # namespace. - #- name: AUTOLINK_KUBECONFIG - # value: "-" - - # The namespace to autolink - #- name: AUTOLINK_NAMESPACE - # value: $(POD_NAMESPACE) - - # The path to a script in the image to use as the default - # post-receive hook - only set during link, so has no effect - # on cloned repositories. See the "hooks" directory in the - # image for examples. - #- name: AUTOLINK_HOOK - - # The master service host is not signed with the service IP - # so we override with the consistent DNS name. Required for - # connections to the server. - - name: KUBERNETES_SERVICE_HOST - value: kubernetes.default - - volumeMounts: - - mountPath: /var/lib/git/ - name: git - volumes: - - name: git - triggers: - - type: ConfigChange - -# The gitserver service is required for DNS resolution -- apiVersion: v1 - kind: Service - metadata: - name: gitserver - labels: - app: gitserver - spec: - ports: - - port: 8080 - targetPort: 8080 - selector: - run-container: gitserver -- apiVersion: v1 - kind: Route - metadata: - name: gitserver - labels: - app: gitserver - spec: - tls: - termination: edge - to: - kind: Service - name: gitserver + name: template + objects: + - kind: Deployment + apiVersion: apps/v1 + metadata: + name: "invalidname!@#$%^&*" + spec: + replicas: 0 + selector: + matchLabels: + key: value + template: + metadata: + labels: + key: value + spec: + containers: + - name: hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 `) -func testExtendedTestdataTestGitserverYamlBytes() ([]byte, error) { - return _testExtendedTestdataTestGitserverYaml, nil +func testExtendedTestdataTemplatesTemplateinstance_badobjectYamlBytes() ([]byte, error) { + return _testExtendedTestdataTemplatesTemplateinstance_badobjectYaml, nil } -func testExtendedTestdataTestGitserverYaml() (*asset, error) { - bytes, err := testExtendedTestdataTestGitserverYamlBytes() +func testExtendedTestdataTemplatesTemplateinstance_badobjectYaml() (*asset, error) { + bytes, err := testExtendedTestdataTemplatesTemplateinstance_badobjectYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/test-gitserver.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/templates/templateinstance_badobject.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataTestSecretJson = []byte(`{ - "kind": "Secret", - "apiVersion": "v1", - "metadata": { - "name": "docker", - "creationTimestamp": null - }, - "data": { - "dockercfg": "eyJodHRwczovL3JlZ2lzdHJ5aG9zdC92MSI6eyJhdXRoIjoic2VjcmV0IiwiZW1haWwiOiJqb2huQGRvZS5jb20ifX0K" - }, - "type": "Opaque" -}`) +var _testExtendedTestdataTemplatesTemplateinstance_objectkindsYaml = []byte(`kind: List +apiVersion: v1 +items: +- kind: Secret + apiVersion: v1 + metadata: + name: configsecret + stringData: + NAME: template +- kind: TemplateInstance + apiVersion: template.openshift.io/v1 + metadata: + name: templateinstance + spec: + template: + kind: Template + apiVersion: v1 + metadata: + name: template + objects: + - kind: Secret + apiVersion: v1 + metadata: + name: secret + labels: + foo: bar + - kind: Deployment + apiVersion: apps/v1 + metadata: + name: deployment + spec: + replicas: 0 + selector: + matchLabels: + key: value + template: + metadata: + labels: + key: value + spec: + containers: + - name: hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + - kind: Route + apiVersion: v1 + metadata: + name: route + spec: + to: + name: foo + - kind: Route + apiVersion: route.openshift.io/v1 + metadata: + name: newroute + spec: + to: + name: foo + parameters: + - name: NAME + value: ${NAME} + secret: + name: configsecret +`) -func testExtendedTestdataTestSecretJsonBytes() ([]byte, error) { - return _testExtendedTestdataTestSecretJson, nil +func testExtendedTestdataTemplatesTemplateinstance_objectkindsYamlBytes() ([]byte, error) { + return _testExtendedTestdataTemplatesTemplateinstance_objectkindsYaml, nil } -func testExtendedTestdataTestSecretJson() (*asset, error) { - bytes, err := testExtendedTestdataTestSecretJsonBytes() +func testExtendedTestdataTemplatesTemplateinstance_objectkindsYaml() (*asset, error) { + bytes, err := testExtendedTestdataTemplatesTemplateinstance_objectkindsYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/test-secret.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/templates/templateinstance_objectkinds.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testExtendedTestdataVerifyservicePipelineTemplateYaml = []byte(`apiVersion: v1 -kind: Template -labels: - template: jenkins-verifyservice-pipeline +var _testExtendedTestdataTemplatesTemplateinstance_readinessYaml = []byte(`kind: Template +apiVersion: v1 metadata: - name: redis-verifyservice-test - app: redis + name: simple-example + annotations: objects: -- apiVersion: v1 - kind: Service +- kind: Service + apiVersion: v1 metadata: - name: redis-headless - app: redis + name: "${NAME}" + annotations: + description: Exposes and load balances the application pods spec: - clusterIP: None ports: - - port: 6379 - targetPort: 6379 + - name: web + port: 8080 + targetPort: 8080 selector: - name: redis -- apiVersion: v1 - kind: BuildConfig + name: "${NAME}" +- kind: Route + apiVersion: v1 metadata: - name: jenkins-verifyservice-pipeline - app: redis + name: "${NAME}" + spec: + host: "${APPLICATION_DOMAIN}" + to: + kind: Service + name: "${NAME}" +- kind: ImageStream + apiVersion: v1 + metadata: + name: "${NAME}" + annotations: + description: Keeps track of changes in the application image +- kind: BuildConfig + apiVersion: v1 + metadata: + name: "${NAME}" + annotations: + description: Defines how to build the application + template.alpha.openshift.io/wait-for-ready: 'true' spec: + source: + type: Git + git: + uri: ${SOURCE_REPOSITORY_URL} strategy: - jenkinsPipelineStrategy: - jenkinsfile: |- - try { - timeout(time: 20, unit: 'MINUTES') { - // Select the default cluster - openshift.withCluster() { - // Select the default project - openshift.withProject() { - // Verify Normal Services - def connectedNormalService = openshift.verifyService('redis') - // Verify Headless Services with Selectors - def connectedHeadlessService = openshift.verifyService('redis-headless') - } - } - } - } catch (err) { - echo "in catch block" - echo "Caught: ${err}" - currentBuild.result = 'FAILURE' - throw err - } - type: JenkinsPipeline + type: Source + sourceStrategy: + from: + kind: DockerImage + name: quay.io/redhat-developer/test-build-simples2i:latest + output: + to: + kind: ImageStreamTag + name: "${NAME}:latest" + triggers: + - type: ConfigChange +- kind: DeploymentConfig + apiVersion: v1 + metadata: + name: "${NAME}" + annotations: + description: Defines how to deploy the application server + template.alpha.openshift.io/wait-for-ready: 'true' + spec: + strategy: + type: Rolling + triggers: + - type: ImageChange + imageChangeParams: + automatic: true + containerNames: + - simple-example + from: + kind: ImageStreamTag + name: "${NAME}:latest" + - type: ConfigChange + replicas: 1 + selector: + name: "${NAME}" + template: + metadata: + name: "${NAME}" + labels: + name: "${NAME}" + spec: + containers: + - name: simple-example + image: " " + ports: + - containerPort: 8080 +parameters: +- name: NAME + displayName: Name + description: The name assigned to all of the frontend objects defined in this template. + required: true + value: simple-example +- name: SOURCE_REPOSITORY_URL + displayName: sourceurl + required: true + value: https://github.com/sclorg/nodejs-ex +- name: APPLICATION_DOMAIN + displayName: Application Hostname + description: The exposed hostname that will route to the Node.js service, if left + blank a value will be defaulted. + value: '' `) -func testExtendedTestdataVerifyservicePipelineTemplateYamlBytes() ([]byte, error) { - return _testExtendedTestdataVerifyservicePipelineTemplateYaml, nil +func testExtendedTestdataTemplatesTemplateinstance_readinessYamlBytes() ([]byte, error) { + return _testExtendedTestdataTemplatesTemplateinstance_readinessYaml, nil } -func testExtendedTestdataVerifyservicePipelineTemplateYaml() (*asset, error) { - bytes, err := testExtendedTestdataVerifyservicePipelineTemplateYamlBytes() +func testExtendedTestdataTemplatesTemplateinstance_readinessYaml() (*asset, error) { + bytes, err := testExtendedTestdataTemplatesTemplateinstance_readinessYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/extended/testdata/verifyservice-pipeline-template.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/templates/templateinstance_readiness.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testIntegrationTestdataProjectRequestTemplateWithQuotaYaml = []byte(`apiVersion: template.openshift.io/v1 +var _testExtendedTestdataTemplatesTemplateservicebroker_bindYaml = []byte(`apiVersion: v1 kind: Template metadata: - creationTimestamp: 2015-10-24T18:25:22Z - name: default-project-request - namespace: default + name: tsbtemplate objects: - apiVersion: v1 - kind: Project + kind: Secret metadata: - annotations: - openshift.io/description: ${PROJECT_DESCRIPTION} - openshift.io/display-name: ${PROJECT_DISPLAYNAME} - extra: here - creationTimestamp: null - name: ${PROJECT_NAME} - spec: {} - status: {} -- apiVersion: v1 - kind: ResourceQuota + name: aadda50d-d92c-402d-bd29-5ed2095aad2c + namespace: ${NAMESPACE} + +- apiVersion: template.openshift.io/v1 + kind: TemplateInstance metadata: - name: ${PROJECT_NAME}-quota + name: aadda50d-d92c-402d-bd29-5ed2095aad2c + namespace: ${NAMESPACE} spec: - hard: - cpu: 200m - memory: 512Mi - pods: 3 - replicationcontrollers: 3 - resourcequotas: 1 - services: 3 -- apiVersion: v1 - kind: LimitRange + template: + apiVersion: v1 + kind: Template + metadata: + uid: d261a5c9-db37-40b5-ac0f-5709e0e3aac4 + objects: + - apiVersion: v1 + data: + username: configmap-username + kind: ConfigMap + metadata: + annotations: + template.openshift.io/expose-configmap-username: "{.data['username']}" + name: configmap + - apiVersion: v1 + kind: Secret + metadata: + annotations: + template.openshift.io/base64-expose-secret-password: "{.data['password']}" + template.openshift.io/expose-secret-username: "{.data['username']}" + name: secret + stringData: + password: secret-password + username: secret-username + - apiVersion: v1 + kind: Service + metadata: + annotations: + template.openshift.io/expose-service-uri: http://{.spec.clusterIP}:{.spec.ports[?(.name=="port")].port} + name: service + spec: + ports: + - name: port + port: 1234 + - apiVersion: v1 + kind: Route + metadata: + annotations: + template.openshift.io/expose-route-uri: http://{.spec.host}{.spec.path} + name: route + spec: + host: host + path: /path + to: + kind: Service + name: service + +- apiVersion: template.openshift.io/v1 + kind: BrokerTemplateInstance metadata: - creationTimestamp: null - name: ${PROJECT_NAME}-limits + name: aadda50d-d92c-402d-bd29-5ed2095aad2c spec: - limits: - - max: - cpu: 500m - memory: 750Mi - min: - cpu: 10m - memory: 5Mi - type: Pod - - default: - cpu: 100m - memory: 100Mi - max: - cpu: 500m - memory: 750Mi - min: - cpu: 10m - memory: 5Mi - type: Container -- apiVersion: v1 - groupNames: [] - kind: RoleBinding - metadata: - creationTimestamp: null - name: admins - namespace: ${PROJECT_NAME} - roleRef: - name: admin - subjects: - - kind: User - name: ${PROJECT_ADMIN_USER} - userNames: - - ${PROJECT_ADMIN_USER} -- apiVersion: v1 - groupNames: - - system:serviceaccounts:${PROJECT_NAME} - kind: RoleBinding - metadata: - creationTimestamp: null - name: system:image-pullers - namespace: ${PROJECT_NAME} - roleRef: - name: system:image-puller - subjects: - - kind: SystemGroup - name: system:serviceaccounts:${PROJECT_NAME} - userNames: [] -- apiVersion: v1 - groupNames: [] - kind: RoleBinding - metadata: - creationTimestamp: null - name: system:image-builders - namespace: ${PROJECT_NAME} - roleRef: - name: system:image-builder - subjects: - - kind: ServiceAccount - name: builder - userNames: - - system:serviceaccount:${PROJECT_NAME}:builder -- apiVersion: v1 - groupNames: [] - kind: RoleBinding - metadata: - creationTimestamp: null - name: system:deployers - namespace: ${PROJECT_NAME} - roleRef: - name: system:deployer - subjects: - - kind: ServiceAccount - name: deployer - userNames: - - system:serviceaccount:${PROJECT_NAME}:deployer + templateInstance: + apiVersion: template.openshift.io/v1 + kind: TemplateInstance + name: aadda50d-d92c-402d-bd29-5ed2095aad2c + namespace: ${NAMESPACE} + + secret: + apiVersion: v1 + kind: Secret + name: aadda50d-d92c-402d-bd29-5ed2095aad2c + namespace: ${NAMESPACE} + parameters: -- name: PROJECT_NAME -- name: PROJECT_DISPLAYNAME -- name: PROJECT_DESCRIPTION -- name: PROJECT_ADMIN_USER +- name: NAMESPACE + required: true `) -func testIntegrationTestdataProjectRequestTemplateWithQuotaYamlBytes() ([]byte, error) { - return _testIntegrationTestdataProjectRequestTemplateWithQuotaYaml, nil +func testExtendedTestdataTemplatesTemplateservicebroker_bindYamlBytes() ([]byte, error) { + return _testExtendedTestdataTemplatesTemplateservicebroker_bindYaml, nil } -func testIntegrationTestdataProjectRequestTemplateWithQuotaYaml() (*asset, error) { - bytes, err := testIntegrationTestdataProjectRequestTemplateWithQuotaYamlBytes() +func testExtendedTestdataTemplatesTemplateservicebroker_bindYaml() (*asset, error) { + bytes, err := testExtendedTestdataTemplatesTemplateservicebroker_bindYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/integration/testdata/project-request-template-with-quota.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/templates/templateservicebroker_bind.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testIntegrationTestdataTestBuildcliBeta2Json = []byte(`{ - "kind": "List", - "apiVersion": "v1", - "metadata": {}, - "items": [ - { - "kind": "ImageStream", - "apiVersion": "v1", - "metadata": { - "name": "ruby-22-centos-buildcli", - "creationTimestamp": null - }, - "spec": { - "dockerImageRepository": "centos/ruby-22-centos", - "tags": [ - { - "name": "valid" - } - ] - }, - "status": { - "dockerImageRepository": "" - } - }, - { - "kind": "BuildConfig", - "apiVersion": "v1", - "metadata": { - "name": "ruby-sample-build-validtag", - "creationTimestamp": null - }, - "spec": { - "triggers": [ - { - "type": "imageChange", - "imageChange": {} - } - ], - "source": { - "type": "Git", - "git": { - "uri": "git://github.com/openshift/ruby-hello-world.git" - } - }, - "strategy": { - "type": "Source", - "sourceStrategy": { - "from": { - "kind": "ImageStreamTag", - "name": "ruby-22-centos-buildcli:valid" - }, - "incremental": true - } - }, - "output": { - "to": { - "kind": "ImageStreamTag", - "name": "origin-ruby-sample:latest" - } - }, - "resources": {} - }, - "status": { - "lastVersion": 0 - } - }, - { - "kind": "BuildConfig", - "apiVersion": "v1", - "metadata": { - "name": "ruby-sample-build-invalidtag", - "creationTimestamp": null - }, - "spec": { - "triggers": [ - { - "type": "imageChange", - "imageChange": {} - } - ], - "source": { - "type": "Git", - "git": { - "uri": "git://github.com/openshift/ruby-hello-world.git" - } - }, - "strategy": { - "type": "Source", - "sourceStrategy": { - "from": { - "kind": "ImageStreamTag", - "name": "ruby-22-centos-buildcli:invalid" - }, - "incremental": true - } - }, - "output": { - "to": { - "kind": "ImageStreamTag", - "name": "origin-ruby-sample:latest" - } - }, - "resources": {} - }, - "status": { - "lastVersion": 0 - } - } - ] -} -`) +var _testExtendedTestdataTestCliDebugYaml = []byte(`kind: List +apiVersion: v1 +items: +- kind: ImageStream + apiVersion: v1 + metadata: + name: local-busybox -func testIntegrationTestdataTestBuildcliBeta2JsonBytes() ([]byte, error) { - return _testIntegrationTestdataTestBuildcliBeta2Json, nil -} +- kind: BuildConfig + apiVersion: v1 + metadata: + name: local-busybox + spec: + strategy: + type: Docker + source: + type: Git + dockerfile: "FROM image-registry.openshift-image-registry.svc:5000/openshift/tools:latest\n" + output: + to: + kind: ImageStreamTag + name: local-busybox:latest + triggers: + - type: ConfigChange -func testIntegrationTestdataTestBuildcliBeta2Json() (*asset, error) { - bytes, err := testIntegrationTestdataTestBuildcliBeta2JsonBytes() - if err != nil { - return nil, err - } +- kind: DeploymentConfig + apiVersion: v1 + metadata: + name: local-busybox1 + spec: + replicas: 0 + selector: + deploymentconfig: local-busybox1 + template: + metadata: + labels: + deploymentconfig: local-busybox1 + spec: + containers: + - name: local-busybox + triggers: + - type: ImageChange + imageChangeParams: + automatic: true + containerNames: + - local-busybox + from: + kind: ImageStreamTag + name: local-busybox:latest - info := bindataFileInfo{name: "test/integration/testdata/test-buildcli-beta2.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} +- kind: DeploymentConfig + apiVersion: v1 + metadata: + name: local-busybox2 + spec: + replicas: 0 + selector: + deploymentconfig: local-busybox2 + template: + metadata: + labels: + deploymentconfig: local-busybox2 + spec: + containers: + - name: local-busybox + command: + - foo + - bar + args: + - baz + - qux + triggers: + - type: ImageChange + imageChangeParams: + automatic: true + containerNames: + - local-busybox + from: + kind: ImageStreamTag + name: local-busybox:latest -var _testIntegrationTestdataTestBuildcliJson = []byte(`{ - "kind": "List", - "apiVersion": "v1", - "metadata": {}, - "items": [ - { - "kind": "ImageStream", - "apiVersion": "v1", - "metadata": { - "name": "ruby-20-centos7-buildcli", - "creationTimestamp": null - }, - "spec": { - "dockerImageRepository": "centos/ruby-25-centos7", - "tags": [ - { - "name": "valid" - } - ] - }, - "status": { - "dockerImageRepository": "" - } - }, - { - "kind": "BuildConfig", - "apiVersion": "v1", - "metadata": { - "name": "ruby-sample-build-validtag", - "creationTimestamp": null - }, - "spec": { - "triggers": [ - { - "type": "imageChange", - "imageChange": {} - } - ], - "source": { - "type": "Git", - "git": { - "uri": "git://github.com/openshift/ruby-hello-world.git" - } - }, - "strategy": { - "type": "Source", - "sourceStrategy": { - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/ruby-25-rhel7:latest" - }, - "incremental": true - } - }, - "output": { - "to": { - "kind": "ImageStreamTag", - "name": "origin-ruby-sample:latest" - } - }, - "resources": {} - }, - "status": { - "lastVersion": 0 - } - }, - { - "kind": "BuildConfig", - "apiVersion": "v1", - "metadata": { - "name": "ruby-sample-build-invalidtag", - "creationTimestamp": null - }, - "spec": { - "triggers": [ - { - "type": "imageChange", - "imageChange": {} - } - ], - "source": { - "type": "Git", - "git": { - "uri": "git://github.com/openshift/ruby-hello-world.git" - } - }, - "strategy": { - "type": "Source", - "sourceStrategy": { - "from": { - "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/ruby-25-rhel7:latest" - }, - "incremental": true - } - }, - "output": { - "to": { - "kind": "ImageStreamTag", - "name": "origin-ruby-sample:latest" - } - }, - "resources": {} - }, - "status": { - "lastVersion": 0 - } - } - ] -} +- kind: DeploymentConfig + apiVersion: v1 + metadata: + name: busybox1 + spec: + replicas: 0 + selector: + deploymentconfig: busybox1 + template: + metadata: + labels: + deploymentconfig: busybox1 + spec: + containers: + - name: busybox + image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest + +- kind: DeploymentConfig + apiVersion: v1 + metadata: + name: busybox2 + spec: + replicas: 0 + selector: + deploymentconfig: busybox2 + template: + metadata: + labels: + deploymentconfig: busybox2 + spec: + containers: + - name: busybox + image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest + command: + - foo + - bar + args: + - baz + - qux `) -func testIntegrationTestdataTestBuildcliJsonBytes() ([]byte, error) { - return _testIntegrationTestdataTestBuildcliJson, nil +func testExtendedTestdataTestCliDebugYamlBytes() ([]byte, error) { + return _testExtendedTestdataTestCliDebugYaml, nil } -func testIntegrationTestdataTestBuildcliJson() (*asset, error) { - bytes, err := testIntegrationTestdataTestBuildcliJsonBytes() +func testExtendedTestdataTestCliDebugYaml() (*asset, error) { + bytes, err := testExtendedTestdataTestCliDebugYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/integration/testdata/test-buildcli.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/test-cli-debug.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testIntegrationTestdataTestDeploymentConfigYaml = []byte(`apiVersion: v1 +var _testExtendedTestdataTestDeploymentConfigYaml = []byte(`apiVersion: v1 kind: DeploymentConfig metadata: name: test-deployment-config @@ -61108,7 +53630,7 @@ spec: name: test-deployment spec: containers: - - image: openshift/origin-pod + - image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest imagePullPolicy: IfNotPresent name: ruby-helloworld ports: @@ -61125,132 +53647,286 @@ spec: name: vol1 triggers: - type: ConfigChange -status: {} `) -func testIntegrationTestdataTestDeploymentConfigYamlBytes() ([]byte, error) { - return _testIntegrationTestdataTestDeploymentConfigYaml, nil +func testExtendedTestdataTestDeploymentConfigYamlBytes() ([]byte, error) { + return _testExtendedTestdataTestDeploymentConfigYaml, nil } -func testIntegrationTestdataTestDeploymentConfigYaml() (*asset, error) { - bytes, err := testIntegrationTestdataTestDeploymentConfigYamlBytes() +func testExtendedTestdataTestDeploymentConfigYaml() (*asset, error) { + bytes, err := testExtendedTestdataTestDeploymentConfigYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/integration/testdata/test-deployment-config.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/test-deployment-config.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testIntegrationTestdataTestImageStreamMappingJson = []byte(`{ - "kind": "ImageStreamMapping", - "apiVersion": "v1", - "metadata": { - "name": "test", - "creationTimestamp": null - }, - "image": { - "metadata": { - "name": "sha256:4986bf8c15363d1c5d15512d5266f8777bfba4974ac56e3270e7760f6f0a8125", - "creationTimestamp": null - }, - "dockerImageReference": "openshift/ruby-19-centos:latest", - "dockerImageMetadata": { - "kind": "DockerImage", - "apiVersion": "1.0", - "Id": "", - "Created": null, - "ContainerConfig": {}, - "Config": {} - }, - "dockerImageMetadataVersion": "1.0", - "dockerImageManifest": "{\n \"name\": \"library/busybox\",\n \"tag\": \"latest\",\n \"architecture\": \"amd64\",\n \"fsLayers\": [\n {\n \"blobSum\": \"tarsum.dev+sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\"\n },\n {\n \"blobSum\": \"tarsum.dev+sha256:d43a7079c4dd020e9c65419c2eb6751ea49d6f7f9337edd895596cd5f7aa6369\"\n },\n {\n \"blobSum\": \"tarsum.dev+sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\"\n },\n {\n \"blobSum\": \"tarsum.dev+sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\"\n }\n ],\n \"history\": [\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"4986bf8c15363d1c5d15512d5266f8777bfba4974ac56e3270e7760f6f0a8125\\\",\\\"parent\\\":\\\"ea13149945cb6b1e746bf28032f02e9b5a793523481a0a18645fc77ad53c4ea2\\\",\\\"created\\\":\\\"2014-12-31T22:23:56.943403668Z\\\",\\\"container\\\":\\\"83dcf36ad1042b90f4ea8b2ebb60e61b2f1a451a883e04b388be299ad382b259\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"7f674915980d\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"Memory\\\":0,\\\"MemorySwap\\\":0,\\\"CpuShares\\\":0,\\\"Cpuset\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"PortSpecs\\\":null,\\\"ExposedPorts\\\":null,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) CMD [/bin/sh]\\\"],\\\"Image\\\":\\\"ea13149945cb6b1e746bf28032f02e9b5a793523481a0a18645fc77ad53c4ea2\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"NetworkDisabled\\\":false,\\\"MacAddress\\\":\\\"\\\",\\\"OnBuild\\\":[]},\\\"docker_version\\\":\\\"1.4.1\\\",\\\"author\\\":\\\"Jerome Petazzoni \\\\u003cjerome@docker.com\\\\u003e\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"7f674915980d\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"Memory\\\":0,\\\"MemorySwap\\\":0,\\\"CpuShares\\\":0,\\\"Cpuset\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"PortSpecs\\\":null,\\\"ExposedPorts\\\":null,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\"],\\\"Image\\\":\\\"ea13149945cb6b1e746bf28032f02e9b5a793523481a0a18645fc77ad53c4ea2\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"NetworkDisabled\\\":false,\\\"MacAddress\\\":\\\"\\\",\\\"OnBuild\\\":[]},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\",\\\"checksum\\\":\\\"tarsum.dev+sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\\\",\\\"Size\\\":0}\\n\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"ea13149945cb6b1e746bf28032f02e9b5a793523481a0a18645fc77ad53c4ea2\\\",\\\"parent\\\":\\\"df7546f9f060a2268024c8a230d8639878585defcc1bc6f79d2728a13957871b\\\",\\\"created\\\":\\\"2014-12-31T22:23:56.190797792Z\\\",\\\"container\\\":\\\"7f674915980dbcafb3096fa82369c2943194486dcb4e585e3490a2e66c530e44\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"7f674915980d\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"Memory\\\":0,\\\"MemorySwap\\\":0,\\\"CpuShares\\\":0,\\\"Cpuset\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"PortSpecs\\\":null,\\\"ExposedPorts\\\":null,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) ADD file:8cf517d90fe79547c474641cc1e6425850e04abbd8856718f7e4a184ea878538 in /\\\"],\\\"Image\\\":\\\"df7546f9f060a2268024c8a230d8639878585defcc1bc6f79d2728a13957871b\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"NetworkDisabled\\\":false,\\\"MacAddress\\\":\\\"\\\",\\\"OnBuild\\\":[]},\\\"docker_version\\\":\\\"1.4.1\\\",\\\"author\\\":\\\"Jerome Petazzoni \\\\u003cjerome@docker.com\\\\u003e\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"7f674915980d\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"Memory\\\":0,\\\"MemorySwap\\\":0,\\\"CpuShares\\\":0,\\\"Cpuset\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"PortSpecs\\\":null,\\\"ExposedPorts\\\":null,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":null,\\\"Image\\\":\\\"df7546f9f060a2268024c8a230d8639878585defcc1bc6f79d2728a13957871b\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"NetworkDisabled\\\":false,\\\"MacAddress\\\":\\\"\\\",\\\"OnBuild\\\":[]},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\",\\\"checksum\\\":\\\"tarsum.dev+sha256:d43a7079c4dd020e9c65419c2eb6751ea49d6f7f9337edd895596cd5f7aa6369\\\",\\\"Size\\\":2433303}\\n\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"df7546f9f060a2268024c8a230d8639878585defcc1bc6f79d2728a13957871b\\\",\\\"parent\\\":\\\"511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158\\\",\\\"created\\\":\\\"2014-10-01T20:46:07.263351912Z\\\",\\\"container\\\":\\\"2147a17cb1b2d6626ed78e5ef8ba4c71ce82c884bc3b57ab01e6114ff357cea4\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"2147a17cb1b2\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"Memory\\\":0,\\\"MemorySwap\\\":0,\\\"CpuShares\\\":0,\\\"Cpuset\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"PortSpecs\\\":null,\\\"ExposedPorts\\\":null,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) MAINTAINER Jerome Petazzoni \\\\u003cjerome@docker.com\\\\u003e\\\"],\\\"Image\\\":\\\"511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"NetworkDisabled\\\":false,\\\"MacAddress\\\":\\\"\\\",\\\"OnBuild\\\":[]},\\\"docker_version\\\":\\\"1.2.0\\\",\\\"author\\\":\\\"Jerome Petazzoni \\\\u003cjerome@docker.com\\\\u003e\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"2147a17cb1b2\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"Memory\\\":0,\\\"MemorySwap\\\":0,\\\"CpuShares\\\":0,\\\"Cpuset\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"PortSpecs\\\":null,\\\"ExposedPorts\\\":null,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":null,\\\"Image\\\":\\\"511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"NetworkDisabled\\\":false,\\\"MacAddress\\\":\\\"\\\",\\\"OnBuild\\\":[]},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\",\\\"checksum\\\":\\\"tarsum.dev+sha256:1b755912c77197c6a43539f2a708ef89d5849b8ce02642cb702e47afaa8195c3\\\",\\\"Size\\\":0}\\n\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158\\\",\\\"comment\\\":\\\"Imported from -\\\",\\\"created\\\":\\\"2013-06-13T14:03:50.821769-07:00\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"Memory\\\":0,\\\"MemorySwap\\\":0,\\\"CpuShares\\\":0,\\\"Cpuset\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"PortSpecs\\\":null,\\\"ExposedPorts\\\":null,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":null,\\\"Cmd\\\":null,\\\"Image\\\":\\\"\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"NetworkDisabled\\\":false,\\\"MacAddress\\\":\\\"\\\",\\\"OnBuild\\\":null},\\\"docker_version\\\":\\\"0.4.0\\\",\\\"architecture\\\":\\\"x86_64\\\",\\\"checksum\\\":\\\"tarsum.dev+sha256:324d4cf44ee7daa46266c1df830c61a7df615c0632176a339e7310e34723d67a\\\",\\\"Size\\\":0}\\n\"\n }\n ],\n \"schemaVersion\": 1,\n \"signatures\": [\n {\n \"header\": {\n \"jwk\": {\n \"crv\": \"P-256\",\n \"kid\": \"OIH7:HQFS:44FK:45VB:3B53:OIAG:TPL4:ATF5:6PNE:MGHN:NHQX:2GE4\",\n \"kty\": \"EC\",\n \"x\": \"Cu_UyxwLgHzE9rvlYSmvVdqYCXY42E9eNhBb0xNv0SQ\",\n \"y\": \"zUsjWJkeKQ5tv7S-hl1Tg71cd-CqnrtiiLxSi6N_yc8\"\n },\n \"alg\": \"ES256\"\n },\n \"signature\": \"bWiisabH8LgSXezUhjN8X3I7ESBo_fCXvFtqAwRmzozTfPHTr8edd13SU0KUJMq4X7_agEuLpSh1V8YGcBVpYg\",\n \"protected\": \"eyJmb3JtYXRMZW5ndGgiOjcwNjMsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxNS0wMy0zMVQxNjozMjoyOVoifQ\"\n }\n ]\n}" +var _testExtendedTestdataTestEnvPodJson = []byte(`{ + "kind":"Pod", + "apiVersion":"v1", + "metadata":{ + "name":"test-pod", + "labels":{ + "name":"test-pod" + } }, - "tag": "sometag" -}`) + "spec":{ + "containers":[ + { + "name":"test", + "image":"image-registry.openshift-image-registry.svc:5000/openshift/tools:latest", + "env": [ + { + "name":"podname", + "valueFrom": { + "fieldRef": { + "fieldPath":"metadata.name" + } + } + }, + { + "name":"podname_composed", + "value":"$(podname)_composed" + }, + { + "name":"var1", + "value":"value1" + }, + { + "name":"var2", + "value":"$(var1)" + }, + { + "name":"var3", + "value":"120" + } + ], + "command": [ + "sleep", + "$(var3)" + ] + } + ], + "restartPolicy":"Never", + "dnsPolicy":"ClusterFirst" + } +} +`) -func testIntegrationTestdataTestImageStreamMappingJsonBytes() ([]byte, error) { - return _testIntegrationTestdataTestImageStreamMappingJson, nil +func testExtendedTestdataTestEnvPodJsonBytes() ([]byte, error) { + return _testExtendedTestdataTestEnvPodJson, nil } -func testIntegrationTestdataTestImageStreamMappingJson() (*asset, error) { - bytes, err := testIntegrationTestdataTestImageStreamMappingJsonBytes() +func testExtendedTestdataTestEnvPodJson() (*asset, error) { + bytes, err := testExtendedTestdataTestEnvPodJsonBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/integration/testdata/test-image-stream-mapping.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/test-env-pod.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testIntegrationTestdataTestImageStreamJson = []byte(`{ - "kind": "ImageStream", - "apiVersion": "v1", - "metadata": { - "name": "test", - "creationTimestamp": null, - "labels": { - "color": "blue" - } - }, - "spec": {}, - "status": { - "dockerImageRepository": "" - } -}`) +var _testExtendedTestdataTestGitserverYaml = []byte(`apiVersion: v1 +kind: Template +labels: + template: gitserver +metadata: + name: gitserver +objects: +# The gitserver is deployed as a singleton pod and uses a very small amount +# of resources. It can host or transiently serve Git repositories, as well +# as automatically integrate with builds in a namespace. +- apiVersion: v1 + kind: DeploymentConfig + metadata: + name: gitserver + labels: + app: gitserver + spec: + replicas: 1 # the gitserver is not HA and should not be scaled past 1 + selector: + run-container: gitserver + template: + metadata: + labels: + run-container: gitserver + spec: + containers: + - name: gitserver + image: openshift/origin-gitserver + readinessProbe: + tcpSocket: + port: 8080 + ports: + - containerPort: 8080 -func testIntegrationTestdataTestImageStreamJsonBytes() ([]byte, error) { - return _testIntegrationTestdataTestImageStreamJson, nil -} + env: + # Each environment variable matching GIT_INITIAL_CLONE_* will + # be cloned when the process starts; failures will be logged. + # must be [A-Z0-9_\-\.], the cloned directory name will + # be lowercased. If the name is invalid the pod will halt. If + # the repository already exists on disk, it will be updated + # from the remote. + # + - name: GIT_INITIAL_CLONE_1 + value: https://github.com/openshift/ruby-hello-world.git;ruby-hello-world -func testIntegrationTestdataTestImageStreamJson() (*asset, error) { - bytes, err := testIntegrationTestdataTestImageStreamJsonBytes() - if err != nil { - return nil, err - } - info := bindataFileInfo{name: "test/integration/testdata/test-image-stream.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} + # The namespace of the pod is required for implicit config + # (passing '-' to AUTOLINK_KUBECONFIG or REQUIRE_SERVER_AUTH) + # and can also be used to target a specific namespace. + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace -var _testIntegrationTestdataTestImageJson = []byte(`{ - "kind": "Image", - "apiVersion": "image.openshift.io/v1", - "metadata": { - "name": "test", - "creationTimestamp": null - }, - "dockerImageReference": "openshift/ruby-19-centos:latest", - "dockerImageMetadata": { - "kind": "DockerImage", - "apiVersion": "1.0", - "Id": "", - "ContainerConfig": {}, - "Config": {} - }, - "dockerImageMetadataVersion": "1.0" -} + # The URL that builds must use to access the Git repositories + # stored in this app. + # TODO: support HTTPS + - name: PUBLIC_URL + value: http://gitserver.$(POD_NAMESPACE).svc.cluster.local:8080 + # The directory to store Git repositories in. If not backed + # by a persistent volume, repositories will be lost when + # deployments occur. Use INITIAL_GIT_CLONE and AUTOLINK_* + # to remove the need to use a persistent volume. + - name: GIT_HOME + value: /var/lib/git + # The directory to use as the default hook directory for any + # cloned or autolinked directories. + - name: HOOK_PATH + value: /var/lib/git-hooks + + # Authentication and authorization + + # If 'yes', clients may push to the server with git push. + - name: ALLOW_GIT_PUSH + value: "yes" + # If 'yes', clients may set hooks via the API. However, unless + # the Git home is backed by a persistent volume, any deployment + # will result in the hooks being lost. + - name: ALLOW_GIT_HOOKS + value: "yes" + # If 'yes', clients can create new git repositories on demand + # by pushing. If the data on disk is not backed by a persistent + # volume, the Git repo will be deleted if the deployment is + # updated. + - name: ALLOW_LAZY_CREATE + value: "yes" + # If 'yes', clients can pull without being authenticated. + - name: ALLOW_ANON_GIT_PULL + + # Provides the path to a kubeconfig file in the image that + # should be used to authorize against the server. The value + # '-' will use the pod's service account. + # May not be used in combination with REQUIRE_GIT_AUTH + #- name: REQUIRE_SERVER_AUTH + # value: "-" + + # The namespace to check authorization against when + # REQUIRE_SERVICE_AUTH is used. Users must have 'get' on + # 'pods' to pull and 'create' on 'pods' to push. + - name: AUTH_NAMESPACE + value: $(POD_NAMESPACE) + # Require BASIC authentication with a username and password + # to push or pull. + # May not be used in combination with REQUIRE_SERVER_AUTH + - name: REQUIRE_GIT_AUTH + value: gituser:gituserpassword + + # Autolinking: + # + # The gitserver can automatically clone Git repositories + # associated with a build config and replace the URL with + # a link to the repo on PUBLIC_URL. The default post-receive + # hook on the cloned repo will then trigger a build. You + # may customize the hook with AUTOLINK_HOOK (path to hook). + # To autolink, the account the pod runs under must have 'edit' + # on the AUTOLINK_NAMESPACE: + # + # oc policy add-role-to-user \ + # system:serviceaccount:${namespace}:gitserver edit + # + # Links are checked every time the pod starts. + + # The location to read auth configuration from for autolinking. + # If '-', use the service account token to link. The account + # represented by this config must have the edit role on the + # namespace. + #- name: AUTOLINK_KUBECONFIG + # value: "-" + + # The namespace to autolink + #- name: AUTOLINK_NAMESPACE + # value: $(POD_NAMESPACE) + + # The path to a script in the image to use as the default + # post-receive hook - only set during link, so has no effect + # on cloned repositories. See the "hooks" directory in the + # image for examples. + #- name: AUTOLINK_HOOK + + # The master service host is not signed with the service IP + # so we override with the consistent DNS name. Required for + # connections to the server. + - name: KUBERNETES_SERVICE_HOST + value: kubernetes.default + + volumeMounts: + - mountPath: /var/lib/git/ + name: git + volumes: + - name: git + triggers: + - type: ConfigChange + +# The gitserver service is required for DNS resolution +- apiVersion: v1 + kind: Service + metadata: + name: gitserver + labels: + app: gitserver + spec: + ports: + - port: 8080 + targetPort: 8080 + selector: + run-container: gitserver +- apiVersion: v1 + kind: Route + metadata: + name: gitserver + labels: + app: gitserver + spec: + tls: + termination: edge + to: + kind: Service + name: gitserver `) -func testIntegrationTestdataTestImageJsonBytes() ([]byte, error) { - return _testIntegrationTestdataTestImageJson, nil +func testExtendedTestdataTestGitserverYamlBytes() ([]byte, error) { + return _testExtendedTestdataTestGitserverYaml, nil } -func testIntegrationTestdataTestImageJson() (*asset, error) { - bytes, err := testIntegrationTestdataTestImageJsonBytes() +func testExtendedTestdataTestGitserverYaml() (*asset, error) { + bytes, err := testExtendedTestdataTestGitserverYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/integration/testdata/test-image.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/test-gitserver.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testIntegrationTestdataTestReplicationControllerYaml = []byte(`apiVersion: v1 +var _testExtendedTestdataTestReplicationControllerYaml = []byte(`apiVersion: v1 kind: ReplicationController metadata: annotations: @@ -61271,7 +53947,7 @@ spec: deploymentconfig: test-deployment spec: containers: - - image: openshift/origin-pod + - image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest imagePullPolicy: IfNotPresent name: ruby-helloworld ports: @@ -61283,144 +53959,111 @@ spec: status: {} `) -func testIntegrationTestdataTestReplicationControllerYamlBytes() ([]byte, error) { - return _testIntegrationTestdataTestReplicationControllerYaml, nil -} - -func testIntegrationTestdataTestReplicationControllerYaml() (*asset, error) { - bytes, err := testIntegrationTestdataTestReplicationControllerYamlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "test/integration/testdata/test-replication-controller.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _testIntegrationTestdataTestRouteJson = []byte(`{ - "kind": "Route", - "apiVersion": "v1", - "metadata": { - "name": "testroute", - "creationTimestamp": null, - "labels": { - "rtlabel1": "greatroute" - } - }, - "spec": { - "host": "test.example.com", - "to": { - "kind": "Service", - "name": "testservice" - } - }, - "status": {} -} -`) - -func testIntegrationTestdataTestRouteJsonBytes() ([]byte, error) { - return _testIntegrationTestdataTestRouteJson, nil +func testExtendedTestdataTestReplicationControllerYamlBytes() ([]byte, error) { + return _testExtendedTestdataTestReplicationControllerYaml, nil } -func testIntegrationTestdataTestRouteJson() (*asset, error) { - bytes, err := testIntegrationTestdataTestRouteJsonBytes() +func testExtendedTestdataTestReplicationControllerYaml() (*asset, error) { + bytes, err := testExtendedTestdataTestReplicationControllerYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/integration/testdata/test-route.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/test-replication-controller.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testIntegrationTestdataTestServiceWithFinalizerJson = []byte(`{ - "kind": "Service", +var _testExtendedTestdataTestSecretJson = []byte(`{ + "kind": "Secret", "apiVersion": "v1", "metadata": { - "name": "frontend", - "creationTimestamp": null, - "labels": { - "name": "frontend" - }, - "finalizers": ["fake/one"] + "name": "docker", + "creationTimestamp": null }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 9998, - "targetPort": 9998, - "nodePort": 0 - } - ], - "selector": { - "name": "frontend" - }, - "type": "ClusterIP", - "sessionAffinity": "None" + "data": { + "dockercfg": "eyJodHRwczovL3JlZ2lzdHJ5aG9zdC92MSI6eyJhdXRoIjoic2VjcmV0IiwiZW1haWwiOiJqb2huQGRvZS5jb20ifX0K" }, - "status": { - "loadBalancer": {} - } + "type": "Opaque" }`) -func testIntegrationTestdataTestServiceWithFinalizerJsonBytes() ([]byte, error) { - return _testIntegrationTestdataTestServiceWithFinalizerJson, nil +func testExtendedTestdataTestSecretJsonBytes() ([]byte, error) { + return _testExtendedTestdataTestSecretJson, nil } -func testIntegrationTestdataTestServiceWithFinalizerJson() (*asset, error) { - bytes, err := testIntegrationTestdataTestServiceWithFinalizerJsonBytes() +func testExtendedTestdataTestSecretJson() (*asset, error) { + bytes, err := testExtendedTestdataTestSecretJsonBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/integration/testdata/test-service-with-finalizer.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/test-secret.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } -var _testIntegrationTestdataTestServiceJson = []byte(`{ - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "frontend", - "creationTimestamp": null, - "labels": { - "name": "frontend" - } - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 9998, - "targetPort": 9998, - "nodePort": 0 - } - ], - "selector": { - "name": "frontend" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } -}`) +var _testExtendedTestdataVerifyservicePipelineTemplateYaml = []byte(`apiVersion: v1 +kind: Template +labels: + template: jenkins-verifyservice-pipeline +metadata: + name: redis-verifyservice-test + app: redis +objects: +- apiVersion: v1 + kind: Service + metadata: + name: redis-headless + app: redis + spec: + clusterIP: None + ports: + - port: 6379 + targetPort: 6379 + selector: + name: redis +- apiVersion: v1 + kind: BuildConfig + metadata: + name: jenkins-verifyservice-pipeline + app: redis + spec: + strategy: + jenkinsPipelineStrategy: + jenkinsfile: |- + try { + timeout(time: 20, unit: 'MINUTES') { + // Select the default cluster + openshift.withCluster() { + // Select the default project + openshift.withProject() { + // Verify Normal Services + def connectedNormalService = openshift.verifyService('redis') + // Verify Headless Services with Selectors + def connectedHeadlessService = openshift.verifyService('redis-headless') + } + } + } + } catch (err) { + echo "in catch block" + echo "Caught: ${err}" + currentBuild.result = 'FAILURE' + throw err + } + type: JenkinsPipeline +`) -func testIntegrationTestdataTestServiceJsonBytes() ([]byte, error) { - return _testIntegrationTestdataTestServiceJson, nil +func testExtendedTestdataVerifyservicePipelineTemplateYamlBytes() ([]byte, error) { + return _testExtendedTestdataVerifyservicePipelineTemplateYaml, nil } -func testIntegrationTestdataTestServiceJson() (*asset, error) { - bytes, err := testIntegrationTestdataTestServiceJsonBytes() +func testExtendedTestdataVerifyservicePipelineTemplateYaml() (*asset, error) { + bytes, err := testExtendedTestdataVerifyservicePipelineTemplateYamlBytes() if err != nil { return nil, err } - info := bindataFileInfo{name: "test/integration/testdata/test-service.json", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + info := bindataFileInfo{name: "test/extended/testdata/verifyservice-pipeline-template.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -61477,545 +54120,496 @@ func AssetNames() []string { // _bindata is a table, holding each asset generator, mapped to its name. var _bindata = map[string]func() (*asset, error){ - "examples/db-templates/mariadb-ephemeral-template.json": examplesDbTemplatesMariadbEphemeralTemplateJson, - "examples/db-templates/mariadb-persistent-template.json": examplesDbTemplatesMariadbPersistentTemplateJson, - "examples/db-templates/mongodb-ephemeral-template.json": examplesDbTemplatesMongodbEphemeralTemplateJson, - "examples/db-templates/mongodb-persistent-template.json": examplesDbTemplatesMongodbPersistentTemplateJson, - "examples/db-templates/mysql-ephemeral-template.json": examplesDbTemplatesMysqlEphemeralTemplateJson, - "examples/db-templates/mysql-persistent-template.json": examplesDbTemplatesMysqlPersistentTemplateJson, - "examples/db-templates/postgresql-ephemeral-template.json": examplesDbTemplatesPostgresqlEphemeralTemplateJson, - "examples/db-templates/postgresql-persistent-template.json": examplesDbTemplatesPostgresqlPersistentTemplateJson, - "examples/db-templates/redis-ephemeral-template.json": examplesDbTemplatesRedisEphemeralTemplateJson, - "examples/db-templates/redis-persistent-template.json": examplesDbTemplatesRedisPersistentTemplateJson, - "examples/image-streams/image-streams-centos7.json": examplesImageStreamsImageStreamsCentos7Json, - "examples/image-streams/image-streams-rhel7.json": examplesImageStreamsImageStreamsRhel7Json, - "examples/sample-app/application-template-dockerbuild.json": examplesSampleAppApplicationTemplateDockerbuildJson, - "examples/sample-app/application-template-pullspecbuild.json": examplesSampleAppApplicationTemplatePullspecbuildJson, - "examples/sample-app/application-template-stibuild.json": examplesSampleAppApplicationTemplateStibuildJson, - "examples/sample-app/cleanup.sh": examplesSampleAppCleanupSh, - "examples/sample-app/github-webhook-example.json": examplesSampleAppGithubWebhookExampleJson, - "examples/quickstarts/cakephp-mysql-persistent.json": examplesQuickstartsCakephpMysqlPersistentJson, - "examples/quickstarts/cakephp-mysql.json": examplesQuickstartsCakephpMysqlJson, - "examples/quickstarts/dancer-mysql-persistent.json": examplesQuickstartsDancerMysqlPersistentJson, - "examples/quickstarts/dancer-mysql.json": examplesQuickstartsDancerMysqlJson, - "examples/quickstarts/django-postgresql-persistent.json": examplesQuickstartsDjangoPostgresqlPersistentJson, - "examples/quickstarts/django-postgresql.json": examplesQuickstartsDjangoPostgresqlJson, - "examples/quickstarts/dotnet-pgsql-persistent.json": examplesQuickstartsDotnetPgsqlPersistentJson, - "examples/quickstarts/dotnet.json": examplesQuickstartsDotnetJson, - "examples/quickstarts/httpd.json": examplesQuickstartsHttpdJson, - "examples/quickstarts/nginx.json": examplesQuickstartsNginxJson, - "examples/quickstarts/nodejs-mongodb-persistent.json": examplesQuickstartsNodejsMongodbPersistentJson, - "examples/quickstarts/nodejs-mongodb.json": examplesQuickstartsNodejsMongodbJson, - "examples/quickstarts/rails-postgresql-persistent.json": examplesQuickstartsRailsPostgresqlPersistentJson, - "examples/quickstarts/rails-postgresql.json": examplesQuickstartsRailsPostgresqlJson, - "examples/hello-openshift/Dockerfile": examplesHelloOpenshiftDockerfile, - "examples/hello-openshift/hello-pod.json": examplesHelloOpenshiftHelloPodJson, - "examples/hello-openshift/hello-project.json": examplesHelloOpenshiftHelloProjectJson, - "examples/jenkins/application-template.json": examplesJenkinsApplicationTemplateJson, - "examples/jenkins/jenkins-ephemeral-template.json": examplesJenkinsJenkinsEphemeralTemplateJson, - "examples/jenkins/jenkins-persistent-template.json": examplesJenkinsJenkinsPersistentTemplateJson, - "examples/jenkins/pipeline/bluegreen-pipeline.yaml": examplesJenkinsPipelineBluegreenPipelineYaml, - "examples/jenkins/pipeline/maven-pipeline.yaml": examplesJenkinsPipelineMavenPipelineYaml, - "examples/jenkins/pipeline/nodejs-sample-pipeline.yaml": examplesJenkinsPipelineNodejsSamplePipelineYaml, - "examples/jenkins/pipeline/openshift-client-plugin-pipeline.yaml": examplesJenkinsPipelineOpenshiftClientPluginPipelineYaml, - "examples/jenkins/pipeline/samplepipeline.yaml": examplesJenkinsPipelineSamplepipelineYaml, - "examples/quickstarts/cakephp-mysql.json/cakephp-mysql.json": examplesQuickstartsCakephpMysqlJsonCakephpMysqlJson, - "test/extended/testdata/aggregator/kube-system-auth-reader.yaml": testExtendedTestdataAggregatorKubeSystemAuthReaderYaml, - "test/extended/testdata/aggregator/sample-apiserver-apiservice.yaml": testExtendedTestdataAggregatorSampleApiserverApiserviceYaml, - "test/extended/testdata/aggregator/sample-apiserver-authdelegator.yaml": testExtendedTestdataAggregatorSampleApiserverAuthdelegatorYaml, - "test/extended/testdata/aggregator/sample-apiserver-authreader.yaml": testExtendedTestdataAggregatorSampleApiserverAuthreaderYaml, - "test/extended/testdata/aggregator/sample-apiserver-rc.yaml": testExtendedTestdataAggregatorSampleApiserverRcYaml, - "test/extended/testdata/aggregator/sample-apiserver-sa.yaml": testExtendedTestdataAggregatorSampleApiserverSaYaml, - "test/extended/testdata/aggregator/sample-apiserver-service.yaml": testExtendedTestdataAggregatorSampleApiserverServiceYaml, - "test/extended/testdata/builds/application-template-custombuild.json": testExtendedTestdataBuildsApplicationTemplateCustombuildJson, - "test/extended/testdata/builds/build-postcommit/docker.yaml": testExtendedTestdataBuildsBuildPostcommitDockerYaml, - "test/extended/testdata/builds/build-postcommit/imagestreams.yaml": testExtendedTestdataBuildsBuildPostcommitImagestreamsYaml, - "test/extended/testdata/builds/build-postcommit/sti.yaml": testExtendedTestdataBuildsBuildPostcommitStiYaml, - "test/extended/testdata/builds/build-pruning/default-group-build-config.yaml": testExtendedTestdataBuildsBuildPruningDefaultGroupBuildConfigYaml, - "test/extended/testdata/builds/build-pruning/default-legacy-build-config.yaml": testExtendedTestdataBuildsBuildPruningDefaultLegacyBuildConfigYaml, - "test/extended/testdata/builds/build-pruning/errored-build-config.yaml": testExtendedTestdataBuildsBuildPruningErroredBuildConfigYaml, - "test/extended/testdata/builds/build-pruning/failed-build-config.yaml": testExtendedTestdataBuildsBuildPruningFailedBuildConfigYaml, - "test/extended/testdata/builds/build-pruning/failed-pipeline.yaml": testExtendedTestdataBuildsBuildPruningFailedPipelineYaml, - "test/extended/testdata/builds/build-pruning/imagestream.yaml": testExtendedTestdataBuildsBuildPruningImagestreamYaml, - "test/extended/testdata/builds/build-pruning/successful-build-config.yaml": testExtendedTestdataBuildsBuildPruningSuccessfulBuildConfigYaml, - "test/extended/testdata/builds/build-pruning/successful-pipeline.yaml": testExtendedTestdataBuildsBuildPruningSuccessfulPipelineYaml, - "test/extended/testdata/builds/build-quota/.s2i/bin/assemble": testExtendedTestdataBuildsBuildQuotaS2iBinAssemble, - "test/extended/testdata/builds/build-quota/Dockerfile": testExtendedTestdataBuildsBuildQuotaDockerfile, - "test/extended/testdata/builds/build-secrets/Dockerfile": testExtendedTestdataBuildsBuildSecretsDockerfile, - "test/extended/testdata/builds/build-secrets/s2i-binary-dir/.s2i/bin/assemble": testExtendedTestdataBuildsBuildSecretsS2iBinaryDirS2iBinAssemble, - "test/extended/testdata/builds/build-secrets/s2i-binary-dir/.s2i/bin/run": testExtendedTestdataBuildsBuildSecretsS2iBinaryDirS2iBinRun, - "test/extended/testdata/builds/build-secrets/s2i-binary-dir/Gemfile": testExtendedTestdataBuildsBuildSecretsS2iBinaryDirGemfile, - "test/extended/testdata/builds/build-secrets/s2i-binary-dir/config.ru": testExtendedTestdataBuildsBuildSecretsS2iBinaryDirConfigRu, - "test/extended/testdata/builds/build-secrets/test-configmap-2.json": testExtendedTestdataBuildsBuildSecretsTestConfigmap2Json, - "test/extended/testdata/builds/build-secrets/test-configmap.json": testExtendedTestdataBuildsBuildSecretsTestConfigmapJson, - "test/extended/testdata/builds/build-secrets/test-docker-build.json": testExtendedTestdataBuildsBuildSecretsTestDockerBuildJson, - "test/extended/testdata/builds/build-secrets/test-is.json": testExtendedTestdataBuildsBuildSecretsTestIsJson, - "test/extended/testdata/builds/build-secrets/test-s2i-build.json": testExtendedTestdataBuildsBuildSecretsTestS2iBuildJson, - "test/extended/testdata/builds/build-secrets/test-secret-2.json": testExtendedTestdataBuildsBuildSecretsTestSecret2Json, - "test/extended/testdata/builds/build-secrets/test-secret.json": testExtendedTestdataBuildsBuildSecretsTestSecretJson, - "test/extended/testdata/builds/build-timing/Dockerfile": testExtendedTestdataBuildsBuildTimingDockerfile, - "test/extended/testdata/builds/build-timing/s2i-binary-dir/.s2i/bin/assemble": testExtendedTestdataBuildsBuildTimingS2iBinaryDirS2iBinAssemble, - "test/extended/testdata/builds/build-timing/s2i-binary-dir/.s2i/bin/run": testExtendedTestdataBuildsBuildTimingS2iBinaryDirS2iBinRun, - "test/extended/testdata/builds/build-timing/s2i-binary-dir/Gemfile": testExtendedTestdataBuildsBuildTimingS2iBinaryDirGemfile, - "test/extended/testdata/builds/build-timing/s2i-binary-dir/config.ru": testExtendedTestdataBuildsBuildTimingS2iBinaryDirConfigRu, - "test/extended/testdata/builds/build-timing/test-docker-build.json": testExtendedTestdataBuildsBuildTimingTestDockerBuildJson, - "test/extended/testdata/builds/build-timing/test-is.json": testExtendedTestdataBuildsBuildTimingTestIsJson, - "test/extended/testdata/builds/build-timing/test-s2i-build.json": testExtendedTestdataBuildsBuildTimingTestS2iBuildJson, - "test/extended/testdata/builds/cluster-config/invalid-build-cluster-config.yaml": testExtendedTestdataBuildsClusterConfigInvalidBuildClusterConfigYaml, - "test/extended/testdata/builds/cluster-config/registry-blacklist.yaml": testExtendedTestdataBuildsClusterConfigRegistryBlacklistYaml, - "test/extended/testdata/builds/cluster-config/registry-whitelist.yaml": testExtendedTestdataBuildsClusterConfigRegistryWhitelistYaml, - "test/extended/testdata/builds/cluster-config.yaml": testExtendedTestdataBuildsClusterConfigYaml, - "test/extended/testdata/builds/custom-build/Dockerfile": testExtendedTestdataBuildsCustomBuildDockerfile, - "test/extended/testdata/builds/custom-build/Dockerfile.sample": testExtendedTestdataBuildsCustomBuildDockerfileSample, - "test/extended/testdata/builds/custom-build/build.sh": testExtendedTestdataBuildsCustomBuildBuildSh, - "test/extended/testdata/builds/docker-add/Dockerfile": testExtendedTestdataBuildsDockerAddDockerfile, - "test/extended/testdata/builds/docker-add/docker-add-env/Dockerfile": testExtendedTestdataBuildsDockerAddDockerAddEnvDockerfile, - "test/extended/testdata/builds/docker-add/docker-add-env/foo": testExtendedTestdataBuildsDockerAddDockerAddEnvFoo, - "test/extended/testdata/builds/incremental-auth-build.json": testExtendedTestdataBuildsIncrementalAuthBuildJson, - "test/extended/testdata/builds/pullsecret/linked-nodejs-bc.yaml": testExtendedTestdataBuildsPullsecretLinkedNodejsBcYaml, - "test/extended/testdata/builds/pullsecret/pullsecret-nodejs-bc.yaml": testExtendedTestdataBuildsPullsecretPullsecretNodejsBcYaml, - "test/extended/testdata/builds/s2i-environment-build-app/.s2i/environment": testExtendedTestdataBuildsS2iEnvironmentBuildAppS2iEnvironment, - "test/extended/testdata/builds/s2i-environment-build-app/Gemfile": testExtendedTestdataBuildsS2iEnvironmentBuildAppGemfile, - "test/extended/testdata/builds/s2i-environment-build-app/config.ru": testExtendedTestdataBuildsS2iEnvironmentBuildAppConfigRu, - "test/extended/testdata/builds/statusfail-assemble/.s2i/bin/assemble": testExtendedTestdataBuildsStatusfailAssembleS2iBinAssemble, - "test/extended/testdata/builds/statusfail-badcontextdirs2i.yaml": testExtendedTestdataBuildsStatusfailBadcontextdirs2iYaml, - "test/extended/testdata/builds/statusfail-failedassemble.yaml": testExtendedTestdataBuildsStatusfailFailedassembleYaml, - "test/extended/testdata/builds/statusfail-fetchbuilderimage.yaml": testExtendedTestdataBuildsStatusfailFetchbuilderimageYaml, - "test/extended/testdata/builds/statusfail-fetchimagecontentdocker.yaml": testExtendedTestdataBuildsStatusfailFetchimagecontentdockerYaml, - "test/extended/testdata/builds/statusfail-fetchsourcedocker.yaml": testExtendedTestdataBuildsStatusfailFetchsourcedockerYaml, - "test/extended/testdata/builds/statusfail-fetchsources2i.yaml": testExtendedTestdataBuildsStatusfailFetchsources2iYaml, - "test/extended/testdata/builds/statusfail-genericreason.yaml": testExtendedTestdataBuildsStatusfailGenericreasonYaml, - "test/extended/testdata/builds/statusfail-oomkilled.yaml": testExtendedTestdataBuildsStatusfailOomkilledYaml, - "test/extended/testdata/builds/statusfail-postcommithook.yaml": testExtendedTestdataBuildsStatusfailPostcommithookYaml, - "test/extended/testdata/builds/statusfail-pushtoregistry.yaml": testExtendedTestdataBuildsStatusfailPushtoregistryYaml, - "test/extended/testdata/builds/test-auth-build.yaml": testExtendedTestdataBuildsTestAuthBuildYaml, - "test/extended/testdata/builds/test-bc-with-pr-ref.yaml": testExtendedTestdataBuildsTestBcWithPrRefYaml, - "test/extended/testdata/builds/test-build-app/Dockerfile": testExtendedTestdataBuildsTestBuildAppDockerfile, - "test/extended/testdata/builds/test-build-app/Gemfile": testExtendedTestdataBuildsTestBuildAppGemfile, - "test/extended/testdata/builds/test-build-app/config.ru": testExtendedTestdataBuildsTestBuildAppConfigRu, - "test/extended/testdata/builds/test-build-cluster-config.yaml": testExtendedTestdataBuildsTestBuildClusterConfigYaml, - "test/extended/testdata/builds/test-build-podsvc.json": testExtendedTestdataBuildsTestBuildPodsvcJson, - "test/extended/testdata/builds/test-build-proxy.yaml": testExtendedTestdataBuildsTestBuildProxyYaml, - "test/extended/testdata/builds/test-build-revision.json": testExtendedTestdataBuildsTestBuildRevisionJson, - "test/extended/testdata/builds/test-build.yaml": testExtendedTestdataBuildsTestBuildYaml, - "test/extended/testdata/builds/test-buildconfigsecretinjector.yaml": testExtendedTestdataBuildsTestBuildconfigsecretinjectorYaml, - "test/extended/testdata/builds/test-cds-dockerbuild.json": testExtendedTestdataBuildsTestCdsDockerbuildJson, - "test/extended/testdata/builds/test-cds-sourcebuild.json": testExtendedTestdataBuildsTestCdsSourcebuildJson, - "test/extended/testdata/builds/test-context-build.json": testExtendedTestdataBuildsTestContextBuildJson, - "test/extended/testdata/builds/test-custom-build.yaml": testExtendedTestdataBuildsTestCustomBuildYaml, - "test/extended/testdata/builds/test-docker-app/Dockerfile": testExtendedTestdataBuildsTestDockerAppDockerfile, - "test/extended/testdata/builds/test-docker-build-pullsecret.json": testExtendedTestdataBuildsTestDockerBuildPullsecretJson, - "test/extended/testdata/builds/test-docker-build.json": testExtendedTestdataBuildsTestDockerBuildJson, - "test/extended/testdata/builds/test-docker-no-outputname.json": testExtendedTestdataBuildsTestDockerNoOutputnameJson, - "test/extended/testdata/builds/test-env-build.json": testExtendedTestdataBuildsTestEnvBuildJson, - "test/extended/testdata/builds/test-imagechangetriggers.yaml": testExtendedTestdataBuildsTestImagechangetriggersYaml, - "test/extended/testdata/builds/test-imageresolution-custom-build.yaml": testExtendedTestdataBuildsTestImageresolutionCustomBuildYaml, - "test/extended/testdata/builds/test-imageresolution-docker-build.yaml": testExtendedTestdataBuildsTestImageresolutionDockerBuildYaml, - "test/extended/testdata/builds/test-imageresolution-s2i-build.yaml": testExtendedTestdataBuildsTestImageresolutionS2iBuildYaml, - "test/extended/testdata/builds/test-imagesource-buildconfig.yaml": testExtendedTestdataBuildsTestImagesourceBuildconfigYaml, - "test/extended/testdata/builds/test-nosrc-build.json": testExtendedTestdataBuildsTestNosrcBuildJson, - "test/extended/testdata/builds/test-s2i-build-quota.json": testExtendedTestdataBuildsTestS2iBuildQuotaJson, - "test/extended/testdata/builds/test-s2i-build.json": testExtendedTestdataBuildsTestS2iBuildJson, - "test/extended/testdata/builds/test-s2i-no-outputname.json": testExtendedTestdataBuildsTestS2iNoOutputnameJson, - "test/extended/testdata/builds/test-symlink-build.yaml": testExtendedTestdataBuildsTestSymlinkBuildYaml, - "test/extended/testdata/builds/valuefrom/failed-docker-build-value-from-config.yaml": testExtendedTestdataBuildsValuefromFailedDockerBuildValueFromConfigYaml, - "test/extended/testdata/builds/valuefrom/failed-sti-build-value-from-config.yaml": testExtendedTestdataBuildsValuefromFailedStiBuildValueFromConfigYaml, - "test/extended/testdata/builds/valuefrom/successful-docker-build-value-from-config.yaml": testExtendedTestdataBuildsValuefromSuccessfulDockerBuildValueFromConfigYaml, - "test/extended/testdata/builds/valuefrom/successful-sti-build-value-from-config.yaml": testExtendedTestdataBuildsValuefromSuccessfulStiBuildValueFromConfigYaml, - "test/extended/testdata/builds/valuefrom/test-configmap.yaml": testExtendedTestdataBuildsValuefromTestConfigmapYaml, - "test/extended/testdata/builds/valuefrom/test-is.json": testExtendedTestdataBuildsValuefromTestIsJson, - "test/extended/testdata/builds/valuefrom/test-secret.yaml": testExtendedTestdataBuildsValuefromTestSecretYaml, - "test/extended/testdata/builds/webhook/bitbucket/testdata/pushevent-not-master.json": testExtendedTestdataBuildsWebhookBitbucketTestdataPusheventNotMasterJson, - "test/extended/testdata/builds/webhook/bitbucket/testdata/pushevent.json": testExtendedTestdataBuildsWebhookBitbucketTestdataPusheventJson, - "test/extended/testdata/builds/webhook/bitbucket/testdata/pushevent54-not-master.json": testExtendedTestdataBuildsWebhookBitbucketTestdataPushevent54NotMasterJson, - "test/extended/testdata/builds/webhook/bitbucket/testdata/pushevent54.json": testExtendedTestdataBuildsWebhookBitbucketTestdataPushevent54Json, - "test/extended/testdata/builds/webhook/generic/testdata/post-receive-git.json": testExtendedTestdataBuildsWebhookGenericTestdataPostReceiveGitJson, - "test/extended/testdata/builds/webhook/generic/testdata/push-generic-envs.json": testExtendedTestdataBuildsWebhookGenericTestdataPushGenericEnvsJson, - "test/extended/testdata/builds/webhook/generic/testdata/push-generic-envs.yaml": testExtendedTestdataBuildsWebhookGenericTestdataPushGenericEnvsYaml, - "test/extended/testdata/builds/webhook/generic/testdata/push-generic.json": testExtendedTestdataBuildsWebhookGenericTestdataPushGenericJson, - "test/extended/testdata/builds/webhook/generic/testdata/push-gitlab.json": testExtendedTestdataBuildsWebhookGenericTestdataPushGitlabJson, - "test/extended/testdata/builds/webhook/github/testdata/pingevent.json": testExtendedTestdataBuildsWebhookGithubTestdataPingeventJson, - "test/extended/testdata/builds/webhook/github/testdata/pushevent-not-master-branch.json": testExtendedTestdataBuildsWebhookGithubTestdataPusheventNotMasterBranchJson, - "test/extended/testdata/builds/webhook/github/testdata/pushevent.json": testExtendedTestdataBuildsWebhookGithubTestdataPusheventJson, - "test/extended/testdata/builds/webhook/gitlab/testdata/pushevent-not-master-branch.json": testExtendedTestdataBuildsWebhookGitlabTestdataPusheventNotMasterBranchJson, - "test/extended/testdata/builds/webhook/gitlab/testdata/pushevent.json": testExtendedTestdataBuildsWebhookGitlabTestdataPusheventJson, - "test/extended/testdata/cli/pod-with-two-containers.yaml": testExtendedTestdataCliPodWithTwoContainersYaml, - "test/extended/testdata/cluster/master-vert.yaml": testExtendedTestdataClusterMasterVertYaml, - "test/extended/testdata/cluster/quickstarts/cakephp-mysql.json": testExtendedTestdataClusterQuickstartsCakephpMysqlJson, - "test/extended/testdata/cluster/quickstarts/dancer-mysql.json": testExtendedTestdataClusterQuickstartsDancerMysqlJson, - "test/extended/testdata/cluster/quickstarts/django-postgresql.json": testExtendedTestdataClusterQuickstartsDjangoPostgresqlJson, - "test/extended/testdata/cluster/quickstarts/nodejs-mongodb.json": testExtendedTestdataClusterQuickstartsNodejsMongodbJson, - "test/extended/testdata/cluster/quickstarts/rails-postgresql.json": testExtendedTestdataClusterQuickstartsRailsPostgresqlJson, - "test/extended/testdata/cmd/hack/lib/cmd.sh": testExtendedTestdataCmdHackLibCmdSh, - "test/extended/testdata/cmd/hack/lib/compress.awk": testExtendedTestdataCmdHackLibCompressAwk, - "test/extended/testdata/cmd/hack/lib/constants.sh": testExtendedTestdataCmdHackLibConstantsSh, - "test/extended/testdata/cmd/hack/lib/init.sh": testExtendedTestdataCmdHackLibInitSh, - "test/extended/testdata/cmd/hack/lib/log/output.sh": testExtendedTestdataCmdHackLibLogOutputSh, - "test/extended/testdata/cmd/hack/lib/log/stacktrace.sh": testExtendedTestdataCmdHackLibLogStacktraceSh, - "test/extended/testdata/cmd/hack/lib/log/system.sh": testExtendedTestdataCmdHackLibLogSystemSh, - "test/extended/testdata/cmd/hack/lib/test/junit.sh": testExtendedTestdataCmdHackLibTestJunitSh, - "test/extended/testdata/cmd/hack/lib/util/environment.sh": testExtendedTestdataCmdHackLibUtilEnvironmentSh, - "test/extended/testdata/cmd/hack/lib/util/misc.sh": testExtendedTestdataCmdHackLibUtilMiscSh, - "test/extended/testdata/cmd/hack/lib/util/text.sh": testExtendedTestdataCmdHackLibUtilTextSh, - "test/extended/testdata/cmd/hack/lib/util/trap.sh": testExtendedTestdataCmdHackLibUtilTrapSh, - "test/extended/testdata/cmd/test/cmd/admin.sh": testExtendedTestdataCmdTestCmdAdminSh, - "test/extended/testdata/cmd/test/cmd/annotations.sh": testExtendedTestdataCmdTestCmdAnnotationsSh, - "test/extended/testdata/cmd/test/cmd/apiresources.sh": testExtendedTestdataCmdTestCmdApiresourcesSh, - "test/extended/testdata/cmd/test/cmd/authentication.sh": testExtendedTestdataCmdTestCmdAuthenticationSh, - "test/extended/testdata/cmd/test/cmd/basicresources.sh": testExtendedTestdataCmdTestCmdBasicresourcesSh, - "test/extended/testdata/cmd/test/cmd/builds.sh": testExtendedTestdataCmdTestCmdBuildsSh, - "test/extended/testdata/cmd/test/cmd/completions.sh": testExtendedTestdataCmdTestCmdCompletionsSh, - "test/extended/testdata/cmd/test/cmd/config.sh": testExtendedTestdataCmdTestCmdConfigSh, - "test/extended/testdata/cmd/test/cmd/convert.sh": testExtendedTestdataCmdTestCmdConvertSh, - "test/extended/testdata/cmd/test/cmd/create.sh": testExtendedTestdataCmdTestCmdCreateSh, - "test/extended/testdata/cmd/test/cmd/debug.sh": testExtendedTestdataCmdTestCmdDebugSh, - "test/extended/testdata/cmd/test/cmd/deployments.sh": testExtendedTestdataCmdTestCmdDeploymentsSh, - "test/extended/testdata/cmd/test/cmd/describer.sh": testExtendedTestdataCmdTestCmdDescriberSh, - "test/extended/testdata/cmd/test/cmd/edit.sh": testExtendedTestdataCmdTestCmdEditSh, - "test/extended/testdata/cmd/test/cmd/env.sh": testExtendedTestdataCmdTestCmdEnvSh, - "test/extended/testdata/cmd/test/cmd/framework-test.sh": testExtendedTestdataCmdTestCmdFrameworkTestSh, - "test/extended/testdata/cmd/test/cmd/get.sh": testExtendedTestdataCmdTestCmdGetSh, - "test/extended/testdata/cmd/test/cmd/help.sh": testExtendedTestdataCmdTestCmdHelpSh, - "test/extended/testdata/cmd/test/cmd/idle.sh": testExtendedTestdataCmdTestCmdIdleSh, - "test/extended/testdata/cmd/test/cmd/image-lookup.sh": testExtendedTestdataCmdTestCmdImageLookupSh, - "test/extended/testdata/cmd/test/cmd/images.sh": testExtendedTestdataCmdTestCmdImagesSh, - "test/extended/testdata/cmd/test/cmd/login.sh": testExtendedTestdataCmdTestCmdLoginSh, - "test/extended/testdata/cmd/test/cmd/migrate.sh": testExtendedTestdataCmdTestCmdMigrateSh, - "test/extended/testdata/cmd/test/cmd/newapp.sh": testExtendedTestdataCmdTestCmdNewappSh, - "test/extended/testdata/cmd/test/cmd/observe.sh": testExtendedTestdataCmdTestCmdObserveSh, - "test/extended/testdata/cmd/test/cmd/policy-storage-admin.sh": testExtendedTestdataCmdTestCmdPolicyStorageAdminSh, - "test/extended/testdata/cmd/test/cmd/policy.sh": testExtendedTestdataCmdTestCmdPolicySh, - "test/extended/testdata/cmd/test/cmd/printer.sh": testExtendedTestdataCmdTestCmdPrinterSh, - "test/extended/testdata/cmd/test/cmd/projects.sh": testExtendedTestdataCmdTestCmdProjectsSh, - "test/extended/testdata/cmd/test/cmd/quota.sh": testExtendedTestdataCmdTestCmdQuotaSh, - "test/extended/testdata/cmd/test/cmd/registry.sh": testExtendedTestdataCmdTestCmdRegistrySh, - "test/extended/testdata/cmd/test/cmd/routes.sh": testExtendedTestdataCmdTestCmdRoutesSh, - "test/extended/testdata/cmd/test/cmd/rsync.sh": testExtendedTestdataCmdTestCmdRsyncSh, - "test/extended/testdata/cmd/test/cmd/run.sh": testExtendedTestdataCmdTestCmdRunSh, - "test/extended/testdata/cmd/test/cmd/secrets.sh": testExtendedTestdataCmdTestCmdSecretsSh, - "test/extended/testdata/cmd/test/cmd/services.sh": testExtendedTestdataCmdTestCmdServicesSh, - "test/extended/testdata/cmd/test/cmd/set-data.sh": testExtendedTestdataCmdTestCmdSetDataSh, - "test/extended/testdata/cmd/test/cmd/set-image.sh": testExtendedTestdataCmdTestCmdSetImageSh, - "test/extended/testdata/cmd/test/cmd/set-liveness-probe.sh": testExtendedTestdataCmdTestCmdSetLivenessProbeSh, - "test/extended/testdata/cmd/test/cmd/setbuildhook.sh": testExtendedTestdataCmdTestCmdSetbuildhookSh, - "test/extended/testdata/cmd/test/cmd/setbuildsecret.sh": testExtendedTestdataCmdTestCmdSetbuildsecretSh, - "test/extended/testdata/cmd/test/cmd/status.sh": testExtendedTestdataCmdTestCmdStatusSh, - "test/extended/testdata/cmd/test/cmd/templates.sh": testExtendedTestdataCmdTestCmdTemplatesSh, - "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/app/Dockerfile": testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexAppDockerfile, - "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.generated.yaml": testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeGeneratedYaml, - "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.imported.yaml": testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeImportedYaml, - "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.yml": testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeYml, - "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/nginx/Dockerfile": testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexNginxDockerfile, - "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/wordpress/docker-compose.yml": testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeWordpressDockerComposeYml, - "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-lonely-pod.json": testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sLonelyPodJson, - "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-sample-app.json": testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sSampleAppJson, - "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-service-pod-no-rc.json": testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sServicePodNoRcJson, - "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-service-with-nothing.json": testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sServiceWithNothingJson, - "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-unserviced-rc.json": testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sUnservicedRcJson, - "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-deployed-app.yaml": testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectDeployedAppYaml, - "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-no-build.yaml": testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectNoBuildYaml, - "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-one-build.yaml": testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectOneBuildYaml, - "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-two-deployment-configs.yaml": testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectTwoDeploymentConfigsYaml, - "test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/petset.yaml": testExtendedTestdataCmdTestCmdTestdataAppScenariosPetsetYaml, - "test/extended/testdata/cmd/test/cmd/testdata/application-template-custombuild.json": testExtendedTestdataCmdTestCmdTestdataApplicationTemplateCustombuildJson, - "test/extended/testdata/cmd/test/cmd/testdata/application-template-dockerbuild.json": testExtendedTestdataCmdTestCmdTestdataApplicationTemplateDockerbuildJson, - "test/extended/testdata/cmd/test/cmd/testdata/application-template-stibuild.json": testExtendedTestdataCmdTestCmdTestdataApplicationTemplateStibuildJson, - "test/extended/testdata/cmd/test/cmd/testdata/convert/job-v1.yaml": testExtendedTestdataCmdTestCmdTestdataConvertJobV1Yaml, - "test/extended/testdata/cmd/test/cmd/testdata/convert/job-v2.json": testExtendedTestdataCmdTestCmdTestdataConvertJobV2Json, - "test/extended/testdata/cmd/test/cmd/testdata/external-service.yaml": testExtendedTestdataCmdTestCmdTestdataExternalServiceYaml, - "test/extended/testdata/cmd/test/cmd/testdata/hello-openshift/hello-pod.json": testExtendedTestdataCmdTestCmdTestdataHelloOpenshiftHelloPodJson, - "test/extended/testdata/cmd/test/cmd/testdata/idling-dc.yaml": testExtendedTestdataCmdTestCmdTestdataIdlingDcYaml, - "test/extended/testdata/cmd/test/cmd/testdata/idling-svc-route.yaml": testExtendedTestdataCmdTestCmdTestdataIdlingSvcRouteYaml, - "test/extended/testdata/cmd/test/cmd/testdata/image-streams/image-streams-centos7.json": testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json, - "test/extended/testdata/cmd/test/cmd/testdata/jenkins/jenkins-ephemeral-template.json": testExtendedTestdataCmdTestCmdTestdataJenkinsJenkinsEphemeralTemplateJson, - "test/extended/testdata/cmd/test/cmd/testdata/mixed-api-versions.yaml": testExtendedTestdataCmdTestCmdTestdataMixedApiVersionsYaml, - "test/extended/testdata/cmd/test/cmd/testdata/modified-ruby-imagestream.json": testExtendedTestdataCmdTestCmdTestdataModifiedRubyImagestreamJson, - "test/extended/testdata/cmd/test/cmd/testdata/multiport-service.yaml": testExtendedTestdataCmdTestCmdTestdataMultiportServiceYaml, - "test/extended/testdata/cmd/test/cmd/testdata/new-app/bc-from-imagestreamimage.json": testExtendedTestdataCmdTestCmdTestdataNewAppBcFromImagestreamimageJson, - "test/extended/testdata/cmd/test/cmd/testdata/new-app/build-arg-dockerfile/Dockerfile": testExtendedTestdataCmdTestCmdTestdataNewAppBuildArgDockerfileDockerfile, - "test/extended/testdata/cmd/test/cmd/testdata/new-app/circular-is.yaml": testExtendedTestdataCmdTestCmdTestdataNewAppCircularIsYaml, - "test/extended/testdata/cmd/test/cmd/testdata/new-app/circular.yaml": testExtendedTestdataCmdTestCmdTestdataNewAppCircularYaml, - "test/extended/testdata/cmd/test/cmd/testdata/new-app/imagestream-ref.yaml": testExtendedTestdataCmdTestCmdTestdataNewAppImagestreamRefYaml, - "test/extended/testdata/cmd/test/cmd/testdata/new-app/installable-stream.yaml": testExtendedTestdataCmdTestCmdTestdataNewAppInstallableStreamYaml, - "test/extended/testdata/cmd/test/cmd/testdata/new-app/invalid-build-strategy.yaml": testExtendedTestdataCmdTestCmdTestdataNewAppInvalidBuildStrategyYaml, - "test/extended/testdata/cmd/test/cmd/testdata/new-app/invalid.json": testExtendedTestdataCmdTestCmdTestdataNewAppInvalidJson, - "test/extended/testdata/cmd/test/cmd/testdata/new-app/template-minimal-expose.json": testExtendedTestdataCmdTestCmdTestdataNewAppTemplateMinimalExposeJson, - "test/extended/testdata/cmd/test/cmd/testdata/new-app/template-with-app-label.json": testExtendedTestdataCmdTestCmdTestdataNewAppTemplateWithAppLabelJson, - "test/extended/testdata/cmd/test/cmd/testdata/new-app/template-with-crd.yaml": testExtendedTestdataCmdTestCmdTestdataNewAppTemplateWithCrdYaml, - "test/extended/testdata/cmd/test/cmd/testdata/new-app/template-with-namespaces.json": testExtendedTestdataCmdTestCmdTestdataNewAppTemplateWithNamespacesJson, - "test/extended/testdata/cmd/test/cmd/testdata/new-app/template-without-app-label.json": testExtendedTestdataCmdTestCmdTestdataNewAppTemplateWithoutAppLabelJson, - "test/extended/testdata/cmd/test/cmd/testdata/new-app/template_multiple_resource_gvs.yaml": testExtendedTestdataCmdTestCmdTestdataNewAppTemplate_multiple_resource_gvsYaml, - "test/extended/testdata/cmd/test/cmd/testdata/new-app/test-cmd-newapp-env.env": testExtendedTestdataCmdTestCmdTestdataNewAppTestCmdNewappEnvEnv, - "test/extended/testdata/cmd/test/cmd/testdata/new-app/test-cmd-newapp-params.env": testExtendedTestdataCmdTestCmdTestdataNewAppTestCmdNewappParamsEnv, - "test/extended/testdata/cmd/test/cmd/testdata/oauthaccesstoken.yaml": testExtendedTestdataCmdTestCmdTestdataOauthaccesstokenYaml, - "test/extended/testdata/cmd/test/cmd/testdata/old-template.json": testExtendedTestdataCmdTestCmdTestdataOldTemplateJson, - "test/extended/testdata/cmd/test/cmd/testdata/resource-builder/directory/json-no-extension-in-directory": testExtendedTestdataCmdTestCmdTestdataResourceBuilderDirectoryJsonNoExtensionInDirectory, - "test/extended/testdata/cmd/test/cmd/testdata/resource-builder/directory/json-with-extension.json": testExtendedTestdataCmdTestCmdTestdataResourceBuilderDirectoryJsonWithExtensionJson, - "test/extended/testdata/cmd/test/cmd/testdata/resource-builder/directory/non-api-file": testExtendedTestdataCmdTestCmdTestdataResourceBuilderDirectoryNonApiFile, - "test/extended/testdata/cmd/test/cmd/testdata/resource-builder/directory/yml-with-extension.yml": testExtendedTestdataCmdTestCmdTestdataResourceBuilderDirectoryYmlWithExtensionYml, - "test/extended/testdata/cmd/test/cmd/testdata/resource-builder/json-no-extension": testExtendedTestdataCmdTestCmdTestdataResourceBuilderJsonNoExtension, - "test/extended/testdata/cmd/test/cmd/testdata/resource-builder/yml-no-extension": testExtendedTestdataCmdTestCmdTestdataResourceBuilderYmlNoExtension, - "test/extended/testdata/cmd/test/cmd/testdata/roles/empty-role.yaml": testExtendedTestdataCmdTestCmdTestdataRolesEmptyRoleYaml, - "test/extended/testdata/cmd/test/cmd/testdata/roles/policy-clusterroles.yaml": testExtendedTestdataCmdTestCmdTestdataRolesPolicyClusterrolesYaml, - "test/extended/testdata/cmd/test/cmd/testdata/roles/policy-roles.yaml": testExtendedTestdataCmdTestCmdTestdataRolesPolicyRolesYaml, - "test/extended/testdata/cmd/test/cmd/testdata/rollingupdate-daemonset.yaml": testExtendedTestdataCmdTestCmdTestdataRollingupdateDaemonsetYaml, - "test/extended/testdata/cmd/test/cmd/testdata/services.yaml": testExtendedTestdataCmdTestCmdTestdataServicesYaml, - "test/extended/testdata/cmd/test/cmd/testdata/simple-deployment.yaml": testExtendedTestdataCmdTestCmdTestdataSimpleDeploymentYaml, - "test/extended/testdata/cmd/test/cmd/testdata/stable-busybox.yaml": testExtendedTestdataCmdTestCmdTestdataStableBusyboxYaml, - "test/extended/testdata/cmd/test/cmd/testdata/statefulset.yaml": testExtendedTestdataCmdTestCmdTestdataStatefulsetYaml, - "test/extended/testdata/cmd/test/cmd/testdata/templateinstance_objectkinds.yaml": testExtendedTestdataCmdTestCmdTestdataTemplateinstance_objectkindsYaml, - "test/extended/testdata/cmd/test/cmd/testdata/templates/basic-users-binding.json": testExtendedTestdataCmdTestCmdTestdataTemplatesBasicUsersBindingJson, - "test/extended/testdata/cmd/test/cmd/testdata/templates/guestbook.env": testExtendedTestdataCmdTestCmdTestdataTemplatesGuestbookEnv, - "test/extended/testdata/cmd/test/cmd/testdata/templates/guestbook.json": testExtendedTestdataCmdTestCmdTestdataTemplatesGuestbookJson, - "test/extended/testdata/cmd/test/cmd/testdata/templates/guestbook_list.json": testExtendedTestdataCmdTestCmdTestdataTemplatesGuestbook_listJson, - "test/extended/testdata/cmd/test/cmd/testdata/templates/multiline.txt": testExtendedTestdataCmdTestCmdTestdataTemplatesMultilineTxt, - "test/extended/testdata/cmd/test/cmd/testdata/templates/template-type-precision.json": testExtendedTestdataCmdTestCmdTestdataTemplatesTemplateTypePrecisionJson, - "test/extended/testdata/cmd/test/cmd/testdata/templates/template_required_params.env": testExtendedTestdataCmdTestCmdTestdataTemplatesTemplate_required_paramsEnv, - "test/extended/testdata/cmd/test/cmd/testdata/templates/template_required_params.yaml": testExtendedTestdataCmdTestCmdTestdataTemplatesTemplate_required_paramsYaml, - "test/extended/testdata/cmd/test/cmd/testdata/test-bc.yaml": testExtendedTestdataCmdTestCmdTestdataTestBcYaml, - "test/extended/testdata/cmd/test/cmd/testdata/test-buildcli.json": testExtendedTestdataCmdTestCmdTestdataTestBuildcliJson, - "test/extended/testdata/cmd/test/cmd/testdata/test-deployment-config.yaml": testExtendedTestdataCmdTestCmdTestdataTestDeploymentConfigYaml, - "test/extended/testdata/cmd/test/cmd/testdata/test-docker-build.json": testExtendedTestdataCmdTestCmdTestdataTestDockerBuildJson, - "test/extended/testdata/cmd/test/cmd/testdata/test-image-stream.json": testExtendedTestdataCmdTestCmdTestdataTestImageStreamJson, - "test/extended/testdata/cmd/test/cmd/testdata/test-image.json": testExtendedTestdataCmdTestCmdTestdataTestImageJson, - "test/extended/testdata/cmd/test/cmd/testdata/test-multiarch-stream.yaml": testExtendedTestdataCmdTestCmdTestdataTestMultiarchStreamYaml, - "test/extended/testdata/cmd/test/cmd/testdata/test-replication-controller.yaml": testExtendedTestdataCmdTestCmdTestdataTestReplicationControllerYaml, - "test/extended/testdata/cmd/test/cmd/testdata/test-route.json": testExtendedTestdataCmdTestCmdTestdataTestRouteJson, - "test/extended/testdata/cmd/test/cmd/testdata/test-s2i-build.json": testExtendedTestdataCmdTestCmdTestdataTestS2iBuildJson, - "test/extended/testdata/cmd/test/cmd/testdata/test-service.json": testExtendedTestdataCmdTestCmdTestdataTestServiceJson, - "test/extended/testdata/cmd/test/cmd/testdata/test-stream.yaml": testExtendedTestdataCmdTestCmdTestdataTestStreamYaml, - "test/extended/testdata/cmd/test/cmd/timeout.sh": testExtendedTestdataCmdTestCmdTimeoutSh, - "test/extended/testdata/cmd/test/cmd/triggers.sh": testExtendedTestdataCmdTestCmdTriggersSh, - "test/extended/testdata/cmd/test/cmd/volumes.sh": testExtendedTestdataCmdTestCmdVolumesSh, - "test/extended/testdata/cmd/test/cmd/whoami.sh": testExtendedTestdataCmdTestCmdWhoamiSh, - "test/extended/testdata/config-map-jenkins-slave-pods.yaml": testExtendedTestdataConfigMapJenkinsSlavePodsYaml, - "test/extended/testdata/csi/aws-ebs/install-template.yaml": testExtendedTestdataCsiAwsEbsInstallTemplateYaml, - "test/extended/testdata/csi/aws-ebs/manifest.yaml": testExtendedTestdataCsiAwsEbsManifestYaml, - "test/extended/testdata/csi/aws-ebs/storageclass.yaml": testExtendedTestdataCsiAwsEbsStorageclassYaml, - "test/extended/testdata/custom-secret-builder/Dockerfile": testExtendedTestdataCustomSecretBuilderDockerfile, - "test/extended/testdata/custom-secret-builder/build.sh": testExtendedTestdataCustomSecretBuilderBuildSh, - "test/extended/testdata/deployments/custom-deployment.yaml": testExtendedTestdataDeploymentsCustomDeploymentYaml, - "test/extended/testdata/deployments/deployment-example.yaml": testExtendedTestdataDeploymentsDeploymentExampleYaml, - "test/extended/testdata/deployments/deployment-history-limit.yaml": testExtendedTestdataDeploymentsDeploymentHistoryLimitYaml, - "test/extended/testdata/deployments/deployment-ignores-deployer.yaml": testExtendedTestdataDeploymentsDeploymentIgnoresDeployerYaml, - "test/extended/testdata/deployments/deployment-image-resolution-is.yaml": testExtendedTestdataDeploymentsDeploymentImageResolutionIsYaml, - "test/extended/testdata/deployments/deployment-image-resolution.yaml": testExtendedTestdataDeploymentsDeploymentImageResolutionYaml, - "test/extended/testdata/deployments/deployment-min-ready-seconds.yaml": testExtendedTestdataDeploymentsDeploymentMinReadySecondsYaml, - "test/extended/testdata/deployments/deployment-simple.yaml": testExtendedTestdataDeploymentsDeploymentSimpleYaml, - "test/extended/testdata/deployments/deployment-trigger.yaml": testExtendedTestdataDeploymentsDeploymentTriggerYaml, - "test/extended/testdata/deployments/deployment-with-ref-env.yaml": testExtendedTestdataDeploymentsDeploymentWithRefEnvYaml, - "test/extended/testdata/deployments/failing-pre-hook.yaml": testExtendedTestdataDeploymentsFailingPreHookYaml, - "test/extended/testdata/deployments/generation-test.yaml": testExtendedTestdataDeploymentsGenerationTestYaml, - "test/extended/testdata/deployments/multi-ict-deployment.yaml": testExtendedTestdataDeploymentsMultiIctDeploymentYaml, - "test/extended/testdata/deployments/paused-deployment.yaml": testExtendedTestdataDeploymentsPausedDeploymentYaml, - "test/extended/testdata/deployments/readiness-test.yaml": testExtendedTestdataDeploymentsReadinessTestYaml, - "test/extended/testdata/deployments/tag-images-deployment.yaml": testExtendedTestdataDeploymentsTagImagesDeploymentYaml, - "test/extended/testdata/deployments/test-deployment-broken.yaml": testExtendedTestdataDeploymentsTestDeploymentBrokenYaml, - "test/extended/testdata/deployments/test-deployment-test.yaml": testExtendedTestdataDeploymentsTestDeploymentTestYaml, - "test/extended/testdata/disaster-recovery/restore-etcd.sh": testExtendedTestdataDisasterRecoveryRestoreEtcdSh, - "test/extended/testdata/disaster-recovery/rollback-A.yaml": testExtendedTestdataDisasterRecoveryRollbackAYaml, - "test/extended/testdata/disaster-recovery/rollback-B.yaml": testExtendedTestdataDisasterRecoveryRollbackBYaml, - "test/extended/testdata/disaster-recovery/ssh-bastion/clusterrole.yaml": testExtendedTestdataDisasterRecoverySshBastionClusterroleYaml, - "test/extended/testdata/disaster-recovery/ssh-bastion/clusterrolebinding.yaml": testExtendedTestdataDisasterRecoverySshBastionClusterrolebindingYaml, - "test/extended/testdata/disaster-recovery/ssh-bastion/deployment.yaml": testExtendedTestdataDisasterRecoverySshBastionDeploymentYaml, - "test/extended/testdata/disaster-recovery/ssh-bastion/namespace.yaml": testExtendedTestdataDisasterRecoverySshBastionNamespaceYaml, - "test/extended/testdata/disaster-recovery/ssh-bastion/role.yaml": testExtendedTestdataDisasterRecoverySshBastionRoleYaml, - "test/extended/testdata/disaster-recovery/ssh-bastion/rolebinding.yaml": testExtendedTestdataDisasterRecoverySshBastionRolebindingYaml, - "test/extended/testdata/disaster-recovery/ssh-bastion/service.yaml": testExtendedTestdataDisasterRecoverySshBastionServiceYaml, - "test/extended/testdata/disaster-recovery/ssh-bastion/serviceaccount.yaml": testExtendedTestdataDisasterRecoverySshBastionServiceaccountYaml, - "test/extended/testdata/disaster-recovery/ssh-bastion/sshd_config": testExtendedTestdataDisasterRecoverySshBastionSshd_config, - "test/extended/testdata/disaster-recovery/update_route_53.py": testExtendedTestdataDisasterRecoveryUpdate_route_53Py, - "test/extended/testdata/forcepull-test.json": testExtendedTestdataForcepullTestJson, - "test/extended/testdata/gssapi/config/kubeconfig": testExtendedTestdataGssapiConfigKubeconfig, - "test/extended/testdata/gssapi/config/oauth_config.json": testExtendedTestdataGssapiConfigOauth_configJson, - "test/extended/testdata/gssapi/fedora/base/Dockerfile": testExtendedTestdataGssapiFedoraBaseDockerfile, - "test/extended/testdata/gssapi/fedora/kerberos/Dockerfile": testExtendedTestdataGssapiFedoraKerberosDockerfile, - "test/extended/testdata/gssapi/fedora/kerberos_configured/Dockerfile": testExtendedTestdataGssapiFedoraKerberos_configuredDockerfile, - "test/extended/testdata/gssapi/proxy/Dockerfile": testExtendedTestdataGssapiProxyDockerfile, - "test/extended/testdata/gssapi/proxy/configure.sh": testExtendedTestdataGssapiProxyConfigureSh, - "test/extended/testdata/gssapi/proxy/gssapiproxy-buildconfig.yaml": testExtendedTestdataGssapiProxyGssapiproxyBuildconfigYaml, - "test/extended/testdata/gssapi/proxy/gssapiproxy-deploymentconfig.yaml": testExtendedTestdataGssapiProxyGssapiproxyDeploymentconfigYaml, - "test/extended/testdata/gssapi/proxy/gssapiproxy-imagestream.yaml": testExtendedTestdataGssapiProxyGssapiproxyImagestreamYaml, - "test/extended/testdata/gssapi/proxy/gssapiproxy-service.yaml": testExtendedTestdataGssapiProxyGssapiproxyServiceYaml, - "test/extended/testdata/gssapi/proxy/healthz": testExtendedTestdataGssapiProxyHealthz, - "test/extended/testdata/gssapi/proxy/kadm5.acl": testExtendedTestdataGssapiProxyKadm5Acl, - "test/extended/testdata/gssapi/proxy/kdc.conf": testExtendedTestdataGssapiProxyKdcConf, - "test/extended/testdata/gssapi/proxy/krb5.conf": testExtendedTestdataGssapiProxyKrb5Conf, - "test/extended/testdata/gssapi/proxy/proxy.conf": testExtendedTestdataGssapiProxyProxyConf, - "test/extended/testdata/gssapi/scripts/gssapi-tests.sh": testExtendedTestdataGssapiScriptsGssapiTestsSh, - "test/extended/testdata/gssapi/scripts/test-wrapper.sh": testExtendedTestdataGssapiScriptsTestWrapperSh, - "test/extended/testdata/gssapi/ubuntu/base/Dockerfile": testExtendedTestdataGssapiUbuntuBaseDockerfile, - "test/extended/testdata/gssapi/ubuntu/kerberos/Dockerfile": testExtendedTestdataGssapiUbuntuKerberosDockerfile, - "test/extended/testdata/gssapi/ubuntu/kerberos_configured/Dockerfile": testExtendedTestdataGssapiUbuntuKerberos_configuredDockerfile, - "test/extended/testdata/hello-builder/Dockerfile": testExtendedTestdataHelloBuilderDockerfile, - "test/extended/testdata/hello-builder/scripts/assemble": testExtendedTestdataHelloBuilderScriptsAssemble, - "test/extended/testdata/hello-builder/scripts/run": testExtendedTestdataHelloBuilderScriptsRun, - "test/extended/testdata/idling-echo-server-rc.yaml": testExtendedTestdataIdlingEchoServerRcYaml, - "test/extended/testdata/idling-echo-server.yaml": testExtendedTestdataIdlingEchoServerYaml, - "test/extended/testdata/image/deployment-with-annotation-trigger.yaml": testExtendedTestdataImageDeploymentWithAnnotationTriggerYaml, - "test/extended/testdata/image/test-image.json": testExtendedTestdataImageTestImageJson, - "test/extended/testdata/image-pull-secrets/dc-with-new-pull-secret.yaml": testExtendedTestdataImagePullSecretsDcWithNewPullSecretYaml, - "test/extended/testdata/image-pull-secrets/dc-with-old-pull-secret.yaml": testExtendedTestdataImagePullSecretsDcWithOldPullSecretYaml, - "test/extended/testdata/image-pull-secrets/pod-with-new-pull-secret.yaml": testExtendedTestdataImagePullSecretsPodWithNewPullSecretYaml, - "test/extended/testdata/image-pull-secrets/pod-with-no-pull-secret.yaml": testExtendedTestdataImagePullSecretsPodWithNoPullSecretYaml, - "test/extended/testdata/image-pull-secrets/pod-with-old-pull-secret.yaml": testExtendedTestdataImagePullSecretsPodWithOldPullSecretYaml, - "test/extended/testdata/image_ecosystem/perl-hotdeploy/index.pl": testExtendedTestdataImage_ecosystemPerlHotdeployIndexPl, - "test/extended/testdata/image_ecosystem/perl-hotdeploy/lib/My/Test.pm": testExtendedTestdataImage_ecosystemPerlHotdeployLibMyTestPm, - "test/extended/testdata/image_ecosystem/perl-hotdeploy/perl.json": testExtendedTestdataImage_ecosystemPerlHotdeployPerlJson, - "test/extended/testdata/imagestream-jenkins-slave-pods.yaml": testExtendedTestdataImagestreamJenkinsSlavePodsYaml, - "test/extended/testdata/imagestreamtag-jenkins-slave-pods.yaml": testExtendedTestdataImagestreamtagJenkinsSlavePodsYaml, - "test/extended/testdata/jenkins-plugin/build-job-clone.xml": testExtendedTestdataJenkinsPluginBuildJobCloneXml, - "test/extended/testdata/jenkins-plugin/build-job-slave.xml": testExtendedTestdataJenkinsPluginBuildJobSlaveXml, - "test/extended/testdata/jenkins-plugin/build-job.xml": testExtendedTestdataJenkinsPluginBuildJobXml, - "test/extended/testdata/jenkins-plugin/build-with-env-job.xml": testExtendedTestdataJenkinsPluginBuildWithEnvJobXml, - "test/extended/testdata/jenkins-plugin/build-with-exec-steps.xml": testExtendedTestdataJenkinsPluginBuildWithExecStepsXml, - "test/extended/testdata/jenkins-plugin/create-job.xml": testExtendedTestdataJenkinsPluginCreateJobXml, - "test/extended/testdata/jenkins-plugin/delete-job-keys.xml": testExtendedTestdataJenkinsPluginDeleteJobKeysXml, - "test/extended/testdata/jenkins-plugin/delete-job-labels.xml": testExtendedTestdataJenkinsPluginDeleteJobLabelsXml, - "test/extended/testdata/jenkins-plugin/delete-job.xml": testExtendedTestdataJenkinsPluginDeleteJobXml, - "test/extended/testdata/jenkins-plugin/imagestream-scm-dsl-job.xml": testExtendedTestdataJenkinsPluginImagestreamScmDslJobXml, - "test/extended/testdata/jenkins-plugin/imagestream-scm-job.xml": testExtendedTestdataJenkinsPluginImagestreamScmJobXml, - "test/extended/testdata/jenkins-plugin/multitag-job.xml": testExtendedTestdataJenkinsPluginMultitagJobXml, - "test/extended/testdata/jenkins-plugin/multitag-template.json": testExtendedTestdataJenkinsPluginMultitagTemplateJson, - "test/extended/testdata/jenkins-plugin/shared-resources-template.json": testExtendedTestdataJenkinsPluginSharedResourcesTemplateJson, - "test/extended/testdata/jenkins-slave-template.yaml": testExtendedTestdataJenkinsSlaveTemplateYaml, - "test/extended/testdata/jobs/v1.yaml": testExtendedTestdataJobsV1Yaml, - "test/extended/testdata/ldap/groupsync/ad/blacklist_ldap.txt": testExtendedTestdataLdapGroupsyncAdBlacklist_ldapTxt, - "test/extended/testdata/ldap/groupsync/ad/blacklist_openshift.txt": testExtendedTestdataLdapGroupsyncAdBlacklist_openshiftTxt, - "test/extended/testdata/ldap/groupsync/ad/ldapgroupuids.txt": testExtendedTestdataLdapGroupsyncAdLdapgroupuidsTxt, - "test/extended/testdata/ldap/groupsync/ad/osgroupuids.txt": testExtendedTestdataLdapGroupsyncAdOsgroupuidsTxt, - "test/extended/testdata/ldap/groupsync/ad/sync-config-dn-everywhere.yaml": testExtendedTestdataLdapGroupsyncAdSyncConfigDnEverywhereYaml, - "test/extended/testdata/ldap/groupsync/ad/sync-config-paging.yaml": testExtendedTestdataLdapGroupsyncAdSyncConfigPagingYaml, - "test/extended/testdata/ldap/groupsync/ad/sync-config-partially-user-defined.yaml": testExtendedTestdataLdapGroupsyncAdSyncConfigPartiallyUserDefinedYaml, - "test/extended/testdata/ldap/groupsync/ad/sync-config-user-defined.yaml": testExtendedTestdataLdapGroupsyncAdSyncConfigUserDefinedYaml, - "test/extended/testdata/ldap/groupsync/ad/sync-config.yaml": testExtendedTestdataLdapGroupsyncAdSyncConfigYaml, - "test/extended/testdata/ldap/groupsync/ad/valid_all_blacklist_sync.yaml": testExtendedTestdataLdapGroupsyncAdValid_all_blacklist_syncYaml, - "test/extended/testdata/ldap/groupsync/ad/valid_all_ldap_sync.yaml": testExtendedTestdataLdapGroupsyncAdValid_all_ldap_syncYaml, - "test/extended/testdata/ldap/groupsync/ad/valid_all_ldap_sync_dn_everywhere.yaml": testExtendedTestdataLdapGroupsyncAdValid_all_ldap_sync_dn_everywhereYaml, - "test/extended/testdata/ldap/groupsync/ad/valid_all_ldap_sync_partially_user_defined.yaml": testExtendedTestdataLdapGroupsyncAdValid_all_ldap_sync_partially_user_definedYaml, - "test/extended/testdata/ldap/groupsync/ad/valid_all_ldap_sync_prune.yaml": testExtendedTestdataLdapGroupsyncAdValid_all_ldap_sync_pruneYaml, - "test/extended/testdata/ldap/groupsync/ad/valid_all_ldap_sync_user_defined.yaml": testExtendedTestdataLdapGroupsyncAdValid_all_ldap_sync_user_definedYaml, - "test/extended/testdata/ldap/groupsync/ad/valid_all_openshift_blacklist_sync.yaml": testExtendedTestdataLdapGroupsyncAdValid_all_openshift_blacklist_syncYaml, - "test/extended/testdata/ldap/groupsync/ad/valid_whitelist_sync.yaml": testExtendedTestdataLdapGroupsyncAdValid_whitelist_syncYaml, - "test/extended/testdata/ldap/groupsync/ad/valid_whitelist_union_sync.yaml": testExtendedTestdataLdapGroupsyncAdValid_whitelist_union_syncYaml, - "test/extended/testdata/ldap/groupsync/ad/whitelist_ldap.txt": testExtendedTestdataLdapGroupsyncAdWhitelist_ldapTxt, - "test/extended/testdata/ldap/groupsync/ad/whitelist_openshift.txt": testExtendedTestdataLdapGroupsyncAdWhitelist_openshiftTxt, - "test/extended/testdata/ldap/groupsync/augmented-ad/blacklist_ldap.txt": testExtendedTestdataLdapGroupsyncAugmentedAdBlacklist_ldapTxt, - "test/extended/testdata/ldap/groupsync/augmented-ad/blacklist_openshift.txt": testExtendedTestdataLdapGroupsyncAugmentedAdBlacklist_openshiftTxt, - "test/extended/testdata/ldap/groupsync/augmented-ad/ldapgroupuids.txt": testExtendedTestdataLdapGroupsyncAugmentedAdLdapgroupuidsTxt, - "test/extended/testdata/ldap/groupsync/augmented-ad/osgroupuids.txt": testExtendedTestdataLdapGroupsyncAugmentedAdOsgroupuidsTxt, - "test/extended/testdata/ldap/groupsync/augmented-ad/sync-config-dn-everywhere.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdSyncConfigDnEverywhereYaml, - "test/extended/testdata/ldap/groupsync/augmented-ad/sync-config-paging.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdSyncConfigPagingYaml, - "test/extended/testdata/ldap/groupsync/augmented-ad/sync-config-partially-user-defined.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdSyncConfigPartiallyUserDefinedYaml, - "test/extended/testdata/ldap/groupsync/augmented-ad/sync-config-user-defined.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdSyncConfigUserDefinedYaml, - "test/extended/testdata/ldap/groupsync/augmented-ad/sync-config.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdSyncConfigYaml, - "test/extended/testdata/ldap/groupsync/augmented-ad/valid_all_blacklist_sync.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_all_blacklist_syncYaml, - "test/extended/testdata/ldap/groupsync/augmented-ad/valid_all_ldap_sync.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_all_ldap_syncYaml, - "test/extended/testdata/ldap/groupsync/augmented-ad/valid_all_ldap_sync_delete_prune.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_all_ldap_sync_delete_pruneYaml, - "test/extended/testdata/ldap/groupsync/augmented-ad/valid_all_ldap_sync_dn_everywhere.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_all_ldap_sync_dn_everywhereYaml, - "test/extended/testdata/ldap/groupsync/augmented-ad/valid_all_ldap_sync_partially_user_defined.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_all_ldap_sync_partially_user_definedYaml, - "test/extended/testdata/ldap/groupsync/augmented-ad/valid_all_ldap_sync_prune.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_all_ldap_sync_pruneYaml, - "test/extended/testdata/ldap/groupsync/augmented-ad/valid_all_ldap_sync_user_defined.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_all_ldap_sync_user_definedYaml, - "test/extended/testdata/ldap/groupsync/augmented-ad/valid_all_openshift_blacklist_sync.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_all_openshift_blacklist_syncYaml, - "test/extended/testdata/ldap/groupsync/augmented-ad/valid_whitelist_sync.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_whitelist_syncYaml, - "test/extended/testdata/ldap/groupsync/augmented-ad/valid_whitelist_union_sync.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_whitelist_union_syncYaml, - "test/extended/testdata/ldap/groupsync/augmented-ad/whitelist_ldap.txt": testExtendedTestdataLdapGroupsyncAugmentedAdWhitelist_ldapTxt, - "test/extended/testdata/ldap/groupsync/augmented-ad/whitelist_openshift.txt": testExtendedTestdataLdapGroupsyncAugmentedAdWhitelist_openshiftTxt, - "test/extended/testdata/ldap/groupsync/rfc2307/blacklist_ldap.txt": testExtendedTestdataLdapGroupsyncRfc2307Blacklist_ldapTxt, - "test/extended/testdata/ldap/groupsync/rfc2307/blacklist_openshift.txt": testExtendedTestdataLdapGroupsyncRfc2307Blacklist_openshiftTxt, - "test/extended/testdata/ldap/groupsync/rfc2307/ldapgroupuids.txt": testExtendedTestdataLdapGroupsyncRfc2307LdapgroupuidsTxt, - "test/extended/testdata/ldap/groupsync/rfc2307/osgroupuids.txt": testExtendedTestdataLdapGroupsyncRfc2307OsgroupuidsTxt, - "test/extended/testdata/ldap/groupsync/rfc2307/sync-config-dn-everywhere.yaml": testExtendedTestdataLdapGroupsyncRfc2307SyncConfigDnEverywhereYaml, - "test/extended/testdata/ldap/groupsync/rfc2307/sync-config-paging.yaml": testExtendedTestdataLdapGroupsyncRfc2307SyncConfigPagingYaml, - "test/extended/testdata/ldap/groupsync/rfc2307/sync-config-partially-user-defined.yaml": testExtendedTestdataLdapGroupsyncRfc2307SyncConfigPartiallyUserDefinedYaml, - "test/extended/testdata/ldap/groupsync/rfc2307/sync-config-tolerating.yaml": testExtendedTestdataLdapGroupsyncRfc2307SyncConfigToleratingYaml, - "test/extended/testdata/ldap/groupsync/rfc2307/sync-config-user-defined.yaml": testExtendedTestdataLdapGroupsyncRfc2307SyncConfigUserDefinedYaml, - "test/extended/testdata/ldap/groupsync/rfc2307/sync-config.yaml": testExtendedTestdataLdapGroupsyncRfc2307SyncConfigYaml, - "test/extended/testdata/ldap/groupsync/rfc2307/valid_all_blacklist_sync.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_all_blacklist_syncYaml, - "test/extended/testdata/ldap/groupsync/rfc2307/valid_all_ldap_sync.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_all_ldap_syncYaml, - "test/extended/testdata/ldap/groupsync/rfc2307/valid_all_ldap_sync_dn_everywhere.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_all_ldap_sync_dn_everywhereYaml, - "test/extended/testdata/ldap/groupsync/rfc2307/valid_all_ldap_sync_partially_user_defined.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_all_ldap_sync_partially_user_definedYaml, - "test/extended/testdata/ldap/groupsync/rfc2307/valid_all_ldap_sync_prune.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_all_ldap_sync_pruneYaml, - "test/extended/testdata/ldap/groupsync/rfc2307/valid_all_ldap_sync_tolerating.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_all_ldap_sync_toleratingYaml, - "test/extended/testdata/ldap/groupsync/rfc2307/valid_all_ldap_sync_user_defined.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_all_ldap_sync_user_definedYaml, - "test/extended/testdata/ldap/groupsync/rfc2307/valid_all_openshift_blacklist_sync.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_all_openshift_blacklist_syncYaml, - "test/extended/testdata/ldap/groupsync/rfc2307/valid_whitelist_sync.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_whitelist_syncYaml, - "test/extended/testdata/ldap/groupsync/rfc2307/valid_whitelist_union_sync.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_whitelist_union_syncYaml, - "test/extended/testdata/ldap/groupsync/rfc2307/whitelist_ldap.txt": testExtendedTestdataLdapGroupsyncRfc2307Whitelist_ldapTxt, - "test/extended/testdata/ldap/groupsync/rfc2307/whitelist_openshift.txt": testExtendedTestdataLdapGroupsyncRfc2307Whitelist_openshiftTxt, - "test/extended/testdata/ldap/ldapserver-config-cm.yaml": testExtendedTestdataLdapLdapserverConfigCmYaml, - "test/extended/testdata/ldap/ldapserver-deployment.yaml": testExtendedTestdataLdapLdapserverDeploymentYaml, - "test/extended/testdata/ldap/ldapserver-scripts-cm.yaml": testExtendedTestdataLdapLdapserverScriptsCmYaml, - "test/extended/testdata/ldap/ldapserver-service.yaml": testExtendedTestdataLdapLdapserverServiceYaml, - "test/extended/testdata/long_names/Dockerfile": testExtendedTestdataLong_namesDockerfile, - "test/extended/testdata/long_names/fixture.json": testExtendedTestdataLong_namesFixtureJson, - "test/extended/testdata/marketplace/csc/02-csc.yaml": testExtendedTestdataMarketplaceCsc02CscYaml, - "test/extended/testdata/marketplace/opsrc/02-opsrc.yaml": testExtendedTestdataMarketplaceOpsrc02OpsrcYaml, - "test/extended/testdata/multi-namespace-pipeline.yaml": testExtendedTestdataMultiNamespacePipelineYaml, - "test/extended/testdata/multi-namespace-template.yaml": testExtendedTestdataMultiNamespaceTemplateYaml, - "test/extended/testdata/oauthserver/cabundle-cm.yaml": testExtendedTestdataOauthserverCabundleCmYaml, - "test/extended/testdata/oauthserver/oauth-network.yaml": testExtendedTestdataOauthserverOauthNetworkYaml, - "test/extended/testdata/oauthserver/oauth-pod.yaml": testExtendedTestdataOauthserverOauthPodYaml, - "test/extended/testdata/oauthserver/oauth-sa.yaml": testExtendedTestdataOauthserverOauthSaYaml, - "test/extended/testdata/olm/operatorgroup.yaml": testExtendedTestdataOlmOperatorgroupYaml, - "test/extended/testdata/olm/subscription.yaml": testExtendedTestdataOlmSubscriptionYaml, - "test/extended/testdata/openshift-secret-to-jenkins-credential.yaml": testExtendedTestdataOpenshiftSecretToJenkinsCredentialYaml, - "test/extended/testdata/releases/payload-1/etcd-operator/image-references": testExtendedTestdataReleasesPayload1EtcdOperatorImageReferences, - "test/extended/testdata/releases/payload-1/etcd-operator/manifest.yaml": testExtendedTestdataReleasesPayload1EtcdOperatorManifestYaml, - "test/extended/testdata/releases/payload-1/image-registry/10_image-registry_crd.yaml": testExtendedTestdataReleasesPayload1ImageRegistry10_imageRegistry_crdYaml, - "test/extended/testdata/releases/payload-1/image-registry/image-references": testExtendedTestdataReleasesPayload1ImageRegistryImageReferences, - "test/extended/testdata/releases/payload-1/image-registry/manifest.yaml": testExtendedTestdataReleasesPayload1ImageRegistryManifestYaml, - "test/extended/testdata/roles/empty-role.yaml": testExtendedTestdataRolesEmptyRoleYaml, - "test/extended/testdata/roles/policy-clusterroles.yaml": testExtendedTestdataRolesPolicyClusterrolesYaml, - "test/extended/testdata/roles/policy-roles.yaml": testExtendedTestdataRolesPolicyRolesYaml, - "test/extended/testdata/router/ingress.yaml": testExtendedTestdataRouterIngressYaml, - "test/extended/testdata/router/reencrypt-serving-cert.yaml": testExtendedTestdataRouterReencryptServingCertYaml, - "test/extended/testdata/router/router-common.yaml": testExtendedTestdataRouterRouterCommonYaml, - "test/extended/testdata/router/router-config-manager.yaml": testExtendedTestdataRouterRouterConfigManagerYaml, - "test/extended/testdata/router/router-grpc-interop.yaml": testExtendedTestdataRouterRouterGrpcInteropYaml, - "test/extended/testdata/router/router-h2spec.yaml": testExtendedTestdataRouterRouterH2specYaml, - "test/extended/testdata/router/router-http-echo-server.yaml": testExtendedTestdataRouterRouterHttpEchoServerYaml, - "test/extended/testdata/router/router-http2.yaml": testExtendedTestdataRouterRouterHttp2Yaml, - "test/extended/testdata/router/router-idle.yaml": testExtendedTestdataRouterRouterIdleYaml, - "test/extended/testdata/router/router-metrics.yaml": testExtendedTestdataRouterRouterMetricsYaml, - "test/extended/testdata/router/router-override-domains.yaml": testExtendedTestdataRouterRouterOverrideDomainsYaml, - "test/extended/testdata/router/router-override.yaml": testExtendedTestdataRouterRouterOverrideYaml, - "test/extended/testdata/router/router-scoped.yaml": testExtendedTestdataRouterRouterScopedYaml, - "test/extended/testdata/router/weighted-router.yaml": testExtendedTestdataRouterWeightedRouterYaml, - "test/extended/testdata/run_policy/parallel-bc.yaml": testExtendedTestdataRun_policyParallelBcYaml, - "test/extended/testdata/run_policy/serial-bc.yaml": testExtendedTestdataRun_policySerialBcYaml, - "test/extended/testdata/run_policy/serial-latest-only-bc.yaml": testExtendedTestdataRun_policySerialLatestOnlyBcYaml, - "test/extended/testdata/s2i-dropcaps/root-access-build.yaml": testExtendedTestdataS2iDropcapsRootAccessBuildYaml, - "test/extended/testdata/s2i-dropcaps/rootable-ruby/Dockerfile": testExtendedTestdataS2iDropcapsRootableRubyDockerfile, - "test/extended/testdata/s2i-dropcaps/rootable-ruby/adduser": testExtendedTestdataS2iDropcapsRootableRubyAdduser, - "test/extended/testdata/s2i-dropcaps/rootable-ruby/assemble": testExtendedTestdataS2iDropcapsRootableRubyAssemble, - "test/extended/testdata/sample-image-stream.json": testExtendedTestdataSampleImageStreamJson, - "test/extended/testdata/samplepipeline-withenvs.yaml": testExtendedTestdataSamplepipelineWithenvsYaml, - "test/extended/testdata/service-serving-cert/nginx-serving-cert.conf": testExtendedTestdataServiceServingCertNginxServingCertConf, - "test/extended/testdata/signer-buildconfig.yaml": testExtendedTestdataSignerBuildconfigYaml, - "test/extended/testdata/templates/crunchydata-pod.json": testExtendedTestdataTemplatesCrunchydataPodJson, - "test/extended/testdata/templates/guestbook.json": testExtendedTestdataTemplatesGuestbookJson, - "test/extended/testdata/templates/guestbook_list.json": testExtendedTestdataTemplatesGuestbook_listJson, - "test/extended/testdata/templates/templateinstance_badobject.yaml": testExtendedTestdataTemplatesTemplateinstance_badobjectYaml, - "test/extended/testdata/templates/templateinstance_objectkinds.yaml": testExtendedTestdataTemplatesTemplateinstance_objectkindsYaml, - "test/extended/testdata/templates/templateinstance_readiness.yaml": testExtendedTestdataTemplatesTemplateinstance_readinessYaml, - "test/extended/testdata/templates/templateservicebroker_bind.yaml": testExtendedTestdataTemplatesTemplateservicebroker_bindYaml, - "test/extended/testdata/test-cli-debug.yaml": testExtendedTestdataTestCliDebugYaml, - "test/extended/testdata/test-env-pod.json": testExtendedTestdataTestEnvPodJson, - "test/extended/testdata/test-gitserver.yaml": testExtendedTestdataTestGitserverYaml, - "test/extended/testdata/test-secret.json": testExtendedTestdataTestSecretJson, - "test/extended/testdata/verifyservice-pipeline-template.yaml": testExtendedTestdataVerifyservicePipelineTemplateYaml, - "test/integration/testdata/project-request-template-with-quota.yaml": testIntegrationTestdataProjectRequestTemplateWithQuotaYaml, - "test/integration/testdata/test-buildcli-beta2.json": testIntegrationTestdataTestBuildcliBeta2Json, - "test/integration/testdata/test-buildcli.json": testIntegrationTestdataTestBuildcliJson, - "test/integration/testdata/test-deployment-config.yaml": testIntegrationTestdataTestDeploymentConfigYaml, - "test/integration/testdata/test-image-stream-mapping.json": testIntegrationTestdataTestImageStreamMappingJson, - "test/integration/testdata/test-image-stream.json": testIntegrationTestdataTestImageStreamJson, - "test/integration/testdata/test-image.json": testIntegrationTestdataTestImageJson, - "test/integration/testdata/test-replication-controller.yaml": testIntegrationTestdataTestReplicationControllerYaml, - "test/integration/testdata/test-route.json": testIntegrationTestdataTestRouteJson, - "test/integration/testdata/test-service-with-finalizer.json": testIntegrationTestdataTestServiceWithFinalizerJson, - "test/integration/testdata/test-service.json": testIntegrationTestdataTestServiceJson, + "examples/db-templates/mariadb-ephemeral-template.json": examplesDbTemplatesMariadbEphemeralTemplateJson, + "examples/db-templates/mariadb-persistent-template.json": examplesDbTemplatesMariadbPersistentTemplateJson, + "examples/db-templates/mongodb-ephemeral-template.json": examplesDbTemplatesMongodbEphemeralTemplateJson, + "examples/db-templates/mongodb-persistent-template.json": examplesDbTemplatesMongodbPersistentTemplateJson, + "examples/db-templates/mysql-ephemeral-template.json": examplesDbTemplatesMysqlEphemeralTemplateJson, + "examples/db-templates/mysql-persistent-template.json": examplesDbTemplatesMysqlPersistentTemplateJson, + "examples/db-templates/postgresql-ephemeral-template.json": examplesDbTemplatesPostgresqlEphemeralTemplateJson, + "examples/db-templates/postgresql-persistent-template.json": examplesDbTemplatesPostgresqlPersistentTemplateJson, + "examples/db-templates/redis-ephemeral-template.json": examplesDbTemplatesRedisEphemeralTemplateJson, + "examples/db-templates/redis-persistent-template.json": examplesDbTemplatesRedisPersistentTemplateJson, + "examples/image-streams/image-streams-centos7.json": examplesImageStreamsImageStreamsCentos7Json, + "examples/sample-app/application-template-dockerbuild.json": examplesSampleAppApplicationTemplateDockerbuildJson, + "examples/sample-app/application-template-pullspecbuild.json": examplesSampleAppApplicationTemplatePullspecbuildJson, + "examples/sample-app/application-template-stibuild.json": examplesSampleAppApplicationTemplateStibuildJson, + "examples/sample-app/cleanup.sh": examplesSampleAppCleanupSh, + "examples/sample-app/github-webhook-example.json": examplesSampleAppGithubWebhookExampleJson, + "examples/quickstarts/cakephp-mysql-persistent.json": examplesQuickstartsCakephpMysqlPersistentJson, + "examples/quickstarts/cakephp-mysql.json": examplesQuickstartsCakephpMysqlJson, + "examples/quickstarts/dancer-mysql-persistent.json": examplesQuickstartsDancerMysqlPersistentJson, + "examples/quickstarts/dancer-mysql.json": examplesQuickstartsDancerMysqlJson, + "examples/quickstarts/django-postgresql-persistent.json": examplesQuickstartsDjangoPostgresqlPersistentJson, + "examples/quickstarts/django-postgresql.json": examplesQuickstartsDjangoPostgresqlJson, + "examples/quickstarts/dotnet-pgsql-persistent.json": examplesQuickstartsDotnetPgsqlPersistentJson, + "examples/quickstarts/dotnet.json": examplesQuickstartsDotnetJson, + "examples/quickstarts/httpd.json": examplesQuickstartsHttpdJson, + "examples/quickstarts/nginx.json": examplesQuickstartsNginxJson, + "examples/quickstarts/nodejs-mongodb-persistent.json": examplesQuickstartsNodejsMongodbPersistentJson, + "examples/quickstarts/nodejs-mongodb.json": examplesQuickstartsNodejsMongodbJson, + "examples/quickstarts/rails-postgresql-persistent.json": examplesQuickstartsRailsPostgresqlPersistentJson, + "examples/quickstarts/rails-postgresql.json": examplesQuickstartsRailsPostgresqlJson, + "examples/hello-openshift/Dockerfile": examplesHelloOpenshiftDockerfile, + "examples/hello-openshift/hello-pod.json": examplesHelloOpenshiftHelloPodJson, + "examples/hello-openshift/hello-project.json": examplesHelloOpenshiftHelloProjectJson, + "examples/jenkins/application-template.json": examplesJenkinsApplicationTemplateJson, + "examples/jenkins/jenkins-ephemeral-template.json": examplesJenkinsJenkinsEphemeralTemplateJson, + "examples/jenkins/jenkins-persistent-template.json": examplesJenkinsJenkinsPersistentTemplateJson, + "examples/jenkins/pipeline/bluegreen-pipeline.yaml": examplesJenkinsPipelineBluegreenPipelineYaml, + "examples/jenkins/pipeline/maven-pipeline.yaml": examplesJenkinsPipelineMavenPipelineYaml, + "examples/jenkins/pipeline/nodejs-sample-pipeline.yaml": examplesJenkinsPipelineNodejsSamplePipelineYaml, + "examples/jenkins/pipeline/openshift-client-plugin-pipeline.yaml": examplesJenkinsPipelineOpenshiftClientPluginPipelineYaml, + "examples/jenkins/pipeline/samplepipeline.yaml": examplesJenkinsPipelineSamplepipelineYaml, + "examples/quickstarts/cakephp-mysql.json/cakephp-mysql.json": examplesQuickstartsCakephpMysqlJsonCakephpMysqlJson, + "test/extended/testdata/aggregator/kube-system-auth-reader.yaml": testExtendedTestdataAggregatorKubeSystemAuthReaderYaml, + "test/extended/testdata/aggregator/sample-apiserver-apiservice.yaml": testExtendedTestdataAggregatorSampleApiserverApiserviceYaml, + "test/extended/testdata/aggregator/sample-apiserver-authdelegator.yaml": testExtendedTestdataAggregatorSampleApiserverAuthdelegatorYaml, + "test/extended/testdata/aggregator/sample-apiserver-authreader.yaml": testExtendedTestdataAggregatorSampleApiserverAuthreaderYaml, + "test/extended/testdata/aggregator/sample-apiserver-rc.yaml": testExtendedTestdataAggregatorSampleApiserverRcYaml, + "test/extended/testdata/aggregator/sample-apiserver-sa.yaml": testExtendedTestdataAggregatorSampleApiserverSaYaml, + "test/extended/testdata/aggregator/sample-apiserver-service.yaml": testExtendedTestdataAggregatorSampleApiserverServiceYaml, + "test/extended/testdata/builds/application-template-custombuild.json": testExtendedTestdataBuildsApplicationTemplateCustombuildJson, + "test/extended/testdata/builds/build-postcommit/docker.yaml": testExtendedTestdataBuildsBuildPostcommitDockerYaml, + "test/extended/testdata/builds/build-postcommit/imagestreams.yaml": testExtendedTestdataBuildsBuildPostcommitImagestreamsYaml, + "test/extended/testdata/builds/build-postcommit/sti.yaml": testExtendedTestdataBuildsBuildPostcommitStiYaml, + "test/extended/testdata/builds/build-pruning/default-group-build-config.yaml": testExtendedTestdataBuildsBuildPruningDefaultGroupBuildConfigYaml, + "test/extended/testdata/builds/build-pruning/default-legacy-build-config.yaml": testExtendedTestdataBuildsBuildPruningDefaultLegacyBuildConfigYaml, + "test/extended/testdata/builds/build-pruning/errored-build-config.yaml": testExtendedTestdataBuildsBuildPruningErroredBuildConfigYaml, + "test/extended/testdata/builds/build-pruning/failed-build-config.yaml": testExtendedTestdataBuildsBuildPruningFailedBuildConfigYaml, + "test/extended/testdata/builds/build-pruning/failed-pipeline.yaml": testExtendedTestdataBuildsBuildPruningFailedPipelineYaml, + "test/extended/testdata/builds/build-pruning/imagestream.yaml": testExtendedTestdataBuildsBuildPruningImagestreamYaml, + "test/extended/testdata/builds/build-pruning/successful-build-config.yaml": testExtendedTestdataBuildsBuildPruningSuccessfulBuildConfigYaml, + "test/extended/testdata/builds/build-pruning/successful-pipeline.yaml": testExtendedTestdataBuildsBuildPruningSuccessfulPipelineYaml, + "test/extended/testdata/builds/build-quota/.s2i/bin/assemble": testExtendedTestdataBuildsBuildQuotaS2iBinAssemble, + "test/extended/testdata/builds/build-quota/Dockerfile": testExtendedTestdataBuildsBuildQuotaDockerfile, + "test/extended/testdata/builds/build-secrets/Dockerfile": testExtendedTestdataBuildsBuildSecretsDockerfile, + "test/extended/testdata/builds/build-secrets/s2i-binary-dir/.s2i/bin/assemble": testExtendedTestdataBuildsBuildSecretsS2iBinaryDirS2iBinAssemble, + "test/extended/testdata/builds/build-secrets/s2i-binary-dir/.s2i/bin/run": testExtendedTestdataBuildsBuildSecretsS2iBinaryDirS2iBinRun, + "test/extended/testdata/builds/build-secrets/s2i-binary-dir/Gemfile": testExtendedTestdataBuildsBuildSecretsS2iBinaryDirGemfile, + "test/extended/testdata/builds/build-secrets/s2i-binary-dir/config.ru": testExtendedTestdataBuildsBuildSecretsS2iBinaryDirConfigRu, + "test/extended/testdata/builds/build-secrets/test-configmap-2.json": testExtendedTestdataBuildsBuildSecretsTestConfigmap2Json, + "test/extended/testdata/builds/build-secrets/test-configmap.json": testExtendedTestdataBuildsBuildSecretsTestConfigmapJson, + "test/extended/testdata/builds/build-secrets/test-docker-build.json": testExtendedTestdataBuildsBuildSecretsTestDockerBuildJson, + "test/extended/testdata/builds/build-secrets/test-is.json": testExtendedTestdataBuildsBuildSecretsTestIsJson, + "test/extended/testdata/builds/build-secrets/test-s2i-build.json": testExtendedTestdataBuildsBuildSecretsTestS2iBuildJson, + "test/extended/testdata/builds/build-secrets/test-secret-2.json": testExtendedTestdataBuildsBuildSecretsTestSecret2Json, + "test/extended/testdata/builds/build-secrets/test-secret.json": testExtendedTestdataBuildsBuildSecretsTestSecretJson, + "test/extended/testdata/builds/build-timing/Dockerfile": testExtendedTestdataBuildsBuildTimingDockerfile, + "test/extended/testdata/builds/build-timing/s2i-binary-dir/.s2i/bin/assemble": testExtendedTestdataBuildsBuildTimingS2iBinaryDirS2iBinAssemble, + "test/extended/testdata/builds/build-timing/s2i-binary-dir/.s2i/bin/run": testExtendedTestdataBuildsBuildTimingS2iBinaryDirS2iBinRun, + "test/extended/testdata/builds/build-timing/s2i-binary-dir/Gemfile": testExtendedTestdataBuildsBuildTimingS2iBinaryDirGemfile, + "test/extended/testdata/builds/build-timing/s2i-binary-dir/config.ru": testExtendedTestdataBuildsBuildTimingS2iBinaryDirConfigRu, + "test/extended/testdata/builds/build-timing/test-docker-build.json": testExtendedTestdataBuildsBuildTimingTestDockerBuildJson, + "test/extended/testdata/builds/build-timing/test-is.json": testExtendedTestdataBuildsBuildTimingTestIsJson, + "test/extended/testdata/builds/build-timing/test-s2i-build.json": testExtendedTestdataBuildsBuildTimingTestS2iBuildJson, + "test/extended/testdata/builds/cluster-config/invalid-build-cluster-config.yaml": testExtendedTestdataBuildsClusterConfigInvalidBuildClusterConfigYaml, + "test/extended/testdata/builds/cluster-config/registry-blacklist.yaml": testExtendedTestdataBuildsClusterConfigRegistryBlacklistYaml, + "test/extended/testdata/builds/cluster-config/registry-whitelist.yaml": testExtendedTestdataBuildsClusterConfigRegistryWhitelistYaml, + "test/extended/testdata/builds/cluster-config.yaml": testExtendedTestdataBuildsClusterConfigYaml, + "test/extended/testdata/builds/custom-build/Dockerfile": testExtendedTestdataBuildsCustomBuildDockerfile, + "test/extended/testdata/builds/custom-build/Dockerfile.sample": testExtendedTestdataBuildsCustomBuildDockerfileSample, + "test/extended/testdata/builds/custom-build/build.sh": testExtendedTestdataBuildsCustomBuildBuildSh, + "test/extended/testdata/builds/docker-add/Dockerfile": testExtendedTestdataBuildsDockerAddDockerfile, + "test/extended/testdata/builds/docker-add/docker-add-env/Dockerfile": testExtendedTestdataBuildsDockerAddDockerAddEnvDockerfile, + "test/extended/testdata/builds/docker-add/docker-add-env/foo": testExtendedTestdataBuildsDockerAddDockerAddEnvFoo, + "test/extended/testdata/builds/incremental-auth-build.json": testExtendedTestdataBuildsIncrementalAuthBuildJson, + "test/extended/testdata/builds/pullsecret/linked-nodejs-bc.yaml": testExtendedTestdataBuildsPullsecretLinkedNodejsBcYaml, + "test/extended/testdata/builds/pullsecret/pullsecret-nodejs-bc.yaml": testExtendedTestdataBuildsPullsecretPullsecretNodejsBcYaml, + "test/extended/testdata/builds/s2i-environment-build-app/.s2i/environment": testExtendedTestdataBuildsS2iEnvironmentBuildAppS2iEnvironment, + "test/extended/testdata/builds/s2i-environment-build-app/Gemfile": testExtendedTestdataBuildsS2iEnvironmentBuildAppGemfile, + "test/extended/testdata/builds/s2i-environment-build-app/config.ru": testExtendedTestdataBuildsS2iEnvironmentBuildAppConfigRu, + "test/extended/testdata/builds/statusfail-assemble/.s2i/bin/assemble": testExtendedTestdataBuildsStatusfailAssembleS2iBinAssemble, + "test/extended/testdata/builds/statusfail-badcontextdirs2i.yaml": testExtendedTestdataBuildsStatusfailBadcontextdirs2iYaml, + "test/extended/testdata/builds/statusfail-failedassemble.yaml": testExtendedTestdataBuildsStatusfailFailedassembleYaml, + "test/extended/testdata/builds/statusfail-fetchbuilderimage.yaml": testExtendedTestdataBuildsStatusfailFetchbuilderimageYaml, + "test/extended/testdata/builds/statusfail-fetchimagecontentdocker.yaml": testExtendedTestdataBuildsStatusfailFetchimagecontentdockerYaml, + "test/extended/testdata/builds/statusfail-fetchsourcedocker.yaml": testExtendedTestdataBuildsStatusfailFetchsourcedockerYaml, + "test/extended/testdata/builds/statusfail-fetchsources2i.yaml": testExtendedTestdataBuildsStatusfailFetchsources2iYaml, + "test/extended/testdata/builds/statusfail-genericreason.yaml": testExtendedTestdataBuildsStatusfailGenericreasonYaml, + "test/extended/testdata/builds/statusfail-oomkilled.yaml": testExtendedTestdataBuildsStatusfailOomkilledYaml, + "test/extended/testdata/builds/statusfail-postcommithook.yaml": testExtendedTestdataBuildsStatusfailPostcommithookYaml, + "test/extended/testdata/builds/statusfail-pushtoregistry.yaml": testExtendedTestdataBuildsStatusfailPushtoregistryYaml, + "test/extended/testdata/builds/test-auth-build.yaml": testExtendedTestdataBuildsTestAuthBuildYaml, + "test/extended/testdata/builds/test-bc-with-pr-ref.yaml": testExtendedTestdataBuildsTestBcWithPrRefYaml, + "test/extended/testdata/builds/test-build-app/Dockerfile": testExtendedTestdataBuildsTestBuildAppDockerfile, + "test/extended/testdata/builds/test-build-app/Gemfile": testExtendedTestdataBuildsTestBuildAppGemfile, + "test/extended/testdata/builds/test-build-app/config.ru": testExtendedTestdataBuildsTestBuildAppConfigRu, + "test/extended/testdata/builds/test-build-cluster-config.yaml": testExtendedTestdataBuildsTestBuildClusterConfigYaml, + "test/extended/testdata/builds/test-build-podsvc.json": testExtendedTestdataBuildsTestBuildPodsvcJson, + "test/extended/testdata/builds/test-build-proxy.yaml": testExtendedTestdataBuildsTestBuildProxyYaml, + "test/extended/testdata/builds/test-build-revision.json": testExtendedTestdataBuildsTestBuildRevisionJson, + "test/extended/testdata/builds/test-build.yaml": testExtendedTestdataBuildsTestBuildYaml, + "test/extended/testdata/builds/test-buildconfigsecretinjector.yaml": testExtendedTestdataBuildsTestBuildconfigsecretinjectorYaml, + "test/extended/testdata/builds/test-cds-dockerbuild.json": testExtendedTestdataBuildsTestCdsDockerbuildJson, + "test/extended/testdata/builds/test-cds-sourcebuild.json": testExtendedTestdataBuildsTestCdsSourcebuildJson, + "test/extended/testdata/builds/test-context-build.json": testExtendedTestdataBuildsTestContextBuildJson, + "test/extended/testdata/builds/test-custom-build.yaml": testExtendedTestdataBuildsTestCustomBuildYaml, + "test/extended/testdata/builds/test-docker-app/Dockerfile": testExtendedTestdataBuildsTestDockerAppDockerfile, + "test/extended/testdata/builds/test-docker-build-pullsecret.json": testExtendedTestdataBuildsTestDockerBuildPullsecretJson, + "test/extended/testdata/builds/test-docker-build.json": testExtendedTestdataBuildsTestDockerBuildJson, + "test/extended/testdata/builds/test-docker-no-outputname.json": testExtendedTestdataBuildsTestDockerNoOutputnameJson, + "test/extended/testdata/builds/test-env-build.json": testExtendedTestdataBuildsTestEnvBuildJson, + "test/extended/testdata/builds/test-image-stream.json": testExtendedTestdataBuildsTestImageStreamJson, + "test/extended/testdata/builds/test-imagechangetriggers.yaml": testExtendedTestdataBuildsTestImagechangetriggersYaml, + "test/extended/testdata/builds/test-imageresolution-custom-build.yaml": testExtendedTestdataBuildsTestImageresolutionCustomBuildYaml, + "test/extended/testdata/builds/test-imageresolution-docker-build.yaml": testExtendedTestdataBuildsTestImageresolutionDockerBuildYaml, + "test/extended/testdata/builds/test-imageresolution-s2i-build.yaml": testExtendedTestdataBuildsTestImageresolutionS2iBuildYaml, + "test/extended/testdata/builds/test-imagesource-buildconfig.yaml": testExtendedTestdataBuildsTestImagesourceBuildconfigYaml, + "test/extended/testdata/builds/test-nosrc-build.json": testExtendedTestdataBuildsTestNosrcBuildJson, + "test/extended/testdata/builds/test-s2i-build-quota.json": testExtendedTestdataBuildsTestS2iBuildQuotaJson, + "test/extended/testdata/builds/test-s2i-build.json": testExtendedTestdataBuildsTestS2iBuildJson, + "test/extended/testdata/builds/test-s2i-no-outputname.json": testExtendedTestdataBuildsTestS2iNoOutputnameJson, + "test/extended/testdata/builds/test-symlink-build.yaml": testExtendedTestdataBuildsTestSymlinkBuildYaml, + "test/extended/testdata/builds/valuefrom/failed-docker-build-value-from-config.yaml": testExtendedTestdataBuildsValuefromFailedDockerBuildValueFromConfigYaml, + "test/extended/testdata/builds/valuefrom/failed-sti-build-value-from-config.yaml": testExtendedTestdataBuildsValuefromFailedStiBuildValueFromConfigYaml, + "test/extended/testdata/builds/valuefrom/successful-docker-build-value-from-config.yaml": testExtendedTestdataBuildsValuefromSuccessfulDockerBuildValueFromConfigYaml, + "test/extended/testdata/builds/valuefrom/successful-sti-build-value-from-config.yaml": testExtendedTestdataBuildsValuefromSuccessfulStiBuildValueFromConfigYaml, + "test/extended/testdata/builds/valuefrom/test-configmap.yaml": testExtendedTestdataBuildsValuefromTestConfigmapYaml, + "test/extended/testdata/builds/valuefrom/test-is.json": testExtendedTestdataBuildsValuefromTestIsJson, + "test/extended/testdata/builds/valuefrom/test-secret.yaml": testExtendedTestdataBuildsValuefromTestSecretYaml, + "test/extended/testdata/builds/webhook/bitbucket/testdata/pushevent-not-master.json": testExtendedTestdataBuildsWebhookBitbucketTestdataPusheventNotMasterJson, + "test/extended/testdata/builds/webhook/bitbucket/testdata/pushevent.json": testExtendedTestdataBuildsWebhookBitbucketTestdataPusheventJson, + "test/extended/testdata/builds/webhook/bitbucket/testdata/pushevent54-not-master.json": testExtendedTestdataBuildsWebhookBitbucketTestdataPushevent54NotMasterJson, + "test/extended/testdata/builds/webhook/bitbucket/testdata/pushevent54.json": testExtendedTestdataBuildsWebhookBitbucketTestdataPushevent54Json, + "test/extended/testdata/builds/webhook/generic/testdata/post-receive-git.json": testExtendedTestdataBuildsWebhookGenericTestdataPostReceiveGitJson, + "test/extended/testdata/builds/webhook/generic/testdata/push-generic-envs.json": testExtendedTestdataBuildsWebhookGenericTestdataPushGenericEnvsJson, + "test/extended/testdata/builds/webhook/generic/testdata/push-generic-envs.yaml": testExtendedTestdataBuildsWebhookGenericTestdataPushGenericEnvsYaml, + "test/extended/testdata/builds/webhook/generic/testdata/push-generic.json": testExtendedTestdataBuildsWebhookGenericTestdataPushGenericJson, + "test/extended/testdata/builds/webhook/generic/testdata/push-gitlab.json": testExtendedTestdataBuildsWebhookGenericTestdataPushGitlabJson, + "test/extended/testdata/builds/webhook/github/testdata/pingevent.json": testExtendedTestdataBuildsWebhookGithubTestdataPingeventJson, + "test/extended/testdata/builds/webhook/github/testdata/pushevent-not-master-branch.json": testExtendedTestdataBuildsWebhookGithubTestdataPusheventNotMasterBranchJson, + "test/extended/testdata/builds/webhook/github/testdata/pushevent.json": testExtendedTestdataBuildsWebhookGithubTestdataPusheventJson, + "test/extended/testdata/builds/webhook/gitlab/testdata/pushevent-not-master-branch.json": testExtendedTestdataBuildsWebhookGitlabTestdataPusheventNotMasterBranchJson, + "test/extended/testdata/builds/webhook/gitlab/testdata/pushevent.json": testExtendedTestdataBuildsWebhookGitlabTestdataPusheventJson, + "test/extended/testdata/cli/pod-with-two-containers.yaml": testExtendedTestdataCliPodWithTwoContainersYaml, + "test/extended/testdata/cluster/master-vert.yaml": testExtendedTestdataClusterMasterVertYaml, + "test/extended/testdata/cluster/quickstarts/cakephp-mysql.json": testExtendedTestdataClusterQuickstartsCakephpMysqlJson, + "test/extended/testdata/cluster/quickstarts/dancer-mysql.json": testExtendedTestdataClusterQuickstartsDancerMysqlJson, + "test/extended/testdata/cluster/quickstarts/django-postgresql.json": testExtendedTestdataClusterQuickstartsDjangoPostgresqlJson, + "test/extended/testdata/cluster/quickstarts/nodejs-mongodb.json": testExtendedTestdataClusterQuickstartsNodejsMongodbJson, + "test/extended/testdata/cluster/quickstarts/rails-postgresql.json": testExtendedTestdataClusterQuickstartsRailsPostgresqlJson, + "test/extended/testdata/cmd/hack/lib/cmd.sh": testExtendedTestdataCmdHackLibCmdSh, + "test/extended/testdata/cmd/hack/lib/compress.awk": testExtendedTestdataCmdHackLibCompressAwk, + "test/extended/testdata/cmd/hack/lib/constants.sh": testExtendedTestdataCmdHackLibConstantsSh, + "test/extended/testdata/cmd/hack/lib/init.sh": testExtendedTestdataCmdHackLibInitSh, + "test/extended/testdata/cmd/hack/lib/log/output.sh": testExtendedTestdataCmdHackLibLogOutputSh, + "test/extended/testdata/cmd/hack/lib/log/stacktrace.sh": testExtendedTestdataCmdHackLibLogStacktraceSh, + "test/extended/testdata/cmd/hack/lib/log/system.sh": testExtendedTestdataCmdHackLibLogSystemSh, + "test/extended/testdata/cmd/hack/lib/test/junit.sh": testExtendedTestdataCmdHackLibTestJunitSh, + "test/extended/testdata/cmd/hack/lib/util/environment.sh": testExtendedTestdataCmdHackLibUtilEnvironmentSh, + "test/extended/testdata/cmd/hack/lib/util/misc.sh": testExtendedTestdataCmdHackLibUtilMiscSh, + "test/extended/testdata/cmd/hack/lib/util/text.sh": testExtendedTestdataCmdHackLibUtilTextSh, + "test/extended/testdata/cmd/hack/lib/util/trap.sh": testExtendedTestdataCmdHackLibUtilTrapSh, + "test/extended/testdata/cmd/test/cmd/admin.sh": testExtendedTestdataCmdTestCmdAdminSh, + "test/extended/testdata/cmd/test/cmd/annotations.sh": testExtendedTestdataCmdTestCmdAnnotationsSh, + "test/extended/testdata/cmd/test/cmd/apiresources.sh": testExtendedTestdataCmdTestCmdApiresourcesSh, + "test/extended/testdata/cmd/test/cmd/authentication.sh": testExtendedTestdataCmdTestCmdAuthenticationSh, + "test/extended/testdata/cmd/test/cmd/basicresources.sh": testExtendedTestdataCmdTestCmdBasicresourcesSh, + "test/extended/testdata/cmd/test/cmd/builds.sh": testExtendedTestdataCmdTestCmdBuildsSh, + "test/extended/testdata/cmd/test/cmd/completions.sh": testExtendedTestdataCmdTestCmdCompletionsSh, + "test/extended/testdata/cmd/test/cmd/config.sh": testExtendedTestdataCmdTestCmdConfigSh, + "test/extended/testdata/cmd/test/cmd/create.sh": testExtendedTestdataCmdTestCmdCreateSh, + "test/extended/testdata/cmd/test/cmd/deployments.sh": testExtendedTestdataCmdTestCmdDeploymentsSh, + "test/extended/testdata/cmd/test/cmd/describer.sh": testExtendedTestdataCmdTestCmdDescriberSh, + "test/extended/testdata/cmd/test/cmd/edit.sh": testExtendedTestdataCmdTestCmdEditSh, + "test/extended/testdata/cmd/test/cmd/env.sh": testExtendedTestdataCmdTestCmdEnvSh, + "test/extended/testdata/cmd/test/cmd/framework-test.sh": testExtendedTestdataCmdTestCmdFrameworkTestSh, + "test/extended/testdata/cmd/test/cmd/get.sh": testExtendedTestdataCmdTestCmdGetSh, + "test/extended/testdata/cmd/test/cmd/help.sh": testExtendedTestdataCmdTestCmdHelpSh, + "test/extended/testdata/cmd/test/cmd/idle.sh": testExtendedTestdataCmdTestCmdIdleSh, + "test/extended/testdata/cmd/test/cmd/image-lookup.sh": testExtendedTestdataCmdTestCmdImageLookupSh, + "test/extended/testdata/cmd/test/cmd/images.sh": testExtendedTestdataCmdTestCmdImagesSh, + "test/extended/testdata/cmd/test/cmd/login.sh": testExtendedTestdataCmdTestCmdLoginSh, + "test/extended/testdata/cmd/test/cmd/migrate.sh": testExtendedTestdataCmdTestCmdMigrateSh, + "test/extended/testdata/cmd/test/cmd/newapp.sh": testExtendedTestdataCmdTestCmdNewappSh, + "test/extended/testdata/cmd/test/cmd/policy.sh": testExtendedTestdataCmdTestCmdPolicySh, + "test/extended/testdata/cmd/test/cmd/printer.sh": testExtendedTestdataCmdTestCmdPrinterSh, + "test/extended/testdata/cmd/test/cmd/projects.sh": testExtendedTestdataCmdTestCmdProjectsSh, + "test/extended/testdata/cmd/test/cmd/quota.sh": testExtendedTestdataCmdTestCmdQuotaSh, + "test/extended/testdata/cmd/test/cmd/registry.sh": testExtendedTestdataCmdTestCmdRegistrySh, + "test/extended/testdata/cmd/test/cmd/routes.sh": testExtendedTestdataCmdTestCmdRoutesSh, + "test/extended/testdata/cmd/test/cmd/run.sh": testExtendedTestdataCmdTestCmdRunSh, + "test/extended/testdata/cmd/test/cmd/secrets.sh": testExtendedTestdataCmdTestCmdSecretsSh, + "test/extended/testdata/cmd/test/cmd/services.sh": testExtendedTestdataCmdTestCmdServicesSh, + "test/extended/testdata/cmd/test/cmd/set-data.sh": testExtendedTestdataCmdTestCmdSetDataSh, + "test/extended/testdata/cmd/test/cmd/set-image.sh": testExtendedTestdataCmdTestCmdSetImageSh, + "test/extended/testdata/cmd/test/cmd/set-liveness-probe.sh": testExtendedTestdataCmdTestCmdSetLivenessProbeSh, + "test/extended/testdata/cmd/test/cmd/setbuildhook.sh": testExtendedTestdataCmdTestCmdSetbuildhookSh, + "test/extended/testdata/cmd/test/cmd/setbuildsecret.sh": testExtendedTestdataCmdTestCmdSetbuildsecretSh, + "test/extended/testdata/cmd/test/cmd/status.sh": testExtendedTestdataCmdTestCmdStatusSh, + "test/extended/testdata/cmd/test/cmd/templates.sh": testExtendedTestdataCmdTestCmdTemplatesSh, + "test/extended/testdata/cmd/test/cmd/testdata/application-template-custombuild.json": testExtendedTestdataCmdTestCmdTestdataApplicationTemplateCustombuildJson, + "test/extended/testdata/cmd/test/cmd/testdata/application-template-dockerbuild.json": testExtendedTestdataCmdTestCmdTestdataApplicationTemplateDockerbuildJson, + "test/extended/testdata/cmd/test/cmd/testdata/application-template-stibuild.json": testExtendedTestdataCmdTestCmdTestdataApplicationTemplateStibuildJson, + "test/extended/testdata/cmd/test/cmd/testdata/convert/job-v1.yaml": testExtendedTestdataCmdTestCmdTestdataConvertJobV1Yaml, + "test/extended/testdata/cmd/test/cmd/testdata/convert/job-v2.json": testExtendedTestdataCmdTestCmdTestdataConvertJobV2Json, + "test/extended/testdata/cmd/test/cmd/testdata/external-service.yaml": testExtendedTestdataCmdTestCmdTestdataExternalServiceYaml, + "test/extended/testdata/cmd/test/cmd/testdata/hello-openshift/hello-pod.json": testExtendedTestdataCmdTestCmdTestdataHelloOpenshiftHelloPodJson, + "test/extended/testdata/cmd/test/cmd/testdata/idling-dc.yaml": testExtendedTestdataCmdTestCmdTestdataIdlingDcYaml, + "test/extended/testdata/cmd/test/cmd/testdata/idling-svc-route.yaml": testExtendedTestdataCmdTestCmdTestdataIdlingSvcRouteYaml, + "test/extended/testdata/cmd/test/cmd/testdata/image-streams/image-streams-centos7.json": testExtendedTestdataCmdTestCmdTestdataImageStreamsImageStreamsCentos7Json, + "test/extended/testdata/cmd/test/cmd/testdata/jenkins/jenkins-ephemeral-template.json": testExtendedTestdataCmdTestCmdTestdataJenkinsJenkinsEphemeralTemplateJson, + "test/extended/testdata/cmd/test/cmd/testdata/mixed-api-versions.yaml": testExtendedTestdataCmdTestCmdTestdataMixedApiVersionsYaml, + "test/extended/testdata/cmd/test/cmd/testdata/modified-ruby-imagestream.json": testExtendedTestdataCmdTestCmdTestdataModifiedRubyImagestreamJson, + "test/extended/testdata/cmd/test/cmd/testdata/multiport-service.yaml": testExtendedTestdataCmdTestCmdTestdataMultiportServiceYaml, + "test/extended/testdata/cmd/test/cmd/testdata/new-app/bc-from-imagestreamimage.json": testExtendedTestdataCmdTestCmdTestdataNewAppBcFromImagestreamimageJson, + "test/extended/testdata/cmd/test/cmd/testdata/new-app/build-arg-dockerfile/Dockerfile": testExtendedTestdataCmdTestCmdTestdataNewAppBuildArgDockerfileDockerfile, + "test/extended/testdata/cmd/test/cmd/testdata/new-app/circular-is.yaml": testExtendedTestdataCmdTestCmdTestdataNewAppCircularIsYaml, + "test/extended/testdata/cmd/test/cmd/testdata/new-app/circular.yaml": testExtendedTestdataCmdTestCmdTestdataNewAppCircularYaml, + "test/extended/testdata/cmd/test/cmd/testdata/new-app/imagestream-ref.yaml": testExtendedTestdataCmdTestCmdTestdataNewAppImagestreamRefYaml, + "test/extended/testdata/cmd/test/cmd/testdata/new-app/installable-stream.yaml": testExtendedTestdataCmdTestCmdTestdataNewAppInstallableStreamYaml, + "test/extended/testdata/cmd/test/cmd/testdata/new-app/invalid-build-strategy.yaml": testExtendedTestdataCmdTestCmdTestdataNewAppInvalidBuildStrategyYaml, + "test/extended/testdata/cmd/test/cmd/testdata/new-app/invalid.json": testExtendedTestdataCmdTestCmdTestdataNewAppInvalidJson, + "test/extended/testdata/cmd/test/cmd/testdata/new-app/template-minimal-expose.json": testExtendedTestdataCmdTestCmdTestdataNewAppTemplateMinimalExposeJson, + "test/extended/testdata/cmd/test/cmd/testdata/new-app/template-with-app-label.json": testExtendedTestdataCmdTestCmdTestdataNewAppTemplateWithAppLabelJson, + "test/extended/testdata/cmd/test/cmd/testdata/new-app/template-with-crd.yaml": testExtendedTestdataCmdTestCmdTestdataNewAppTemplateWithCrdYaml, + "test/extended/testdata/cmd/test/cmd/testdata/new-app/template-with-namespaces.json": testExtendedTestdataCmdTestCmdTestdataNewAppTemplateWithNamespacesJson, + "test/extended/testdata/cmd/test/cmd/testdata/new-app/template-without-app-label.json": testExtendedTestdataCmdTestCmdTestdataNewAppTemplateWithoutAppLabelJson, + "test/extended/testdata/cmd/test/cmd/testdata/new-app/template_multiple_resource_gvs.yaml": testExtendedTestdataCmdTestCmdTestdataNewAppTemplate_multiple_resource_gvsYaml, + "test/extended/testdata/cmd/test/cmd/testdata/new-app/test-cmd-newapp-env.env": testExtendedTestdataCmdTestCmdTestdataNewAppTestCmdNewappEnvEnv, + "test/extended/testdata/cmd/test/cmd/testdata/new-app/test-cmd-newapp-params.env": testExtendedTestdataCmdTestCmdTestdataNewAppTestCmdNewappParamsEnv, + "test/extended/testdata/cmd/test/cmd/testdata/oauthaccesstoken.yaml": testExtendedTestdataCmdTestCmdTestdataOauthaccesstokenYaml, + "test/extended/testdata/cmd/test/cmd/testdata/old-template.json": testExtendedTestdataCmdTestCmdTestdataOldTemplateJson, + "test/extended/testdata/cmd/test/cmd/testdata/resource-builder/directory/json-no-extension-in-directory": testExtendedTestdataCmdTestCmdTestdataResourceBuilderDirectoryJsonNoExtensionInDirectory, + "test/extended/testdata/cmd/test/cmd/testdata/resource-builder/directory/json-with-extension.json": testExtendedTestdataCmdTestCmdTestdataResourceBuilderDirectoryJsonWithExtensionJson, + "test/extended/testdata/cmd/test/cmd/testdata/resource-builder/directory/non-api-file": testExtendedTestdataCmdTestCmdTestdataResourceBuilderDirectoryNonApiFile, + "test/extended/testdata/cmd/test/cmd/testdata/resource-builder/directory/yml-with-extension.yml": testExtendedTestdataCmdTestCmdTestdataResourceBuilderDirectoryYmlWithExtensionYml, + "test/extended/testdata/cmd/test/cmd/testdata/resource-builder/json-no-extension": testExtendedTestdataCmdTestCmdTestdataResourceBuilderJsonNoExtension, + "test/extended/testdata/cmd/test/cmd/testdata/resource-builder/yml-no-extension": testExtendedTestdataCmdTestCmdTestdataResourceBuilderYmlNoExtension, + "test/extended/testdata/cmd/test/cmd/testdata/rollingupdate-daemonset.yaml": testExtendedTestdataCmdTestCmdTestdataRollingupdateDaemonsetYaml, + "test/extended/testdata/cmd/test/cmd/testdata/services.yaml": testExtendedTestdataCmdTestCmdTestdataServicesYaml, + "test/extended/testdata/cmd/test/cmd/testdata/simple-deployment.yaml": testExtendedTestdataCmdTestCmdTestdataSimpleDeploymentYaml, + "test/extended/testdata/cmd/test/cmd/testdata/statefulset.yaml": testExtendedTestdataCmdTestCmdTestdataStatefulsetYaml, + "test/extended/testdata/cmd/test/cmd/testdata/templateinstance_objectkinds.yaml": testExtendedTestdataCmdTestCmdTestdataTemplateinstance_objectkindsYaml, + "test/extended/testdata/cmd/test/cmd/testdata/templates/basic-users-binding.json": testExtendedTestdataCmdTestCmdTestdataTemplatesBasicUsersBindingJson, + "test/extended/testdata/cmd/test/cmd/testdata/templates/guestbook.env": testExtendedTestdataCmdTestCmdTestdataTemplatesGuestbookEnv, + "test/extended/testdata/cmd/test/cmd/testdata/templates/guestbook.json": testExtendedTestdataCmdTestCmdTestdataTemplatesGuestbookJson, + "test/extended/testdata/cmd/test/cmd/testdata/templates/guestbook_list.json": testExtendedTestdataCmdTestCmdTestdataTemplatesGuestbook_listJson, + "test/extended/testdata/cmd/test/cmd/testdata/templates/multiline.txt": testExtendedTestdataCmdTestCmdTestdataTemplatesMultilineTxt, + "test/extended/testdata/cmd/test/cmd/testdata/templates/template-type-precision.json": testExtendedTestdataCmdTestCmdTestdataTemplatesTemplateTypePrecisionJson, + "test/extended/testdata/cmd/test/cmd/testdata/templates/template_required_params.env": testExtendedTestdataCmdTestCmdTestdataTemplatesTemplate_required_paramsEnv, + "test/extended/testdata/cmd/test/cmd/testdata/templates/template_required_params.yaml": testExtendedTestdataCmdTestCmdTestdataTemplatesTemplate_required_paramsYaml, + "test/extended/testdata/cmd/test/cmd/testdata/test-bc.yaml": testExtendedTestdataCmdTestCmdTestdataTestBcYaml, + "test/extended/testdata/cmd/test/cmd/testdata/test-buildcli.json": testExtendedTestdataCmdTestCmdTestdataTestBuildcliJson, + "test/extended/testdata/cmd/test/cmd/testdata/test-deployment-config.yaml": testExtendedTestdataCmdTestCmdTestdataTestDeploymentConfigYaml, + "test/extended/testdata/cmd/test/cmd/testdata/test-docker-build.json": testExtendedTestdataCmdTestCmdTestdataTestDockerBuildJson, + "test/extended/testdata/cmd/test/cmd/testdata/test-image-stream.json": testExtendedTestdataCmdTestCmdTestdataTestImageStreamJson, + "test/extended/testdata/cmd/test/cmd/testdata/test-image.json": testExtendedTestdataCmdTestCmdTestdataTestImageJson, + "test/extended/testdata/cmd/test/cmd/testdata/test-multiarch-stream.yaml": testExtendedTestdataCmdTestCmdTestdataTestMultiarchStreamYaml, + "test/extended/testdata/cmd/test/cmd/testdata/test-replication-controller.yaml": testExtendedTestdataCmdTestCmdTestdataTestReplicationControllerYaml, + "test/extended/testdata/cmd/test/cmd/testdata/test-route.json": testExtendedTestdataCmdTestCmdTestdataTestRouteJson, + "test/extended/testdata/cmd/test/cmd/testdata/test-s2i-build.json": testExtendedTestdataCmdTestCmdTestdataTestS2iBuildJson, + "test/extended/testdata/cmd/test/cmd/testdata/test-service.json": testExtendedTestdataCmdTestCmdTestdataTestServiceJson, + "test/extended/testdata/cmd/test/cmd/testdata/test-stream.yaml": testExtendedTestdataCmdTestCmdTestdataTestStreamYaml, + "test/extended/testdata/cmd/test/cmd/triggers.sh": testExtendedTestdataCmdTestCmdTriggersSh, + "test/extended/testdata/cmd/test/cmd/volumes.sh": testExtendedTestdataCmdTestCmdVolumesSh, + "test/extended/testdata/cmd/test/cmd/whoami.sh": testExtendedTestdataCmdTestCmdWhoamiSh, + "test/extended/testdata/config-map-jenkins-slave-pods.yaml": testExtendedTestdataConfigMapJenkinsSlavePodsYaml, + "test/extended/testdata/custom-secret-builder/Dockerfile": testExtendedTestdataCustomSecretBuilderDockerfile, + "test/extended/testdata/custom-secret-builder/build.sh": testExtendedTestdataCustomSecretBuilderBuildSh, + "test/extended/testdata/deployments/custom-deployment.yaml": testExtendedTestdataDeploymentsCustomDeploymentYaml, + "test/extended/testdata/deployments/deployment-example.yaml": testExtendedTestdataDeploymentsDeploymentExampleYaml, + "test/extended/testdata/deployments/deployment-history-limit.yaml": testExtendedTestdataDeploymentsDeploymentHistoryLimitYaml, + "test/extended/testdata/deployments/deployment-ignores-deployer.yaml": testExtendedTestdataDeploymentsDeploymentIgnoresDeployerYaml, + "test/extended/testdata/deployments/deployment-image-resolution-is.yaml": testExtendedTestdataDeploymentsDeploymentImageResolutionIsYaml, + "test/extended/testdata/deployments/deployment-image-resolution.yaml": testExtendedTestdataDeploymentsDeploymentImageResolutionYaml, + "test/extended/testdata/deployments/deployment-min-ready-seconds.yaml": testExtendedTestdataDeploymentsDeploymentMinReadySecondsYaml, + "test/extended/testdata/deployments/deployment-simple.yaml": testExtendedTestdataDeploymentsDeploymentSimpleYaml, + "test/extended/testdata/deployments/deployment-trigger.yaml": testExtendedTestdataDeploymentsDeploymentTriggerYaml, + "test/extended/testdata/deployments/deployment-with-ref-env.yaml": testExtendedTestdataDeploymentsDeploymentWithRefEnvYaml, + "test/extended/testdata/deployments/failing-pre-hook.yaml": testExtendedTestdataDeploymentsFailingPreHookYaml, + "test/extended/testdata/deployments/generation-test.yaml": testExtendedTestdataDeploymentsGenerationTestYaml, + "test/extended/testdata/deployments/multi-ict-deployment.yaml": testExtendedTestdataDeploymentsMultiIctDeploymentYaml, + "test/extended/testdata/deployments/paused-deployment.yaml": testExtendedTestdataDeploymentsPausedDeploymentYaml, + "test/extended/testdata/deployments/readiness-test.yaml": testExtendedTestdataDeploymentsReadinessTestYaml, + "test/extended/testdata/deployments/tag-images-deployment.yaml": testExtendedTestdataDeploymentsTagImagesDeploymentYaml, + "test/extended/testdata/deployments/test-deployment-broken.yaml": testExtendedTestdataDeploymentsTestDeploymentBrokenYaml, + "test/extended/testdata/deployments/test-deployment-test.yaml": testExtendedTestdataDeploymentsTestDeploymentTestYaml, + "test/extended/testdata/forcepull-test.json": testExtendedTestdataForcepullTestJson, + "test/extended/testdata/gssapi/config/kubeconfig": testExtendedTestdataGssapiConfigKubeconfig, + "test/extended/testdata/gssapi/config/oauth_config.json": testExtendedTestdataGssapiConfigOauth_configJson, + "test/extended/testdata/gssapi/fedora/base/Dockerfile": testExtendedTestdataGssapiFedoraBaseDockerfile, + "test/extended/testdata/gssapi/fedora/kerberos/Dockerfile": testExtendedTestdataGssapiFedoraKerberosDockerfile, + "test/extended/testdata/gssapi/fedora/kerberos_configured/Dockerfile": testExtendedTestdataGssapiFedoraKerberos_configuredDockerfile, + "test/extended/testdata/gssapi/proxy/Dockerfile": testExtendedTestdataGssapiProxyDockerfile, + "test/extended/testdata/gssapi/proxy/configure.sh": testExtendedTestdataGssapiProxyConfigureSh, + "test/extended/testdata/gssapi/proxy/gssapiproxy-buildconfig.yaml": testExtendedTestdataGssapiProxyGssapiproxyBuildconfigYaml, + "test/extended/testdata/gssapi/proxy/gssapiproxy-deploymentconfig.yaml": testExtendedTestdataGssapiProxyGssapiproxyDeploymentconfigYaml, + "test/extended/testdata/gssapi/proxy/gssapiproxy-imagestream.yaml": testExtendedTestdataGssapiProxyGssapiproxyImagestreamYaml, + "test/extended/testdata/gssapi/proxy/gssapiproxy-service.yaml": testExtendedTestdataGssapiProxyGssapiproxyServiceYaml, + "test/extended/testdata/gssapi/proxy/healthz": testExtendedTestdataGssapiProxyHealthz, + "test/extended/testdata/gssapi/proxy/kadm5.acl": testExtendedTestdataGssapiProxyKadm5Acl, + "test/extended/testdata/gssapi/proxy/kdc.conf": testExtendedTestdataGssapiProxyKdcConf, + "test/extended/testdata/gssapi/proxy/krb5.conf": testExtendedTestdataGssapiProxyKrb5Conf, + "test/extended/testdata/gssapi/proxy/proxy.conf": testExtendedTestdataGssapiProxyProxyConf, + "test/extended/testdata/gssapi/scripts/gssapi-tests.sh": testExtendedTestdataGssapiScriptsGssapiTestsSh, + "test/extended/testdata/gssapi/scripts/test-wrapper.sh": testExtendedTestdataGssapiScriptsTestWrapperSh, + "test/extended/testdata/gssapi/ubuntu/base/Dockerfile": testExtendedTestdataGssapiUbuntuBaseDockerfile, + "test/extended/testdata/gssapi/ubuntu/kerberos/Dockerfile": testExtendedTestdataGssapiUbuntuKerberosDockerfile, + "test/extended/testdata/gssapi/ubuntu/kerberos_configured/Dockerfile": testExtendedTestdataGssapiUbuntuKerberos_configuredDockerfile, + "test/extended/testdata/hello-builder/Dockerfile": testExtendedTestdataHelloBuilderDockerfile, + "test/extended/testdata/hello-builder/scripts/assemble": testExtendedTestdataHelloBuilderScriptsAssemble, + "test/extended/testdata/hello-builder/scripts/run": testExtendedTestdataHelloBuilderScriptsRun, + "test/extended/testdata/idling-echo-server-rc.yaml": testExtendedTestdataIdlingEchoServerRcYaml, + "test/extended/testdata/idling-echo-server.yaml": testExtendedTestdataIdlingEchoServerYaml, + "test/extended/testdata/image/deployment-with-annotation-trigger.yaml": testExtendedTestdataImageDeploymentWithAnnotationTriggerYaml, + "test/extended/testdata/image/test-image.json": testExtendedTestdataImageTestImageJson, + "test/extended/testdata/image-pull-secrets/dc-with-new-pull-secret.yaml": testExtendedTestdataImagePullSecretsDcWithNewPullSecretYaml, + "test/extended/testdata/image-pull-secrets/dc-with-old-pull-secret.yaml": testExtendedTestdataImagePullSecretsDcWithOldPullSecretYaml, + "test/extended/testdata/image-pull-secrets/pod-with-new-pull-secret.yaml": testExtendedTestdataImagePullSecretsPodWithNewPullSecretYaml, + "test/extended/testdata/image-pull-secrets/pod-with-no-pull-secret.yaml": testExtendedTestdataImagePullSecretsPodWithNoPullSecretYaml, + "test/extended/testdata/image-pull-secrets/pod-with-old-pull-secret.yaml": testExtendedTestdataImagePullSecretsPodWithOldPullSecretYaml, + "test/extended/testdata/image_ecosystem/perl-hotdeploy/index.pl": testExtendedTestdataImage_ecosystemPerlHotdeployIndexPl, + "test/extended/testdata/image_ecosystem/perl-hotdeploy/lib/My/Test.pm": testExtendedTestdataImage_ecosystemPerlHotdeployLibMyTestPm, + "test/extended/testdata/image_ecosystem/perl-hotdeploy/perl.json": testExtendedTestdataImage_ecosystemPerlHotdeployPerlJson, + "test/extended/testdata/imagestream-jenkins-slave-pods.yaml": testExtendedTestdataImagestreamJenkinsSlavePodsYaml, + "test/extended/testdata/imagestreamtag-jenkins-slave-pods.yaml": testExtendedTestdataImagestreamtagJenkinsSlavePodsYaml, + "test/extended/testdata/jenkins-plugin/build-job-clone.xml": testExtendedTestdataJenkinsPluginBuildJobCloneXml, + "test/extended/testdata/jenkins-plugin/build-job-slave.xml": testExtendedTestdataJenkinsPluginBuildJobSlaveXml, + "test/extended/testdata/jenkins-plugin/build-job.xml": testExtendedTestdataJenkinsPluginBuildJobXml, + "test/extended/testdata/jenkins-plugin/build-with-env-job.xml": testExtendedTestdataJenkinsPluginBuildWithEnvJobXml, + "test/extended/testdata/jenkins-plugin/build-with-exec-steps.xml": testExtendedTestdataJenkinsPluginBuildWithExecStepsXml, + "test/extended/testdata/jenkins-plugin/create-job.xml": testExtendedTestdataJenkinsPluginCreateJobXml, + "test/extended/testdata/jenkins-plugin/delete-job-keys.xml": testExtendedTestdataJenkinsPluginDeleteJobKeysXml, + "test/extended/testdata/jenkins-plugin/delete-job-labels.xml": testExtendedTestdataJenkinsPluginDeleteJobLabelsXml, + "test/extended/testdata/jenkins-plugin/delete-job.xml": testExtendedTestdataJenkinsPluginDeleteJobXml, + "test/extended/testdata/jenkins-plugin/imagestream-scm-dsl-job.xml": testExtendedTestdataJenkinsPluginImagestreamScmDslJobXml, + "test/extended/testdata/jenkins-plugin/imagestream-scm-job.xml": testExtendedTestdataJenkinsPluginImagestreamScmJobXml, + "test/extended/testdata/jenkins-plugin/multitag-job.xml": testExtendedTestdataJenkinsPluginMultitagJobXml, + "test/extended/testdata/jenkins-plugin/multitag-template.json": testExtendedTestdataJenkinsPluginMultitagTemplateJson, + "test/extended/testdata/jenkins-plugin/shared-resources-template.json": testExtendedTestdataJenkinsPluginSharedResourcesTemplateJson, + "test/extended/testdata/jenkins-slave-template.yaml": testExtendedTestdataJenkinsSlaveTemplateYaml, + "test/extended/testdata/jobs/v1.yaml": testExtendedTestdataJobsV1Yaml, + "test/extended/testdata/ldap/groupsync/ad/blacklist_ldap.txt": testExtendedTestdataLdapGroupsyncAdBlacklist_ldapTxt, + "test/extended/testdata/ldap/groupsync/ad/blacklist_openshift.txt": testExtendedTestdataLdapGroupsyncAdBlacklist_openshiftTxt, + "test/extended/testdata/ldap/groupsync/ad/ldapgroupuids.txt": testExtendedTestdataLdapGroupsyncAdLdapgroupuidsTxt, + "test/extended/testdata/ldap/groupsync/ad/osgroupuids.txt": testExtendedTestdataLdapGroupsyncAdOsgroupuidsTxt, + "test/extended/testdata/ldap/groupsync/ad/sync-config-dn-everywhere.yaml": testExtendedTestdataLdapGroupsyncAdSyncConfigDnEverywhereYaml, + "test/extended/testdata/ldap/groupsync/ad/sync-config-paging.yaml": testExtendedTestdataLdapGroupsyncAdSyncConfigPagingYaml, + "test/extended/testdata/ldap/groupsync/ad/sync-config-partially-user-defined.yaml": testExtendedTestdataLdapGroupsyncAdSyncConfigPartiallyUserDefinedYaml, + "test/extended/testdata/ldap/groupsync/ad/sync-config-user-defined.yaml": testExtendedTestdataLdapGroupsyncAdSyncConfigUserDefinedYaml, + "test/extended/testdata/ldap/groupsync/ad/sync-config.yaml": testExtendedTestdataLdapGroupsyncAdSyncConfigYaml, + "test/extended/testdata/ldap/groupsync/ad/valid_all_blacklist_sync.yaml": testExtendedTestdataLdapGroupsyncAdValid_all_blacklist_syncYaml, + "test/extended/testdata/ldap/groupsync/ad/valid_all_ldap_sync.yaml": testExtendedTestdataLdapGroupsyncAdValid_all_ldap_syncYaml, + "test/extended/testdata/ldap/groupsync/ad/valid_all_ldap_sync_dn_everywhere.yaml": testExtendedTestdataLdapGroupsyncAdValid_all_ldap_sync_dn_everywhereYaml, + "test/extended/testdata/ldap/groupsync/ad/valid_all_ldap_sync_partially_user_defined.yaml": testExtendedTestdataLdapGroupsyncAdValid_all_ldap_sync_partially_user_definedYaml, + "test/extended/testdata/ldap/groupsync/ad/valid_all_ldap_sync_prune.yaml": testExtendedTestdataLdapGroupsyncAdValid_all_ldap_sync_pruneYaml, + "test/extended/testdata/ldap/groupsync/ad/valid_all_ldap_sync_user_defined.yaml": testExtendedTestdataLdapGroupsyncAdValid_all_ldap_sync_user_definedYaml, + "test/extended/testdata/ldap/groupsync/ad/valid_all_openshift_blacklist_sync.yaml": testExtendedTestdataLdapGroupsyncAdValid_all_openshift_blacklist_syncYaml, + "test/extended/testdata/ldap/groupsync/ad/valid_whitelist_sync.yaml": testExtendedTestdataLdapGroupsyncAdValid_whitelist_syncYaml, + "test/extended/testdata/ldap/groupsync/ad/valid_whitelist_union_sync.yaml": testExtendedTestdataLdapGroupsyncAdValid_whitelist_union_syncYaml, + "test/extended/testdata/ldap/groupsync/ad/whitelist_ldap.txt": testExtendedTestdataLdapGroupsyncAdWhitelist_ldapTxt, + "test/extended/testdata/ldap/groupsync/ad/whitelist_openshift.txt": testExtendedTestdataLdapGroupsyncAdWhitelist_openshiftTxt, + "test/extended/testdata/ldap/groupsync/augmented-ad/blacklist_ldap.txt": testExtendedTestdataLdapGroupsyncAugmentedAdBlacklist_ldapTxt, + "test/extended/testdata/ldap/groupsync/augmented-ad/blacklist_openshift.txt": testExtendedTestdataLdapGroupsyncAugmentedAdBlacklist_openshiftTxt, + "test/extended/testdata/ldap/groupsync/augmented-ad/ldapgroupuids.txt": testExtendedTestdataLdapGroupsyncAugmentedAdLdapgroupuidsTxt, + "test/extended/testdata/ldap/groupsync/augmented-ad/osgroupuids.txt": testExtendedTestdataLdapGroupsyncAugmentedAdOsgroupuidsTxt, + "test/extended/testdata/ldap/groupsync/augmented-ad/sync-config-dn-everywhere.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdSyncConfigDnEverywhereYaml, + "test/extended/testdata/ldap/groupsync/augmented-ad/sync-config-paging.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdSyncConfigPagingYaml, + "test/extended/testdata/ldap/groupsync/augmented-ad/sync-config-partially-user-defined.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdSyncConfigPartiallyUserDefinedYaml, + "test/extended/testdata/ldap/groupsync/augmented-ad/sync-config-user-defined.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdSyncConfigUserDefinedYaml, + "test/extended/testdata/ldap/groupsync/augmented-ad/sync-config.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdSyncConfigYaml, + "test/extended/testdata/ldap/groupsync/augmented-ad/valid_all_blacklist_sync.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_all_blacklist_syncYaml, + "test/extended/testdata/ldap/groupsync/augmented-ad/valid_all_ldap_sync.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_all_ldap_syncYaml, + "test/extended/testdata/ldap/groupsync/augmented-ad/valid_all_ldap_sync_delete_prune.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_all_ldap_sync_delete_pruneYaml, + "test/extended/testdata/ldap/groupsync/augmented-ad/valid_all_ldap_sync_dn_everywhere.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_all_ldap_sync_dn_everywhereYaml, + "test/extended/testdata/ldap/groupsync/augmented-ad/valid_all_ldap_sync_partially_user_defined.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_all_ldap_sync_partially_user_definedYaml, + "test/extended/testdata/ldap/groupsync/augmented-ad/valid_all_ldap_sync_prune.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_all_ldap_sync_pruneYaml, + "test/extended/testdata/ldap/groupsync/augmented-ad/valid_all_ldap_sync_user_defined.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_all_ldap_sync_user_definedYaml, + "test/extended/testdata/ldap/groupsync/augmented-ad/valid_all_openshift_blacklist_sync.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_all_openshift_blacklist_syncYaml, + "test/extended/testdata/ldap/groupsync/augmented-ad/valid_whitelist_sync.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_whitelist_syncYaml, + "test/extended/testdata/ldap/groupsync/augmented-ad/valid_whitelist_union_sync.yaml": testExtendedTestdataLdapGroupsyncAugmentedAdValid_whitelist_union_syncYaml, + "test/extended/testdata/ldap/groupsync/augmented-ad/whitelist_ldap.txt": testExtendedTestdataLdapGroupsyncAugmentedAdWhitelist_ldapTxt, + "test/extended/testdata/ldap/groupsync/augmented-ad/whitelist_openshift.txt": testExtendedTestdataLdapGroupsyncAugmentedAdWhitelist_openshiftTxt, + "test/extended/testdata/ldap/groupsync/rfc2307/blacklist_ldap.txt": testExtendedTestdataLdapGroupsyncRfc2307Blacklist_ldapTxt, + "test/extended/testdata/ldap/groupsync/rfc2307/blacklist_openshift.txt": testExtendedTestdataLdapGroupsyncRfc2307Blacklist_openshiftTxt, + "test/extended/testdata/ldap/groupsync/rfc2307/ldapgroupuids.txt": testExtendedTestdataLdapGroupsyncRfc2307LdapgroupuidsTxt, + "test/extended/testdata/ldap/groupsync/rfc2307/osgroupuids.txt": testExtendedTestdataLdapGroupsyncRfc2307OsgroupuidsTxt, + "test/extended/testdata/ldap/groupsync/rfc2307/sync-config-dn-everywhere.yaml": testExtendedTestdataLdapGroupsyncRfc2307SyncConfigDnEverywhereYaml, + "test/extended/testdata/ldap/groupsync/rfc2307/sync-config-paging.yaml": testExtendedTestdataLdapGroupsyncRfc2307SyncConfigPagingYaml, + "test/extended/testdata/ldap/groupsync/rfc2307/sync-config-partially-user-defined.yaml": testExtendedTestdataLdapGroupsyncRfc2307SyncConfigPartiallyUserDefinedYaml, + "test/extended/testdata/ldap/groupsync/rfc2307/sync-config-tolerating.yaml": testExtendedTestdataLdapGroupsyncRfc2307SyncConfigToleratingYaml, + "test/extended/testdata/ldap/groupsync/rfc2307/sync-config-user-defined.yaml": testExtendedTestdataLdapGroupsyncRfc2307SyncConfigUserDefinedYaml, + "test/extended/testdata/ldap/groupsync/rfc2307/sync-config.yaml": testExtendedTestdataLdapGroupsyncRfc2307SyncConfigYaml, + "test/extended/testdata/ldap/groupsync/rfc2307/valid_all_blacklist_sync.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_all_blacklist_syncYaml, + "test/extended/testdata/ldap/groupsync/rfc2307/valid_all_ldap_sync.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_all_ldap_syncYaml, + "test/extended/testdata/ldap/groupsync/rfc2307/valid_all_ldap_sync_dn_everywhere.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_all_ldap_sync_dn_everywhereYaml, + "test/extended/testdata/ldap/groupsync/rfc2307/valid_all_ldap_sync_partially_user_defined.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_all_ldap_sync_partially_user_definedYaml, + "test/extended/testdata/ldap/groupsync/rfc2307/valid_all_ldap_sync_prune.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_all_ldap_sync_pruneYaml, + "test/extended/testdata/ldap/groupsync/rfc2307/valid_all_ldap_sync_tolerating.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_all_ldap_sync_toleratingYaml, + "test/extended/testdata/ldap/groupsync/rfc2307/valid_all_ldap_sync_user_defined.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_all_ldap_sync_user_definedYaml, + "test/extended/testdata/ldap/groupsync/rfc2307/valid_all_openshift_blacklist_sync.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_all_openshift_blacklist_syncYaml, + "test/extended/testdata/ldap/groupsync/rfc2307/valid_whitelist_sync.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_whitelist_syncYaml, + "test/extended/testdata/ldap/groupsync/rfc2307/valid_whitelist_union_sync.yaml": testExtendedTestdataLdapGroupsyncRfc2307Valid_whitelist_union_syncYaml, + "test/extended/testdata/ldap/groupsync/rfc2307/whitelist_ldap.txt": testExtendedTestdataLdapGroupsyncRfc2307Whitelist_ldapTxt, + "test/extended/testdata/ldap/groupsync/rfc2307/whitelist_openshift.txt": testExtendedTestdataLdapGroupsyncRfc2307Whitelist_openshiftTxt, + "test/extended/testdata/ldap/groupsync.sh": testExtendedTestdataLdapGroupsyncSh, + "test/extended/testdata/ldap/ldapserver-config-cm.yaml": testExtendedTestdataLdapLdapserverConfigCmYaml, + "test/extended/testdata/ldap/ldapserver-deployment.yaml": testExtendedTestdataLdapLdapserverDeploymentYaml, + "test/extended/testdata/ldap/ldapserver-scripts-cm.yaml": testExtendedTestdataLdapLdapserverScriptsCmYaml, + "test/extended/testdata/ldap/ldapserver-service.yaml": testExtendedTestdataLdapLdapserverServiceYaml, + "test/extended/testdata/long_names/Dockerfile": testExtendedTestdataLong_namesDockerfile, + "test/extended/testdata/long_names/fixture.json": testExtendedTestdataLong_namesFixtureJson, + "test/extended/testdata/marketplace/csc/02-csc.yaml": testExtendedTestdataMarketplaceCsc02CscYaml, + "test/extended/testdata/marketplace/opsrc/02-opsrc.yaml": testExtendedTestdataMarketplaceOpsrc02OpsrcYaml, + "test/extended/testdata/multi-namespace-pipeline.yaml": testExtendedTestdataMultiNamespacePipelineYaml, + "test/extended/testdata/multi-namespace-template.yaml": testExtendedTestdataMultiNamespaceTemplateYaml, + "test/extended/testdata/oauthserver/cabundle-cm.yaml": testExtendedTestdataOauthserverCabundleCmYaml, + "test/extended/testdata/oauthserver/oauth-network.yaml": testExtendedTestdataOauthserverOauthNetworkYaml, + "test/extended/testdata/oauthserver/oauth-pod.yaml": testExtendedTestdataOauthserverOauthPodYaml, + "test/extended/testdata/oauthserver/oauth-sa.yaml": testExtendedTestdataOauthserverOauthSaYaml, + "test/extended/testdata/olm/operatorgroup.yaml": testExtendedTestdataOlmOperatorgroupYaml, + "test/extended/testdata/olm/subscription.yaml": testExtendedTestdataOlmSubscriptionYaml, + "test/extended/testdata/openshift-secret-to-jenkins-credential.yaml": testExtendedTestdataOpenshiftSecretToJenkinsCredentialYaml, + "test/extended/testdata/releases/payload-1/etcd-operator/image-references": testExtendedTestdataReleasesPayload1EtcdOperatorImageReferences, + "test/extended/testdata/releases/payload-1/etcd-operator/manifest.yaml": testExtendedTestdataReleasesPayload1EtcdOperatorManifestYaml, + "test/extended/testdata/releases/payload-1/image-registry/10_image-registry_crd.yaml": testExtendedTestdataReleasesPayload1ImageRegistry10_imageRegistry_crdYaml, + "test/extended/testdata/releases/payload-1/image-registry/image-references": testExtendedTestdataReleasesPayload1ImageRegistryImageReferences, + "test/extended/testdata/releases/payload-1/image-registry/manifest.yaml": testExtendedTestdataReleasesPayload1ImageRegistryManifestYaml, + "test/extended/testdata/roles/empty-role.yaml": testExtendedTestdataRolesEmptyRoleYaml, + "test/extended/testdata/roles/policy-clusterroles.yaml": testExtendedTestdataRolesPolicyClusterrolesYaml, + "test/extended/testdata/roles/policy-roles.yaml": testExtendedTestdataRolesPolicyRolesYaml, + "test/extended/testdata/router/ingress.yaml": testExtendedTestdataRouterIngressYaml, + "test/extended/testdata/router/reencrypt-serving-cert.yaml": testExtendedTestdataRouterReencryptServingCertYaml, + "test/extended/testdata/router/router-common.yaml": testExtendedTestdataRouterRouterCommonYaml, + "test/extended/testdata/router/router-config-manager.yaml": testExtendedTestdataRouterRouterConfigManagerYaml, + "test/extended/testdata/router/router-grpc-interop.yaml": testExtendedTestdataRouterRouterGrpcInteropYaml, + "test/extended/testdata/router/router-h2spec.yaml": testExtendedTestdataRouterRouterH2specYaml, + "test/extended/testdata/router/router-http-echo-server.yaml": testExtendedTestdataRouterRouterHttpEchoServerYaml, + "test/extended/testdata/router/router-http2.yaml": testExtendedTestdataRouterRouterHttp2Yaml, + "test/extended/testdata/router/router-idle.yaml": testExtendedTestdataRouterRouterIdleYaml, + "test/extended/testdata/router/router-metrics.yaml": testExtendedTestdataRouterRouterMetricsYaml, + "test/extended/testdata/router/router-override-domains.yaml": testExtendedTestdataRouterRouterOverrideDomainsYaml, + "test/extended/testdata/router/router-override.yaml": testExtendedTestdataRouterRouterOverrideYaml, + "test/extended/testdata/router/router-scoped.yaml": testExtendedTestdataRouterRouterScopedYaml, + "test/extended/testdata/router/weighted-router.yaml": testExtendedTestdataRouterWeightedRouterYaml, + "test/extended/testdata/run_policy/parallel-bc.yaml": testExtendedTestdataRun_policyParallelBcYaml, + "test/extended/testdata/run_policy/serial-bc.yaml": testExtendedTestdataRun_policySerialBcYaml, + "test/extended/testdata/run_policy/serial-latest-only-bc.yaml": testExtendedTestdataRun_policySerialLatestOnlyBcYaml, + "test/extended/testdata/s2i-dropcaps/root-access-build.yaml": testExtendedTestdataS2iDropcapsRootAccessBuildYaml, + "test/extended/testdata/s2i-dropcaps/rootable-ruby/Dockerfile": testExtendedTestdataS2iDropcapsRootableRubyDockerfile, + "test/extended/testdata/s2i-dropcaps/rootable-ruby/adduser": testExtendedTestdataS2iDropcapsRootableRubyAdduser, + "test/extended/testdata/s2i-dropcaps/rootable-ruby/assemble": testExtendedTestdataS2iDropcapsRootableRubyAssemble, + "test/extended/testdata/sample-image-stream.json": testExtendedTestdataSampleImageStreamJson, + "test/extended/testdata/samplepipeline-withenvs.yaml": testExtendedTestdataSamplepipelineWithenvsYaml, + "test/extended/testdata/service-serving-cert/nginx-serving-cert.conf": testExtendedTestdataServiceServingCertNginxServingCertConf, + "test/extended/testdata/signer-buildconfig.yaml": testExtendedTestdataSignerBuildconfigYaml, + "test/extended/testdata/stable-busybox.yaml": testExtendedTestdataStableBusyboxYaml, + "test/extended/testdata/templates/crunchydata-pod.json": testExtendedTestdataTemplatesCrunchydataPodJson, + "test/extended/testdata/templates/guestbook.json": testExtendedTestdataTemplatesGuestbookJson, + "test/extended/testdata/templates/guestbook_list.json": testExtendedTestdataTemplatesGuestbook_listJson, + "test/extended/testdata/templates/templateinstance_badobject.yaml": testExtendedTestdataTemplatesTemplateinstance_badobjectYaml, + "test/extended/testdata/templates/templateinstance_objectkinds.yaml": testExtendedTestdataTemplatesTemplateinstance_objectkindsYaml, + "test/extended/testdata/templates/templateinstance_readiness.yaml": testExtendedTestdataTemplatesTemplateinstance_readinessYaml, + "test/extended/testdata/templates/templateservicebroker_bind.yaml": testExtendedTestdataTemplatesTemplateservicebroker_bindYaml, + "test/extended/testdata/test-cli-debug.yaml": testExtendedTestdataTestCliDebugYaml, + "test/extended/testdata/test-deployment-config.yaml": testExtendedTestdataTestDeploymentConfigYaml, + "test/extended/testdata/test-env-pod.json": testExtendedTestdataTestEnvPodJson, + "test/extended/testdata/test-gitserver.yaml": testExtendedTestdataTestGitserverYaml, + "test/extended/testdata/test-replication-controller.yaml": testExtendedTestdataTestReplicationControllerYaml, + "test/extended/testdata/test-secret.json": testExtendedTestdataTestSecretJson, + "test/extended/testdata/verifyservice-pipeline-template.yaml": testExtendedTestdataVerifyservicePipelineTemplateYaml, } // AssetDir returns the file names below a certain @@ -62079,7 +54673,6 @@ var _bintree = &bintree{nil, map[string]*bintree{ }}, "image-streams": {nil, map[string]*bintree{ "image-streams-centos7.json": {examplesImageStreamsImageStreamsCentos7Json, map[string]*bintree{}}, - "image-streams-rhel7.json": {examplesImageStreamsImageStreamsRhel7Json, map[string]*bintree{}}, }}, "jenkins": {nil, map[string]*bintree{ "application-template.json": {examplesJenkinsApplicationTemplateJson, map[string]*bintree{}}, @@ -62263,6 +54856,7 @@ var _bintree = &bintree{nil, map[string]*bintree{ "test-docker-build.json": {testExtendedTestdataBuildsTestDockerBuildJson, map[string]*bintree{}}, "test-docker-no-outputname.json": {testExtendedTestdataBuildsTestDockerNoOutputnameJson, map[string]*bintree{}}, "test-env-build.json": {testExtendedTestdataBuildsTestEnvBuildJson, map[string]*bintree{}}, + "test-image-stream.json": {testExtendedTestdataBuildsTestImageStreamJson, map[string]*bintree{}}, "test-imagechangetriggers.yaml": {testExtendedTestdataBuildsTestImagechangetriggersYaml, map[string]*bintree{}}, "test-imageresolution-custom-build.yaml": {testExtendedTestdataBuildsTestImageresolutionCustomBuildYaml, map[string]*bintree{}}, "test-imageresolution-docker-build.yaml": {testExtendedTestdataBuildsTestImageresolutionDockerBuildYaml, map[string]*bintree{}}, @@ -62353,78 +54947,45 @@ var _bintree = &bintree{nil, map[string]*bintree{ }}, "test": {nil, map[string]*bintree{ "cmd": {nil, map[string]*bintree{ - "admin.sh": {testExtendedTestdataCmdTestCmdAdminSh, map[string]*bintree{}}, - "annotations.sh": {testExtendedTestdataCmdTestCmdAnnotationsSh, map[string]*bintree{}}, - "apiresources.sh": {testExtendedTestdataCmdTestCmdApiresourcesSh, map[string]*bintree{}}, - "authentication.sh": {testExtendedTestdataCmdTestCmdAuthenticationSh, map[string]*bintree{}}, - "basicresources.sh": {testExtendedTestdataCmdTestCmdBasicresourcesSh, map[string]*bintree{}}, - "builds.sh": {testExtendedTestdataCmdTestCmdBuildsSh, map[string]*bintree{}}, - "completions.sh": {testExtendedTestdataCmdTestCmdCompletionsSh, map[string]*bintree{}}, - "config.sh": {testExtendedTestdataCmdTestCmdConfigSh, map[string]*bintree{}}, - "convert.sh": {testExtendedTestdataCmdTestCmdConvertSh, map[string]*bintree{}}, - "create.sh": {testExtendedTestdataCmdTestCmdCreateSh, map[string]*bintree{}}, - "debug.sh": {testExtendedTestdataCmdTestCmdDebugSh, map[string]*bintree{}}, - "deployments.sh": {testExtendedTestdataCmdTestCmdDeploymentsSh, map[string]*bintree{}}, - "describer.sh": {testExtendedTestdataCmdTestCmdDescriberSh, map[string]*bintree{}}, - "edit.sh": {testExtendedTestdataCmdTestCmdEditSh, map[string]*bintree{}}, - "env.sh": {testExtendedTestdataCmdTestCmdEnvSh, map[string]*bintree{}}, - "framework-test.sh": {testExtendedTestdataCmdTestCmdFrameworkTestSh, map[string]*bintree{}}, - "get.sh": {testExtendedTestdataCmdTestCmdGetSh, map[string]*bintree{}}, - "help.sh": {testExtendedTestdataCmdTestCmdHelpSh, map[string]*bintree{}}, - "idle.sh": {testExtendedTestdataCmdTestCmdIdleSh, map[string]*bintree{}}, - "image-lookup.sh": {testExtendedTestdataCmdTestCmdImageLookupSh, map[string]*bintree{}}, - "images.sh": {testExtendedTestdataCmdTestCmdImagesSh, map[string]*bintree{}}, - "login.sh": {testExtendedTestdataCmdTestCmdLoginSh, map[string]*bintree{}}, - "migrate.sh": {testExtendedTestdataCmdTestCmdMigrateSh, map[string]*bintree{}}, - "newapp.sh": {testExtendedTestdataCmdTestCmdNewappSh, map[string]*bintree{}}, - "observe.sh": {testExtendedTestdataCmdTestCmdObserveSh, map[string]*bintree{}}, - "policy-storage-admin.sh": {testExtendedTestdataCmdTestCmdPolicyStorageAdminSh, map[string]*bintree{}}, - "policy.sh": {testExtendedTestdataCmdTestCmdPolicySh, map[string]*bintree{}}, - "printer.sh": {testExtendedTestdataCmdTestCmdPrinterSh, map[string]*bintree{}}, - "projects.sh": {testExtendedTestdataCmdTestCmdProjectsSh, map[string]*bintree{}}, - "quota.sh": {testExtendedTestdataCmdTestCmdQuotaSh, map[string]*bintree{}}, - "registry.sh": {testExtendedTestdataCmdTestCmdRegistrySh, map[string]*bintree{}}, - "routes.sh": {testExtendedTestdataCmdTestCmdRoutesSh, map[string]*bintree{}}, - "rsync.sh": {testExtendedTestdataCmdTestCmdRsyncSh, map[string]*bintree{}}, - "run.sh": {testExtendedTestdataCmdTestCmdRunSh, map[string]*bintree{}}, - "secrets.sh": {testExtendedTestdataCmdTestCmdSecretsSh, map[string]*bintree{}}, - "services.sh": {testExtendedTestdataCmdTestCmdServicesSh, map[string]*bintree{}}, - "set-data.sh": {testExtendedTestdataCmdTestCmdSetDataSh, map[string]*bintree{}}, - "set-image.sh": {testExtendedTestdataCmdTestCmdSetImageSh, map[string]*bintree{}}, - "set-liveness-probe.sh": {testExtendedTestdataCmdTestCmdSetLivenessProbeSh, map[string]*bintree{}}, - "setbuildhook.sh": {testExtendedTestdataCmdTestCmdSetbuildhookSh, map[string]*bintree{}}, - "setbuildsecret.sh": {testExtendedTestdataCmdTestCmdSetbuildsecretSh, map[string]*bintree{}}, - "status.sh": {testExtendedTestdataCmdTestCmdStatusSh, map[string]*bintree{}}, - "templates.sh": {testExtendedTestdataCmdTestCmdTemplatesSh, map[string]*bintree{}}, + "admin.sh": {testExtendedTestdataCmdTestCmdAdminSh, map[string]*bintree{}}, + "annotations.sh": {testExtendedTestdataCmdTestCmdAnnotationsSh, map[string]*bintree{}}, + "apiresources.sh": {testExtendedTestdataCmdTestCmdApiresourcesSh, map[string]*bintree{}}, + "authentication.sh": {testExtendedTestdataCmdTestCmdAuthenticationSh, map[string]*bintree{}}, + "basicresources.sh": {testExtendedTestdataCmdTestCmdBasicresourcesSh, map[string]*bintree{}}, + "builds.sh": {testExtendedTestdataCmdTestCmdBuildsSh, map[string]*bintree{}}, + "completions.sh": {testExtendedTestdataCmdTestCmdCompletionsSh, map[string]*bintree{}}, + "config.sh": {testExtendedTestdataCmdTestCmdConfigSh, map[string]*bintree{}}, + "create.sh": {testExtendedTestdataCmdTestCmdCreateSh, map[string]*bintree{}}, + "deployments.sh": {testExtendedTestdataCmdTestCmdDeploymentsSh, map[string]*bintree{}}, + "describer.sh": {testExtendedTestdataCmdTestCmdDescriberSh, map[string]*bintree{}}, + "edit.sh": {testExtendedTestdataCmdTestCmdEditSh, map[string]*bintree{}}, + "env.sh": {testExtendedTestdataCmdTestCmdEnvSh, map[string]*bintree{}}, + "framework-test.sh": {testExtendedTestdataCmdTestCmdFrameworkTestSh, map[string]*bintree{}}, + "get.sh": {testExtendedTestdataCmdTestCmdGetSh, map[string]*bintree{}}, + "help.sh": {testExtendedTestdataCmdTestCmdHelpSh, map[string]*bintree{}}, + "idle.sh": {testExtendedTestdataCmdTestCmdIdleSh, map[string]*bintree{}}, + "image-lookup.sh": {testExtendedTestdataCmdTestCmdImageLookupSh, map[string]*bintree{}}, + "images.sh": {testExtendedTestdataCmdTestCmdImagesSh, map[string]*bintree{}}, + "login.sh": {testExtendedTestdataCmdTestCmdLoginSh, map[string]*bintree{}}, + "migrate.sh": {testExtendedTestdataCmdTestCmdMigrateSh, map[string]*bintree{}}, + "newapp.sh": {testExtendedTestdataCmdTestCmdNewappSh, map[string]*bintree{}}, + "policy.sh": {testExtendedTestdataCmdTestCmdPolicySh, map[string]*bintree{}}, + "printer.sh": {testExtendedTestdataCmdTestCmdPrinterSh, map[string]*bintree{}}, + "projects.sh": {testExtendedTestdataCmdTestCmdProjectsSh, map[string]*bintree{}}, + "quota.sh": {testExtendedTestdataCmdTestCmdQuotaSh, map[string]*bintree{}}, + "registry.sh": {testExtendedTestdataCmdTestCmdRegistrySh, map[string]*bintree{}}, + "routes.sh": {testExtendedTestdataCmdTestCmdRoutesSh, map[string]*bintree{}}, + "run.sh": {testExtendedTestdataCmdTestCmdRunSh, map[string]*bintree{}}, + "secrets.sh": {testExtendedTestdataCmdTestCmdSecretsSh, map[string]*bintree{}}, + "services.sh": {testExtendedTestdataCmdTestCmdServicesSh, map[string]*bintree{}}, + "set-data.sh": {testExtendedTestdataCmdTestCmdSetDataSh, map[string]*bintree{}}, + "set-image.sh": {testExtendedTestdataCmdTestCmdSetImageSh, map[string]*bintree{}}, + "set-liveness-probe.sh": {testExtendedTestdataCmdTestCmdSetLivenessProbeSh, map[string]*bintree{}}, + "setbuildhook.sh": {testExtendedTestdataCmdTestCmdSetbuildhookSh, map[string]*bintree{}}, + "setbuildsecret.sh": {testExtendedTestdataCmdTestCmdSetbuildsecretSh, map[string]*bintree{}}, + "status.sh": {testExtendedTestdataCmdTestCmdStatusSh, map[string]*bintree{}}, + "templates.sh": {testExtendedTestdataCmdTestCmdTemplatesSh, map[string]*bintree{}}, "testdata": {nil, map[string]*bintree{ - "app-scenarios": {nil, map[string]*bintree{ - "docker-compose": {nil, map[string]*bintree{ - "complex": {nil, map[string]*bintree{ - "app": {nil, map[string]*bintree{ - "Dockerfile": {testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexAppDockerfile, map[string]*bintree{}}, - }}, - "docker-compose.generated.yaml": {testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeGeneratedYaml, map[string]*bintree{}}, - "docker-compose.imported.yaml": {testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeImportedYaml, map[string]*bintree{}}, - "docker-compose.yml": {testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexDockerComposeYml, map[string]*bintree{}}, - "nginx": {nil, map[string]*bintree{ - "Dockerfile": {testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeComplexNginxDockerfile, map[string]*bintree{}}, - }}, - }}, - "wordpress": {nil, map[string]*bintree{ - "docker-compose.yml": {testExtendedTestdataCmdTestCmdTestdataAppScenariosDockerComposeWordpressDockerComposeYml, map[string]*bintree{}}, - }}, - }}, - "k8s-lonely-pod.json": {testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sLonelyPodJson, map[string]*bintree{}}, - "k8s-sample-app.json": {testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sSampleAppJson, map[string]*bintree{}}, - "k8s-service-pod-no-rc.json": {testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sServicePodNoRcJson, map[string]*bintree{}}, - "k8s-service-with-nothing.json": {testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sServiceWithNothingJson, map[string]*bintree{}}, - "k8s-unserviced-rc.json": {testExtendedTestdataCmdTestCmdTestdataAppScenariosK8sUnservicedRcJson, map[string]*bintree{}}, - "new-project-deployed-app.yaml": {testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectDeployedAppYaml, map[string]*bintree{}}, - "new-project-no-build.yaml": {testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectNoBuildYaml, map[string]*bintree{}}, - "new-project-one-build.yaml": {testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectOneBuildYaml, map[string]*bintree{}}, - "new-project-two-deployment-configs.yaml": {testExtendedTestdataCmdTestCmdTestdataAppScenariosNewProjectTwoDeploymentConfigsYaml, map[string]*bintree{}}, - "petset.yaml": {testExtendedTestdataCmdTestCmdTestdataAppScenariosPetsetYaml, map[string]*bintree{}}, - }}, "application-template-custombuild.json": {testExtendedTestdataCmdTestCmdTestdataApplicationTemplateCustombuildJson, map[string]*bintree{}}, "application-template-dockerbuild.json": {testExtendedTestdataCmdTestCmdTestdataApplicationTemplateDockerbuildJson, map[string]*bintree{}}, "application-template-stibuild.json": {testExtendedTestdataCmdTestCmdTestdataApplicationTemplateStibuildJson, map[string]*bintree{}}, @@ -62479,15 +55040,9 @@ var _bintree = &bintree{nil, map[string]*bintree{ "json-no-extension": {testExtendedTestdataCmdTestCmdTestdataResourceBuilderJsonNoExtension, map[string]*bintree{}}, "yml-no-extension": {testExtendedTestdataCmdTestCmdTestdataResourceBuilderYmlNoExtension, map[string]*bintree{}}, }}, - "roles": {nil, map[string]*bintree{ - "empty-role.yaml": {testExtendedTestdataCmdTestCmdTestdataRolesEmptyRoleYaml, map[string]*bintree{}}, - "policy-clusterroles.yaml": {testExtendedTestdataCmdTestCmdTestdataRolesPolicyClusterrolesYaml, map[string]*bintree{}}, - "policy-roles.yaml": {testExtendedTestdataCmdTestCmdTestdataRolesPolicyRolesYaml, map[string]*bintree{}}, - }}, "rollingupdate-daemonset.yaml": {testExtendedTestdataCmdTestCmdTestdataRollingupdateDaemonsetYaml, map[string]*bintree{}}, "services.yaml": {testExtendedTestdataCmdTestCmdTestdataServicesYaml, map[string]*bintree{}}, "simple-deployment.yaml": {testExtendedTestdataCmdTestCmdTestdataSimpleDeploymentYaml, map[string]*bintree{}}, - "stable-busybox.yaml": {testExtendedTestdataCmdTestCmdTestdataStableBusyboxYaml, map[string]*bintree{}}, "statefulset.yaml": {testExtendedTestdataCmdTestCmdTestdataStatefulsetYaml, map[string]*bintree{}}, "templateinstance_objectkinds.yaml": {testExtendedTestdataCmdTestCmdTestdataTemplateinstance_objectkindsYaml, map[string]*bintree{}}, "templates": {nil, map[string]*bintree{ @@ -62513,7 +55068,6 @@ var _bintree = &bintree{nil, map[string]*bintree{ "test-service.json": {testExtendedTestdataCmdTestCmdTestdataTestServiceJson, map[string]*bintree{}}, "test-stream.yaml": {testExtendedTestdataCmdTestCmdTestdataTestStreamYaml, map[string]*bintree{}}, }}, - "timeout.sh": {testExtendedTestdataCmdTestCmdTimeoutSh, map[string]*bintree{}}, "triggers.sh": {testExtendedTestdataCmdTestCmdTriggersSh, map[string]*bintree{}}, "volumes.sh": {testExtendedTestdataCmdTestCmdVolumesSh, map[string]*bintree{}}, "whoami.sh": {testExtendedTestdataCmdTestCmdWhoamiSh, map[string]*bintree{}}, @@ -62521,13 +55075,6 @@ var _bintree = &bintree{nil, map[string]*bintree{ }}, }}, "config-map-jenkins-slave-pods.yaml": {testExtendedTestdataConfigMapJenkinsSlavePodsYaml, map[string]*bintree{}}, - "csi": {nil, map[string]*bintree{ - "aws-ebs": {nil, map[string]*bintree{ - "install-template.yaml": {testExtendedTestdataCsiAwsEbsInstallTemplateYaml, map[string]*bintree{}}, - "manifest.yaml": {testExtendedTestdataCsiAwsEbsManifestYaml, map[string]*bintree{}}, - "storageclass.yaml": {testExtendedTestdataCsiAwsEbsStorageclassYaml, map[string]*bintree{}}, - }}, - }}, "custom-secret-builder": {nil, map[string]*bintree{ "Dockerfile": {testExtendedTestdataCustomSecretBuilderDockerfile, map[string]*bintree{}}, "build.sh": {testExtendedTestdataCustomSecretBuilderBuildSh, map[string]*bintree{}}, @@ -62552,23 +55099,6 @@ var _bintree = &bintree{nil, map[string]*bintree{ "test-deployment-broken.yaml": {testExtendedTestdataDeploymentsTestDeploymentBrokenYaml, map[string]*bintree{}}, "test-deployment-test.yaml": {testExtendedTestdataDeploymentsTestDeploymentTestYaml, map[string]*bintree{}}, }}, - "disaster-recovery": {nil, map[string]*bintree{ - "restore-etcd.sh": {testExtendedTestdataDisasterRecoveryRestoreEtcdSh, map[string]*bintree{}}, - "rollback-A.yaml": {testExtendedTestdataDisasterRecoveryRollbackAYaml, map[string]*bintree{}}, - "rollback-B.yaml": {testExtendedTestdataDisasterRecoveryRollbackBYaml, map[string]*bintree{}}, - "ssh-bastion": {nil, map[string]*bintree{ - "clusterrole.yaml": {testExtendedTestdataDisasterRecoverySshBastionClusterroleYaml, map[string]*bintree{}}, - "clusterrolebinding.yaml": {testExtendedTestdataDisasterRecoverySshBastionClusterrolebindingYaml, map[string]*bintree{}}, - "deployment.yaml": {testExtendedTestdataDisasterRecoverySshBastionDeploymentYaml, map[string]*bintree{}}, - "namespace.yaml": {testExtendedTestdataDisasterRecoverySshBastionNamespaceYaml, map[string]*bintree{}}, - "role.yaml": {testExtendedTestdataDisasterRecoverySshBastionRoleYaml, map[string]*bintree{}}, - "rolebinding.yaml": {testExtendedTestdataDisasterRecoverySshBastionRolebindingYaml, map[string]*bintree{}}, - "service.yaml": {testExtendedTestdataDisasterRecoverySshBastionServiceYaml, map[string]*bintree{}}, - "serviceaccount.yaml": {testExtendedTestdataDisasterRecoverySshBastionServiceaccountYaml, map[string]*bintree{}}, - "sshd_config": {testExtendedTestdataDisasterRecoverySshBastionSshd_config, map[string]*bintree{}}, - }}, - "update_route_53.py": {testExtendedTestdataDisasterRecoveryUpdate_route_53Py, map[string]*bintree{}}, - }}, "forcepull-test.json": {testExtendedTestdataForcepullTestJson, map[string]*bintree{}}, "gssapi": {nil, map[string]*bintree{ "config": {nil, map[string]*bintree{ @@ -62740,6 +55270,7 @@ var _bintree = &bintree{nil, map[string]*bintree{ "whitelist_openshift.txt": {testExtendedTestdataLdapGroupsyncRfc2307Whitelist_openshiftTxt, map[string]*bintree{}}, }}, }}, + "groupsync.sh": {testExtendedTestdataLdapGroupsyncSh, map[string]*bintree{}}, "ldapserver-config-cm.yaml": {testExtendedTestdataLdapLdapserverConfigCmYaml, map[string]*bintree{}}, "ldapserver-deployment.yaml": {testExtendedTestdataLdapLdapserverDeploymentYaml, map[string]*bintree{}}, "ldapserver-scripts-cm.yaml": {testExtendedTestdataLdapLdapserverScriptsCmYaml, map[string]*bintree{}}, @@ -62823,6 +55354,7 @@ var _bintree = &bintree{nil, map[string]*bintree{ "nginx-serving-cert.conf": {testExtendedTestdataServiceServingCertNginxServingCertConf, map[string]*bintree{}}, }}, "signer-buildconfig.yaml": {testExtendedTestdataSignerBuildconfigYaml, map[string]*bintree{}}, + "stable-busybox.yaml": {testExtendedTestdataStableBusyboxYaml, map[string]*bintree{}}, "templates": {nil, map[string]*bintree{ "crunchydata-pod.json": {testExtendedTestdataTemplatesCrunchydataPodJson, map[string]*bintree{}}, "guestbook.json": {testExtendedTestdataTemplatesGuestbookJson, map[string]*bintree{}}, @@ -62833,27 +55365,14 @@ var _bintree = &bintree{nil, map[string]*bintree{ "templateservicebroker_bind.yaml": {testExtendedTestdataTemplatesTemplateservicebroker_bindYaml, map[string]*bintree{}}, }}, "test-cli-debug.yaml": {testExtendedTestdataTestCliDebugYaml, map[string]*bintree{}}, + "test-deployment-config.yaml": {testExtendedTestdataTestDeploymentConfigYaml, map[string]*bintree{}}, "test-env-pod.json": {testExtendedTestdataTestEnvPodJson, map[string]*bintree{}}, "test-gitserver.yaml": {testExtendedTestdataTestGitserverYaml, map[string]*bintree{}}, + "test-replication-controller.yaml": {testExtendedTestdataTestReplicationControllerYaml, map[string]*bintree{}}, "test-secret.json": {testExtendedTestdataTestSecretJson, map[string]*bintree{}}, "verifyservice-pipeline-template.yaml": {testExtendedTestdataVerifyservicePipelineTemplateYaml, map[string]*bintree{}}, }}, }}, - "integration": {nil, map[string]*bintree{ - "testdata": {nil, map[string]*bintree{ - "project-request-template-with-quota.yaml": {testIntegrationTestdataProjectRequestTemplateWithQuotaYaml, map[string]*bintree{}}, - "test-buildcli-beta2.json": {testIntegrationTestdataTestBuildcliBeta2Json, map[string]*bintree{}}, - "test-buildcli.json": {testIntegrationTestdataTestBuildcliJson, map[string]*bintree{}}, - "test-deployment-config.yaml": {testIntegrationTestdataTestDeploymentConfigYaml, map[string]*bintree{}}, - "test-image-stream-mapping.json": {testIntegrationTestdataTestImageStreamMappingJson, map[string]*bintree{}}, - "test-image-stream.json": {testIntegrationTestdataTestImageStreamJson, map[string]*bintree{}}, - "test-image.json": {testIntegrationTestdataTestImageJson, map[string]*bintree{}}, - "test-replication-controller.yaml": {testIntegrationTestdataTestReplicationControllerYaml, map[string]*bintree{}}, - "test-route.json": {testIntegrationTestdataTestRouteJson, map[string]*bintree{}}, - "test-service-with-finalizer.json": {testIntegrationTestdataTestServiceWithFinalizerJson, map[string]*bintree{}}, - "test-service.json": {testIntegrationTestdataTestServiceJson, map[string]*bintree{}}, - }}, - }}, }}, }} diff --git a/test/extended/testdata/builds/docker-add/docker-add-env/Dockerfile b/test/extended/testdata/builds/docker-add/docker-add-env/Dockerfile index 0d3b57659b18..19e721c53d67 100644 --- a/test/extended/testdata/builds/docker-add/docker-add-env/Dockerfile +++ b/test/extended/testdata/builds/docker-add/docker-add-env/Dockerfile @@ -1,3 +1,3 @@ -FROM registry.redhat.io/rhel7 +FROM centos ENV foo=foo ADD ./${foo} /tmp/foo diff --git a/test/extended/testdata/builds/test-build-revision.json b/test/extended/testdata/builds/test-build-revision.json index e03c9e7238cb..299172caa17c 100644 --- a/test/extended/testdata/builds/test-build-revision.json +++ b/test/extended/testdata/builds/test-build-revision.json @@ -14,7 +14,7 @@ "source": { "type": "Git", "git": { - "uri": "git://github.com/openshift/ruby-hello-world.git" + "uri": "https://github.com/openshift/ruby-hello-world.git" } }, "strategy": { diff --git a/test/extended/testdata/builds/test-build.yaml b/test/extended/testdata/builds/test-build.yaml index 3bbbb07e7b19..3897b9cd03de 100644 --- a/test/extended/testdata/builds/test-build.yaml +++ b/test/extended/testdata/builds/test-build.yaml @@ -35,7 +35,7 @@ items: source: type: Git git: - uri: git://github.com/openshift/ruby-hello-world.git + uri: https://github.com/openshift/ruby-hello-world.git strategy: type: Source sourceStrategy: @@ -64,7 +64,7 @@ items: source: type: Git git: - uri: git://github.com/openshift/ruby-hello-world.git + uri: https://github.com/openshift/ruby-hello-world.git strategy: type: Source sourceStrategy: diff --git a/test/extended/testdata/builds/test-cds-sourcebuild.json b/test/extended/testdata/builds/test-cds-sourcebuild.json index e89e304bb4ec..13ca8d9bdb9e 100644 --- a/test/extended/testdata/builds/test-cds-sourcebuild.json +++ b/test/extended/testdata/builds/test-cds-sourcebuild.json @@ -25,7 +25,7 @@ "triggers": [], "source":{ "type":"Dockerfile", - "dockerfile":"FROM image-registry.openshift-image-registry.svc:5000/openshift/tools:latest \nRUN sleep 10m" + "dockerfile":"FROM image-registry.openshift-image-registry.svc:5000/openshift/tools:latest\nRUN sleep 10m" }, "strategy": { "type": "Source", diff --git a/test/integration/testdata/test-image-stream.json b/test/extended/testdata/builds/test-image-stream.json similarity index 100% rename from test/integration/testdata/test-image-stream.json rename to test/extended/testdata/builds/test-image-stream.json diff --git a/test/extended/testdata/builds/valuefrom/failed-docker-build-value-from-config.yaml b/test/extended/testdata/builds/valuefrom/failed-docker-build-value-from-config.yaml index 9a281db3ff84..f9491653f774 100644 --- a/test/extended/testdata/builds/valuefrom/failed-docker-build-value-from-config.yaml +++ b/test/extended/testdata/builds/valuefrom/failed-docker-build-value-from-config.yaml @@ -10,7 +10,7 @@ spec: runPolicy: Serial source: dockerfile: - 'FROM busybox@sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6' + 'FROM image-registry.openshift-image-registry.svc:5000/openshift/tools:latest' strategy: type: Docker dockerStrategy: diff --git a/test/extended/testdata/builds/webhook/generic/testdata/push-generic-envs.json b/test/extended/testdata/builds/webhook/generic/testdata/push-generic-envs.json index b835d5258a20..2f8e35891381 100644 --- a/test/extended/testdata/builds/webhook/generic/testdata/push-generic-envs.json +++ b/test/extended/testdata/builds/webhook/generic/testdata/push-generic-envs.json @@ -1,7 +1,7 @@ { "type" : "Git", "git" : { - "uri" : "git://mygitserver/myrepo.git", + "uri" : "https://mygitserver/myrepo.git", "ref" : "refs/heads/master", "commit" : "9bdc3a26ff933b32f3e558636b58aea86a69f051", "message" : "Random act of kindness", diff --git a/test/extended/testdata/builds/webhook/generic/testdata/push-generic-envs.yaml b/test/extended/testdata/builds/webhook/generic/testdata/push-generic-envs.yaml index f5086b1d5bf4..4e37300b9ff9 100644 --- a/test/extended/testdata/builds/webhook/generic/testdata/push-generic-envs.yaml +++ b/test/extended/testdata/builds/webhook/generic/testdata/push-generic-envs.yaml @@ -1,7 +1,7 @@ --- type: "Git" git: - uri: "git://mygitserver/myrepo.git" + uri: "https://mygitserver/myrepo.git" ref: "refs/heads/master" commit: "9bdc3a26ff933b32f3e558636b58aea86a69f051" message: "Random act of kindness" diff --git a/test/extended/testdata/builds/webhook/generic/testdata/push-generic.json b/test/extended/testdata/builds/webhook/generic/testdata/push-generic.json index d26dd50c556c..5e173b2ef575 100644 --- a/test/extended/testdata/builds/webhook/generic/testdata/push-generic.json +++ b/test/extended/testdata/builds/webhook/generic/testdata/push-generic.json @@ -1,7 +1,7 @@ { "type" : "Git", "git" : { - "uri" : "git://mygitserver/myrepo.git", + "uri" : "https://mygitserver/myrepo.git", "ref" : "refs/heads/master", "commit" : "9bdc3a26ff933b32f3e558636b58aea86a69f051", "message" : "Random act of kindness", diff --git a/test/extended/testdata/builds/webhook/github/testdata/pushevent-not-master-branch.json b/test/extended/testdata/builds/webhook/github/testdata/pushevent-not-master-branch.json index c4cac83d2b02..9ca55bdb70d6 100644 --- a/test/extended/testdata/builds/webhook/github/testdata/pushevent-not-master-branch.json +++ b/test/extended/testdata/builds/webhook/github/testdata/pushevent-not-master-branch.json @@ -107,7 +107,7 @@ "created_at":1409063699, "updated_at":"2014-08-26T14:34:59Z", "pushed_at":1409238007, - "git_url":"git://github.com/anonUser/anonRepo.git", + "git_url":"https://github.com/anonUser/anonRepo.git", "ssh_url":"git@github.com:anonUser/anonRepo.git", "clone_url":"https://github.com/anonUser/anonRepo.git", "svn_url":"https://github.com/anonUser/anonRepo", diff --git a/test/extended/testdata/builds/webhook/github/testdata/pushevent.json b/test/extended/testdata/builds/webhook/github/testdata/pushevent.json index e087faa276b4..5d5324cfcdee 100644 --- a/test/extended/testdata/builds/webhook/github/testdata/pushevent.json +++ b/test/extended/testdata/builds/webhook/github/testdata/pushevent.json @@ -107,7 +107,7 @@ "created_at":1409063699, "updated_at":"2014-08-26T14:34:59Z", "pushed_at":1409238007, - "git_url":"git://github.com/anonUser/anonRepo.git", + "git_url":"https://github.com/anonUser/anonRepo.git", "ssh_url":"git@github.com:anonUser/anonRepo.git", "clone_url":"https://github.com/anonUser/anonRepo.git", "svn_url":"https://github.com/anonUser/anonRepo", diff --git a/test/extended/testdata/cli/pod-with-two-containers.yaml b/test/extended/testdata/cli/pod-with-two-containers.yaml index 2f87ed72a0da..e176a6625587 100644 --- a/test/extended/testdata/cli/pod-with-two-containers.yaml +++ b/test/extended/testdata/cli/pod-with-two-containers.yaml @@ -7,7 +7,7 @@ metadata: spec: containers: - name: hello-centos - image: docker.io/centos:centos7 + image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest command: - /bin/sleep - infinity @@ -16,10 +16,9 @@ spec: memory: 256Mi terminationMessagePath: "/dev/termination-log" imagePullPolicy: IfNotPresent - capabilities: {} securityContext: {} - name: hello-centos-2 - image: docker.io/centos:centos7 + image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest command: - /bin/sleep - infinity @@ -28,7 +27,6 @@ spec: memory: 256Mi terminationMessagePath: "/dev/termination-log1" imagePullPolicy: IfNotPresent - capabilities: {} securityContext: {} restartPolicy: Always dnsPolicy: ClusterFirst diff --git a/test/extended/testdata/cmd/test/cmd/basicresources.sh b/test/extended/testdata/cmd/test/cmd/basicresources.sh index adef7c860cbc..6a2c1f46bb50 100755 --- a/test/extended/testdata/cmd/test/cmd/basicresources.sh +++ b/test/extended/testdata/cmd/test/cmd/basicresources.sh @@ -108,8 +108,6 @@ os::test::junit::declare_suite_start "cmd/basicresources/services" os::cmd::expect_success 'oc get services' os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-service.json' os::cmd::expect_success 'oc delete services frontend' -# TODO: reenable with a permission check -# os::cmd::expect_failure_and_text 'oc create -f test/integration/testdata/test-service-with-finalizer.json' "finalizers are disabled" echo "services: ok" os::test::junit::declare_suite_end @@ -120,8 +118,8 @@ os::cmd::expect_success 'oc get -f ${TEST_DATA}/mixed-api-versions.yaml -o os::cmd::expect_success 'oc label -f ${TEST_DATA}/mixed-api-versions.yaml mylabel=a' os::cmd::expect_success 'oc annotate -f ${TEST_DATA}/mixed-api-versions.yaml myannotation=b' # Make sure all six resources, with different API versions, got labeled and annotated -os::cmd::expect_success_and_text 'oc get -f ${TEST_DATA}/mixed-api-versions.yaml --output=jsonpath="{..metadata.labels.mylabel}"' '^a a a a$' -os::cmd::expect_success_and_text 'oc get -f ${TEST_DATA}/mixed-api-versions.yaml --output=jsonpath="{..metadata.annotations.myannotation}"' '^b b b b$' +os::cmd::expect_success_and_text 'oc get -f ${TEST_DATA}/mixed-api-versions.yaml --output=jsonpath="{..metadata.labels.mylabel}"' 'a a a a' +os::cmd::expect_success_and_text 'oc get -f ${TEST_DATA}/mixed-api-versions.yaml --output=jsonpath="{..metadata.annotations.myannotation}"' 'b b b b' os::cmd::expect_success 'oc delete -f ${TEST_DATA}/mixed-api-versions.yaml' echo "list version conversion: ok" os::test::junit::declare_suite_end @@ -278,9 +276,9 @@ export KUBECONFIG="${temp_config}" #os::cmd::expect_success 'oc new-project test-project-admin' #os::cmd::try_until_success "oc project test-project-admin" -os::cmd::expect_success 'oc create deploymentconfig --image=openshift/hello-openshift test' -os::cmd::expect_success 'oc run --image=openshift/hello-openshift --restart=Never test3' -os::cmd::expect_success 'oc create job --image=openshift/hello-openshift test4' +os::cmd::expect_success 'oc create deploymentconfig --image=image-registry.openshift-image-registry.svc:5000/openshift/tools:latest test' +os::cmd::expect_success 'oc run --image=image-registry.openshift-image-registry.svc:5000/openshift/tools:latest --restart=Never test3' +os::cmd::expect_success 'oc create job --image=image-registry.openshift-image-registry.svc:5000/openshift/tools:latest test4' os::cmd::expect_success 'oc delete dc/test pod/test3 job/test4' os::cmd::expect_success_and_text 'oc create deploymentconfig --dry-run foo --image=bar -o name' 'deploymentconfig.apps.openshift.io/foo' diff --git a/test/extended/testdata/cmd/test/cmd/builds.sh b/test/extended/testdata/cmd/test/cmd/builds.sh index 702e54bb2921..e82619094c26 100755 --- a/test/extended/testdata/cmd/test/cmd/builds.sh +++ b/test/extended/testdata/cmd/test/cmd/builds.sh @@ -35,7 +35,7 @@ os::cmd::expect_failure_and_text "oc new-build --binary" "you must provide a --n os::cmd::expect_success "oc new-build --binary --name=binary-test" os::cmd::expect_success_and_text "oc get bc/binary-test" 'Binary' -os::cmd::expect_success 'oc delete is/binary-test bc/binary-test bc/tests' +os::cmd::expect_success 'oc delete is/binary-test bc/binary-test is/tests bc/tests' # Build from Dockerfile with output to DockerImage os::cmd::expect_success "oc new-build -D \$'FROM image-registry.openshift-image-registry.svc:5000/openshift/tests:latest' --to-docker" diff --git a/test/extended/testdata/cmd/test/cmd/config.sh b/test/extended/testdata/cmd/test/cmd/config.sh index 089e8bdf8ade..8ad09e674d03 100755 --- a/test/extended/testdata/cmd/test/cmd/config.sh +++ b/test/extended/testdata/cmd/test/cmd/config.sh @@ -34,15 +34,15 @@ os::cmd::expect_success_and_not_text 'oc get bc' 'does not exist' # need some level of default (both upstream and here) to get the pretty auth message because you fail on namespace first. os::cmd::expect_failure_and_text 'KUBERNETES_MASTER=anything env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --user="test"' 'auth info "test" does not exist' - os::cmd::expect_failure_and_text 'oc get bc --config=missing' 'missing: no such file or directory' + os::cmd::expect_failure_and_text 'oc get bc --kubeconfig=missing' 'missing: no such file or directory' # define temp location for new config NEW_CONFIG_LOC="${BASETMPDIR}/new-config.yaml" # make sure non-existing --cluster and --user can still be set - os::cmd::expect_success_and_text "oc config set-context new-context-name --cluster=missing-cluster --user=missing-user --namespace=default --config='${NEW_CONFIG_LOC}'" 'Context "new-context-name" ' - os::cmd::expect_failure_and_text "env -u KUBERNETES_SERVICE_HOST -u KUBECONFIG -u KUBERNETES_MASTER oc get buildconfigs --config='${NEW_CONFIG_LOC}'" 'Missing or incomplete configuration info' - os::cmd::expect_failure_and_text "env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --config='${NEW_CONFIG_LOC}'" 'Missing or incomplete configuration info' + os::cmd::expect_success_and_text "oc config set-context new-context-name --cluster=missing-cluster --user=missing-user --namespace=default --kubeconfig='${NEW_CONFIG_LOC}'" 'Context "new-context-name" ' + os::cmd::expect_failure_and_text "env -u KUBERNETES_SERVICE_HOST -u KUBECONFIG -u KUBERNETES_MASTER oc get buildconfigs --kubeconfig='${NEW_CONFIG_LOC}'" 'Missing or incomplete configuration info' + os::cmd::expect_failure_and_text "env -u KUBERNETES_SERVICE_HOST oc get buildconfigs --kubeconfig='${NEW_CONFIG_LOC}'" 'Missing or incomplete configuration info' ) echo "config error handling: ok" os::test::junit::declare_suite_end diff --git a/test/extended/testdata/cmd/test/cmd/convert.sh b/test/extended/testdata/cmd/test/cmd/convert.sh deleted file mode 100755 index adf92cb08416..000000000000 --- a/test/extended/testdata/cmd/test/cmd/convert.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -set -o errexit -set -o nounset -set -o pipefail - -OS_ROOT=$(dirname "${BASH_SOURCE}")/../.. -source "${OS_ROOT}/hack/lib/init.sh" -os::log::stacktrace::install -trap os::test::junit::reconcile_output EXIT - -# Cleanup cluster resources created by this test -( - set +e - oc delete all --all - exit 0 -) &>/dev/null - -os::test::junit::declare_suite_start "cmd/convert" -# This test validates the convert command - -os::cmd::expect_success "oc convert -f ${TEST_DATA}/convert/job-v1.yaml | grep 'apiVersion: batch/v1'" -os::cmd::expect_success "oc convert -f ${TEST_DATA}/convert/job-v2.json | grep 'apiVersion: batch/v1beta1'" - -os::cmd::expect_success_and_text "oc convert -f ${TEST_DATA}/convert | oc create --dry-run -f -" 'job.batch/pi created' -os::cmd::expect_success_and_text "oc convert -f ${TEST_DATA}/convert | oc create --dry-run -f -" 'cronjob.batch/hello created' - -echo "convert: ok" -os::test::junit::declare_suite_end diff --git a/test/extended/testdata/cmd/test/cmd/debug.sh b/test/extended/testdata/cmd/test/cmd/debug.sh deleted file mode 100755 index fc5a4157aef2..000000000000 --- a/test/extended/testdata/cmd/test/cmd/debug.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT - -# Cleanup cluster resources created by this test -( - set +e - oc delete all,templates --all - exit 0 -) &>/dev/null - -os::test::junit::declare_suite_start "cmd/debug" -# This test validates the debug command -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-deployment-config.yaml' -os::cmd::expect_success_and_text "oc debug dc/test-deployment-config -o yaml" '\- /bin/sh' -os::cmd::expect_success_and_text "oc debug dc/test-deployment-config --keep-annotations -o yaml" 'annotations:' -os::cmd::expect_success_and_text "oc debug dc/test-deployment-config --as-root -o yaml" 'runAsUser: 0' -os::cmd::expect_success_and_text "oc debug dc/test-deployment-config --as-root=false -o yaml" 'runAsNonRoot: true' -os::cmd::expect_success_and_text "oc debug dc/test-deployment-config --as-user=1 -o yaml" 'runAsUser: 1' -os::cmd::expect_success_and_text "oc debug dc/test-deployment-config --keep-liveness --keep-readiness -o yaml" '' -os::cmd::expect_success_and_text "oc debug dc/test-deployment-config -o yaml -- /bin/env" '\- /bin/env' -os::cmd::expect_success_and_text "oc debug -t dc/test-deployment-config -o yaml" 'stdinOnce' -os::cmd::expect_success_and_text "oc debug -t dc/test-deployment-config -o yaml" 'tty' -os::cmd::expect_success_and_text "oc debug --v=8 -t dc/test-deployment-config -o yaml" "Response Headers" -os::cmd::expect_success_and_not_text "oc debug --tty=false dc/test-deployment-config -o yaml" 'tty' -os::cmd::expect_success_and_not_text "oc debug dc/test-deployment-config -o yaml -- /bin/env" 'stdin' -os::cmd::expect_success_and_not_text "oc debug dc/test-deployment-config -o yaml -- /bin/env" 'tty' -os::cmd::expect_failure_and_text "oc debug dc/test-deployment-config --node-name=invalid -- /bin/env" 'on node "invalid"' -# Does not require a real resource on the server -os::cmd::expect_success_and_not_text "oc debug -T -f ${TEST_DATA}/hello-openshift/hello-pod.json -o yaml" 'tty' -os::cmd::expect_success_and_text "oc debug -f ${TEST_DATA}/hello-openshift/hello-pod.json --keep-liveness --keep-readiness -o yaml" '' -os::cmd::expect_success_and_text "oc debug -f ${TEST_DATA}/hello-openshift/hello-pod.json -o yaml -- /bin/env" '\- /bin/env' -os::cmd::expect_success_and_not_text "oc debug -f ${TEST_DATA}/hello-openshift/hello-pod.json -o yaml -- /bin/env" 'stdin' -os::cmd::expect_success_and_not_text "oc debug -f ${TEST_DATA}/hello-openshift/hello-pod.json -o yaml -- /bin/env" 'tty' -# TODO: write a test that emulates a TTY to verify the correct defaulting of what the pod is created - -# Ensure debug does not depend on a container actually existing for the selected resource. -# The command should not hang waiting for an attachable pod. Timeout each cmd after 10s. -os::cmd::expect_success 'oc create -f ${TEST_DATA}/test-replication-controller.yaml' -os::cmd::expect_success 'oc scale --replicas=0 rc/test-replication-controller' -os::cmd::expect_success_and_text "oc debug --request-timeout=10s -c ruby-helloworld --one-container rc/test-replication-controller -o jsonpath='{.metadata.name}'" 'test-replication-controller-debug' - -os::cmd::expect_success 'oc scale --replicas=0 dc/test-deployment-config' -os::cmd::expect_success_and_text "oc debug --request-timeout=10s -c ruby-helloworld --one-container dc/test-deployment-config -o jsonpath='{.metadata.name}'" 'test-deployment-config' - -tmp_deploy="$(mktemp)" -os::cmd::expect_success 'oc create -f - >> $tmp_deploy << __EOF__ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: test-deployment - labels: - deployment: test-deployment -spec: - replicas: 0 - selector: - matchLabels: - deployment: test-deployment - template: - metadata: - labels: - deployment: test-deployment - name: test-deployment - spec: - containers: - - name: ruby-helloworld - image: openshift/origin-pod - imagePullPolicy: IfNotPresent - resources: {} -status: {} -__EOF__' -os::cmd::expect_success_and_text "oc debug --request-timeout=10s -c ruby-helloworld --one-container deploy/test-deployment -o jsonpath='{.metadata.name}'" 'test-deployment-debug' - -# re-scale existing resources -os::cmd::expect_success 'oc scale --replicas=1 dc/test-deployment-config' - -os::cmd::expect_success 'oc create -f ${TEST_DATA}/image-streams/image-streams-centos7.json' -os::cmd::try_until_success 'oc get imagestreamtags wildfly:latest' -os::cmd::expect_success_and_text "oc debug istag/wildfly:latest -o yaml" 'image:.*cmd-debug/wildfly.*@' -sha="$( oc get istag/wildfly:latest --template '{{ .image.metadata.name }}' )" -os::cmd::expect_success_and_text "oc debug isimage/wildfly@${sha} -o yaml" 'image: docker.io/openshift/wildfly-150-centos7' - -echo "debug: ok" -os::test::junit::declare_suite_end diff --git a/test/extended/testdata/cmd/test/cmd/deployments.sh b/test/extended/testdata/cmd/test/cmd/deployments.sh index 0ae3c0aace45..c1f77be513eb 100755 --- a/test/extended/testdata/cmd/test/cmd/deployments.sh +++ b/test/extended/testdata/cmd/test/cmd/deployments.sh @@ -20,9 +20,9 @@ os::cmd::expect_success 'oc describe deploymentConfigs test-deployment-config' os::cmd::expect_success_and_text 'oc get dc -o name' 'deploymentconfig.apps.openshift.io/test-deployment-config' os::cmd::try_until_success 'oc get rc/test-deployment-config-1' os::cmd::expect_success_and_text 'oc describe dc test-deployment-config' 'deploymentconfig=test-deployment-config' -os::cmd::expect_success_and_text 'oc status' 'dc/test-deployment-config deploys docker.io/openshift/origin-pod:latest' +os::cmd::expect_success_and_text 'oc status' 'dc/test-deployment-config deploys image-registry.openshift-image-registry.svc:5000/openshift/tools:latest' os::cmd::expect_success 'oc create -f ${TEST_DATA}/hello-openshift/hello-pod.json' -os::cmd::try_until_text 'oc status' 'pod/hello-openshift runs openshift/hello-openshift' +os::cmd::try_until_text 'oc status' 'pod/hello-openshift runs' os::test::junit::declare_suite_start "cmd/deployments/env" # Patch a nil list @@ -122,7 +122,7 @@ os::cmd::try_until_success 'oc rollout history dc/database --revision=2' # rolling back to the same revision should fail os::cmd::expect_failure 'oc rollback dc/database --to-version=2' # undo --dry-run should report the original image -os::cmd::expect_success_and_text 'oc rollout undo dc/database --dry-run' 'mysql-57-centos7' +os::cmd::expect_success_and_text 'oc rollout undo dc/database --dry-run' 'image-registry.openshift-image-registry.svc:5000/openshift/mysql:5.7' echo "rollback: ok" os::test::junit::declare_suite_end diff --git a/test/extended/testdata/cmd/test/cmd/edit.sh b/test/extended/testdata/cmd/test/cmd/edit.sh old mode 100755 new mode 100644 index d9fef503aaa6..6972d19dec12 --- a/test/extended/testdata/cmd/test/cmd/edit.sh +++ b/test/extended/testdata/cmd/test/cmd/edit.sh @@ -15,16 +15,16 @@ os::test::junit::declare_suite_start "cmd/edit" os::cmd::expect_success 'oc create -f ${TEST_DATA}/hello-openshift/hello-pod.json' -os::cmd::expect_success_and_text 'OC_EDITOR=cat oc edit pod/hello-openshift' 'Edit cancelled' -os::cmd::expect_success_and_text 'OC_EDITOR=cat oc edit pod/hello-openshift' 'name: hello-openshift' -#os::cmd::expect_success_and_text 'OC_EDITOR=cat oc edit --windows-line-endings pod/hello-openshift | file -' 'CRLF' -#os::cmd::expect_success_and_not_text 'OC_EDITOR=cat oc edit --windows-line-endings=false pod/hello-openshift | file -' 'CRFL' +os::cmd::expect_success_and_text 'KUBE_EDITOR=cat oc edit pod/hello-openshift' 'Edit cancelled' +os::cmd::expect_success_and_text 'KUBE_EDITOR=cat oc edit pod/hello-openshift' 'name: hello-openshift' +#os::cmd::expect_success_and_text 'KUBE_EDITOR=cat oc edit --windows-line-endings pod/hello-openshift | file -' 'CRLF' +#os::cmd::expect_success_and_not_text 'KUBE_EDITOR=cat oc edit --windows-line-endings=false pod/hello-openshift | file -' 'CRFL' os::cmd::expect_success 'oc create -f ${TEST_DATA}/services.yaml' -os::cmd::expect_success_and_text 'OC_EDITOR=cat oc edit svc' 'kind: List' +os::cmd::expect_success_and_text 'KUBE_EDITOR=cat oc edit svc' 'kind: List' os::cmd::expect_success 'oc create imagestream test' -os::cmd::expect_success 'oc tag --source=docker docker.io/busybox:latest test:new' +os::cmd::expect_success 'oc tag --source=docker quay.io/openshifttest/hello-openshift:openshift test:new' os::cmd::try_until_success 'oc get istag/test:new' os::cmd::expect_success_and_not_text 'oc get istag/test:new -o jsonpath={.metadata.annotations}' "tags.?:.?hidden" editorfile="$(mktemp -d)/tmp-editor.sh" diff --git a/test/extended/testdata/cmd/test/cmd/env.sh b/test/extended/testdata/cmd/test/cmd/env.sh index 19a785071beb..de0e5629eb58 100755 --- a/test/extended/testdata/cmd/test/cmd/env.sh +++ b/test/extended/testdata/cmd/test/cmd/env.sh @@ -40,7 +40,7 @@ metadata: spec: source: git: - uri: git://github.com/openshift/ruby-hello-world.git + uri: https://github.com/openshift/ruby-hello-world.git strategy: jenkinsPipelineStrategy: {} ' | oc create -f -" diff --git a/test/extended/testdata/cmd/test/cmd/images.sh b/test/extended/testdata/cmd/test/cmd/images.sh index d38277400123..6c7fbc09d104 100755 --- a/test/extended/testdata/cmd/test/cmd/images.sh +++ b/test/extended/testdata/cmd/test/cmd/images.sh @@ -75,42 +75,43 @@ os::cmd::expect_success_and_text 'oc get istag' 'wildfly' # test image stream tag operations os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.generation}' '2' os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.from.kind}' 'ImageStreamTag' -os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.from.name}' '15.0' +os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.from.name}' '21.0' os::cmd::expect_success 'oc annotate istag/wildfly:latest foo=bar' os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.metadata.annotations.foo}' 'bar' os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.annotations.foo}' 'bar' os::cmd::expect_success 'oc annotate istag/wildfly:latest foo-' os::cmd::expect_success_and_not_text 'oc get istag/wildfly:latest -o jsonpath={.metadata.annotations}' 'bar' os::cmd::expect_success_and_not_text 'oc get istag/wildfly:latest -o jsonpath={.tag.annotations}' 'bar' -os::cmd::expect_success "oc patch istag/wildfly:latest -p='{\"tag\":{\"from\":{\"kind\":\"DockerImage\",\"name\":\"mysql:latest\"}}}'" +os::cmd::expect_success "oc patch istag/wildfly:latest -p='{\"tag\":{\"from\":{\"kind\":\"DockerImage\",\"name\":\"quay.io/wildfly/wildfly-centos7:19.0\"}}}'" os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.from.kind}' 'DockerImage' -os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.from.name}' 'mysql:latest' +os::cmd::expect_success_and_text 'oc get istag/wildfly:latest -o jsonpath={.tag.from.name}' 'quay.io/wildfly/wildfly-centos7:19.0' os::cmd::expect_success_and_not_text 'oc get istag/wildfly:latest -o jsonpath={.tag.generation}' '2' # create an image stream tag -os::cmd::expect_success 'oc create imagestreamtag tag:1 --from=wildfly:15.0' -os::cmd::expect_success 'oc create imagestreamtag tag:2 --from-image=mysql:latest' +os::cmd::expect_success 'oc create imagestreamtag tag:1 --from=wildfly:21.0' +os::cmd::expect_success 'oc create imagestreamtag tag:2 --from-image=quay.io/openshifttest/hello-openshift:openshift' os::cmd::try_until_success 'oc get imagestreamtags tag:2' os::cmd::expect_success 'oc create imagestreamtag tag:3 -A foo=bar' os::cmd::expect_success 'oc create imagestreamtag tag:4 --from=:2' os::cmd::expect_success 'oc create imagestreamtag tag:5 --from=tag:2' -os::cmd::expect_success 'oc create imagestreamtag tag:6 --reference --from-image=mysql:latest' +os::cmd::expect_success 'oc create imagestreamtag tag:6 --reference --from-image=quay.io/openshifttest/hello-openshift:openshift' os::cmd::expect_success 'oc create imagestreamtag tag:7 --reference-policy=Local --from=tag:2' -os::cmd::expect_success 'oc create istag tag:8 --insecure --from-image=mysql:latest' +os::cmd::expect_success 'oc create istag tag:8 --insecure --from-image=quay.io/openshifttest/hello-openshift:openshift' os::cmd::try_until_success 'oc get imagestreamtags tag:8' -os::cmd::expect_success 'oc create imagestreamtag tag:9 --scheduled --reference-policy=Local --from-image=mysql:latest' +os::cmd::expect_success 'oc create imagestreamtag tag:9 --scheduled --reference-policy=Local --from-image=quay.io/openshifttest/hello-openshift:openshift' os::cmd::expect_success 'oc create imagestream tag-b' -os::cmd::expect_success 'oc create imagestreamtag tag-b:1 --from=wildfly:15.0' +os::cmd::expect_success 'oc create imagestreamtag tag-b:1 --from-image=quay.io/wildfly/wildfly-centos7:20.0' os::cmd::expect_success 'oc create imagestreamtag tag-c:1 -A annotation.with.dots=are.ok' -os::cmd::expect_failure_and_text 'oc create imagestreamtag tag-c --from-image=mysql:latest' 'must be of the form :' +os::cmd::expect_failure_and_text 'oc create imagestreamtag tag-b:1 --from=quay.io/wildfly/wildfly-centos7:20.0' 'registry may not be specified' +os::cmd::expect_failure_and_text 'oc create imagestreamtag tag-c --from-image=quay.io/openshifttest/hello-openshift:openshift' 'must be of the form :' os::cmd::expect_failure_and_text 'oc create imagestreamtag tag-c:1 -A foo' 'annotations must be of the form key=value, but is "foo"' -os::cmd::expect_failure_and_text 'oc create imagestreamtag tag-c:2 --from=mysql --from-image=mysql:latest' '\--from and --from-image may not be used together' +os::cmd::expect_failure_and_text 'oc create imagestreamtag tag-c:2 --from=mysql --from-image=quay.io/openshifttest/hello-openshift:openshift' '\--from and --from-image may not be used together' -os::cmd::expect_success_and_text 'oc get istag/tag:1 -o jsonpath={.image.dockerImageReference}' 'wildfly.*@sha256:' -tag1=$( oc get istag/wildfly:15.0 -o jsonpath={.image.metadata.name} ) +os::cmd::expect_success_and_text 'oc get istag/tag:1 -o jsonpath={.image.dockerImageReference}' 'wildfly-centos7.*@sha256:' +tag1=$( oc get istag/wildfly:20.0 -o jsonpath={.image.metadata.name} ) os::cmd::expect_success_and_text 'oc get istag/tag-b:1 -o jsonpath={.image.metadata.name}' "${tag1}" -os::cmd::expect_success_and_text 'oc get istag/tag:2 -o jsonpath={.image.dockerImageReference}' 'mysql@sha256:' +os::cmd::expect_success_and_text 'oc get istag/tag:2 -o jsonpath={.image.dockerImageReference}' 'hello-openshift@sha256:' tag2=$( oc get istag/tag:2 -o jsonpath={.image.metadata.name} ) os::cmd::expect_success_and_text "oc get is/tag -o 'jsonpath={.spec.tags[?(@.name==\"3\")].annotations.foo}'" 'bar' os::cmd::expect_success_and_text 'oc get istag/tag:4 -o jsonpath={.image.metadata.name}' "${tag2}" @@ -131,7 +132,6 @@ os::cmd::expect_failure 'oc get imageStreams nodejs' os::cmd::expect_failure 'oc get imageStreams postgresql' os::cmd::expect_failure 'oc get imageStreams mongodb' os::cmd::expect_failure 'oc get imageStreams wildfly' -os::cmd::try_until_success 'oc get imagestreamTags mysql:5.5' os::cmd::try_until_success 'oc get imagestreamTags mysql:5.6' os::cmd::try_until_success 'oc get imagestreamTags mysql:5.7' os::cmd::expect_success_and_text "oc get imagestreams mysql --template='{{ index .metadata.annotations \"openshift.io/image.dockerRepositoryCheck\"}}'" '[0-9]{4}\-[0-9]{2}\-[0-9]{2}' # expect a date like YYYY-MM-DD @@ -160,66 +160,64 @@ os::test::junit::declare_suite_end os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/import-image" # should follow the latest reference to 5.6 and update that, and leave latest unchanged os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 1).from.kind}}'" 'DockerImage' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 2).from.kind}}'" 'DockerImage' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 3).from.kind}}'" 'ImageStreamTag' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 3).from.name}}'" '5.7' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 2).from.kind}}'" 'ImageStreamTag' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 2).from.name}}'" '5.7' # import existing tag (implicit latest) os::cmd::expect_success_and_text 'oc import-image mysql' 'sha256:' os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 1).from.kind}}'" 'DockerImage' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 2).from.kind}}'" 'DockerImage' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 3).from.kind}}'" 'ImageStreamTag' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 3).from.name}}'" '5.7' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 2).from.kind}}'" 'ImageStreamTag' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 2).from.name}}'" '5.7' # should prevent changing source -os::cmd::expect_failure_and_text 'oc import-image mysql --from=docker.io/mysql' "use the 'tag' command if you want to change the source" +os::cmd::expect_failure_and_text 'oc import-image mysql --from=quay.io/openshifttest/hello-openshift:openshift' "use the 'tag' command if you want to change the source" os::cmd::expect_success 'oc describe is/mysql' # import existing tag (explicit) os::cmd::expect_success_and_text 'oc import-image mysql:5.6' "sha256:" os::cmd::expect_success_and_text 'oc import-image mysql:latest' "sha256:" # import existing image stream creating new tag -os::cmd::expect_success_and_text 'oc import-image mysql:external --from=docker.io/mysql' "sha256:" +os::cmd::expect_success_and_text 'oc import-image mysql:external --from=quay.io/openshifttest/hello-openshift:openshift' "sha256:" os::cmd::expect_success_and_text "oc get istag/mysql:external --template='{{.tag.from.kind}}'" 'DockerImage' -os::cmd::expect_success_and_text "oc get istag/mysql:external --template='{{.tag.from.name}}'" 'docker.io/mysql' +os::cmd::expect_success_and_text "oc get istag/mysql:external --template='{{.tag.from.name}}'" 'quay.io/openshifttest/hello-openshift:openshift' # import creates new image stream with single tag -os::cmd::expect_failure_and_text 'oc import-image mysql-new-single:latest --from=docker.io/mysql:latest' '\-\-confirm' -os::cmd::expect_success_and_text 'oc import-image mysql-new-single:latest --from=docker.io/mysql:latest --confirm' 'sha256:' +os::cmd::expect_failure_and_text 'oc import-image mysql-new-single:latest --from=quay.io/openshifttest/hello-openshift:openshift' '\-\-confirm' +os::cmd::expect_success_and_text 'oc import-image mysql-new-single:latest --from=quay.io/openshifttest/hello-openshift:openshift --confirm' 'sha256:' os::cmd::expect_success_and_text "oc get is/mysql-new-single --template='{{(len .spec.tags)}}'" '1' os::cmd::expect_success 'oc delete is/mysql-new-single' # import creates new image stream with all tags -os::cmd::expect_failure_and_text 'oc import-image mysql-new-all --from=mysql --all' '\-\-confirm' -os::cmd::expect_success_and_text 'oc import-image mysql-new-all --from=mysql --all --confirm --request-timeout=1m' 'sha256:' -name=$(oc get istag/mysql-new-all:latest --template='{{ .image.metadata.name }}') +os::cmd::expect_failure_and_text 'oc import-image mysql-new-all --from=quay.io/openshifttest/hello-openshift --all' '\-\-confirm' +os::cmd::expect_success_and_text 'oc import-image mysql-new-all --from=quay.io/openshifttest/hello-openshift --all --confirm --request-timeout=1m' 'sha256:' +name=$(oc get istag/mysql-new-all:openshift --template='{{ .image.metadata.name }}') echo "import-image: ok" os::test::junit::declare_suite_end os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/tag" # oc tag os::cmd::expect_success 'oc tag mysql:latest mysql:tag1 --alias' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 5).from.kind}}'" 'ImageStreamTag' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 4).from.kind}}'" 'ImageStreamTag' os::cmd::expect_success "oc tag mysql@${name} mysql:tag2 --alias" -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 6).from.kind}}'" 'ImageStreamImage' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 5).from.kind}}'" 'ImageStreamImage' os::cmd::expect_success 'oc tag mysql:notfound mysql:tag3 --alias' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 7).from.kind}}'" 'ImageStreamTag' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 6).from.kind}}'" 'ImageStreamTag' os::cmd::expect_success 'oc tag --source=imagestreamtag mysql:latest mysql:tag4 --alias' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 8).from.kind}}'" 'ImageStreamTag' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 7).from.kind}}'" 'ImageStreamTag' os::cmd::expect_success 'oc tag --source=istag mysql:latest mysql:tag5 --alias' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 9).from.kind}}'" 'ImageStreamTag' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 8).from.kind}}'" 'ImageStreamTag' os::cmd::expect_success "oc tag --source=imagestreamimage mysql@${name} mysql:tag6 --alias" -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 10).from.kind}}'" 'ImageStreamImage' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 9).from.kind}}'" 'ImageStreamImage' os::cmd::expect_success "oc tag --source=isimage mysql@${name} mysql:tag7 --alias" -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 11).from.kind}}'" 'ImageStreamImage' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 10).from.kind}}'" 'ImageStreamImage' os::cmd::expect_success 'oc tag --source=docker mysql:latest mysql:tag8 --alias' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 12).from.kind}}'" 'DockerImage' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 11).from.kind}}'" 'DockerImage' os::cmd::expect_success 'oc tag mysql:latest mysql:zzz mysql:yyy --alias' +os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 12).from.kind}}'" 'ImageStreamTag' os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 13).from.kind}}'" 'ImageStreamTag' -os::cmd::expect_success_and_text "oc get is/mysql --template='{{(index .spec.tags 14).from.kind}}'" 'ImageStreamTag' os::cmd::expect_failure_and_text 'oc tag mysql:latest tagtest:tag1 --alias' 'cannot set alias across' @@ -233,25 +231,25 @@ os::cmd::expect_success 'oc label is/mysql labelA=value' os::cmd::expect_success 'oc tag mysql:latest mysql:labeled' os::cmd::expect_success_and_text "oc get istag/mysql:labeled -o jsonpath='{.metadata.labels.labelA}'" 'value' # test copying tags -os::cmd::expect_success 'oc tag registry-1.docker.io/openshift/origin:v1.0.4 newrepo:latest' +os::cmd::expect_success 'oc tag quay.io/openshift/origin-cli:4.6 newrepo:latest' os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .spec.tags 0).from.kind}}'" 'DockerImage' -os::cmd::try_until_success 'oc get istag/mysql:5.5' +os::cmd::try_until_success 'oc get istag/mysql:5.6' # default behavior is to copy the current image, but since this is an external image we preserve the dockerImageReference -os::cmd::expect_success 'oc tag mysql:5.5 newrepo:latest' +os::cmd::expect_success 'oc tag mysql:5.6 newrepo:latest' os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .spec.tags 0).from.kind}}'" 'ImageStreamImage' -os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .status.tags 0 \"items\" 0).dockerImageReference}}'" '^docker.io/openshift/mysql-55-centos7@sha256:' +os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .status.tags 0 \"items\" 0).dockerImageReference}}'" '^registry.centos.org/centos/mysql-56-centos7@sha256:' # when copying a tag that points to the internal registry, update the container image reference #os::cmd::expect_success "oc tag test:new newrepo:direct" #os::cmd::expect_success_and_text 'oc get istag/newrepo:direct -o jsonpath={.image.dockerImageReference}' "/$project/newrepo@sha256:" # test references -os::cmd::expect_success 'oc tag mysql:5.5 reference:latest --reference' +os::cmd::expect_success 'oc tag mysql:5.6 reference:latest --reference' os::cmd::expect_success_and_text "oc get is/reference --template='{{(index .spec.tags 0).from.kind}}'" 'ImageStreamImage' os::cmd::expect_success_and_text "oc get is/reference --template='{{(index .spec.tags 0).reference}}'" 'true' # create a second project to test tagging across projects os::cmd::expect_success 'oc new-project test-cmd-images-2' -os::cmd::expect_success "oc tag $project/mysql:5.5 newrepo:latest" +os::cmd::expect_success "oc tag $project/mysql:5.6 newrepo:latest" os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .spec.tags 0).from.kind}}'" 'ImageStreamImage' -os::cmd::expect_success_and_text 'oc get istag/newrepo:latest -o jsonpath={.image.dockerImageReference}' 'docker.io/openshift/mysql-55-centos7@sha256:' +os::cmd::expect_success_and_text 'oc get istag/newrepo:latest -o jsonpath={.image.dockerImageReference}' 'registry.centos.org/centos/mysql-56-centos7@sha256:' # tag across projects without specifying the source's project os::cmd::expect_success_and_text "oc tag newrepo:latest '${project}/mysql:tag1'" "mysql:tag1 set to" os::cmd::expect_success_and_text "oc get is/newrepo --template='{{(index .spec.tags 0).name}}'" "latest" @@ -293,12 +291,12 @@ os::test::junit::declare_suite_end os::test::junit::declare_suite_start "cmd/images${IMAGES_TESTS_POSTFIX:-}/delete-istag" # test deleting a tag using oc delete -os::cmd::expect_success_and_text "oc get is perl --template '{{(index .spec.tags 0).name}}'" '5.16' -os::cmd::expect_success_and_text "oc get is perl --template '{{(index .status.tags 0).tag}}'" '5.16' +os::cmd::expect_success_and_text "oc get is perl --template '{{(index .spec.tags 0).name}}'" '5.24' +os::cmd::expect_success_and_text "oc get is perl --template '{{(index .status.tags 0).tag}}'" '5.24' os::cmd::expect_success_and_text "oc describe is perl | sed -n -e '0,/^Tags:/d' -e '/^\s\+/d' -e '/./p' | head -n 1" 'latest' -os::cmd::expect_success "oc delete istag/perl:5.16 --context='${cluster_admin_context}'" -os::cmd::expect_success_and_not_text 'oc get is/perl --template={{.spec.tags}}' 'version:5.16' -os::cmd::expect_success_and_not_text 'oc get is/perl --template={{.status.tags}}' 'version:5.16' +os::cmd::expect_success "oc delete istag/perl:5.24 --context='${cluster_admin_context}'" +os::cmd::expect_success_and_not_text 'oc get is/perl --template={{.spec.tags}}' 'version:5.24' +os::cmd::expect_success_and_not_text 'oc get is/perl --template={{.status.tags}}' 'version:5.24' os::cmd::expect_success 'oc delete all --all' echo "delete istag: ok" diff --git a/test/extended/testdata/cmd/test/cmd/login.sh b/test/extended/testdata/cmd/test/cmd/login.sh index 3da428536795..b6905f9d613b 100755 --- a/test/extended/testdata/cmd/test/cmd/login.sh +++ b/test/extended/testdata/cmd/test/cmd/login.sh @@ -107,7 +107,6 @@ os::cmd::expect_success 'oc get projects' os::cmd::expect_success 'oc project project-foo' os::cmd::expect_success_and_text 'oc config view' "current-context.+project-foo/${API_HOST}:${API_PORT}/test-user" os::cmd::expect_success_and_text 'oc whoami' 'test-user' -os::cmd::expect_success_and_text "oc whoami --config='${login_kubeconfig}'" 'system:admin' os::cmd::expect_success_and_text "oc whoami --kubeconfig='${login_kubeconfig}'" 'system:admin' os::cmd::expect_success_and_text 'oc whoami -t' '.' os::cmd::expect_success_and_text 'oc whoami -c' '.' diff --git a/test/extended/testdata/cmd/test/cmd/newapp.sh b/test/extended/testdata/cmd/test/cmd/newapp.sh index 5a7c2a7d0da4..e69267ee25ee 100755 --- a/test/extended/testdata/cmd/test/cmd/newapp.sh +++ b/test/extended/testdata/cmd/test/cmd/newapp.sh @@ -38,7 +38,7 @@ os::cmd::try_until_success 'oc get istag php:latest -n test-imagestreams' os::cmd::expect_success 'oc create istag php:latest --from=openshift/php:7.1 -n openshift' # create a new tag for an existing imagestream in the current namespace -os::cmd::expect_success 'oc create istag perl:5.20 --from=openshift/perl:5.20' +os::cmd::expect_success 'oc create istag perl:5.24 --from=openshift/perl:5.24' os::cmd::expect_success 'oc new-app --docker-image=library/perl https://github.com/sclorg/dancer-ex --strategy=source' os::cmd::try_until_success 'oc get istag perl:latest -n test-imagestreams' @@ -74,9 +74,8 @@ os::cmd::expect_success 'oc new-app https://github.com/sclorg/rails-ex --strateg # verify we can generate a container image based component "mongodb" directly os::cmd::expect_success_and_text 'oc new-app mongo -o yaml' 'image:\s*mongo' # the local image repository takes precedence over the Docker Hub "mysql" image -os::cmd::expect_success 'oc create -f examples/image-streams/image-streams-centos7.json' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/image-streams/image-streams-centos7.json' os::cmd::try_until_success 'oc get imagestreamtags mysql:latest' $((2*TIME_MIN)) -os::cmd::try_until_success 'oc get imagestreamtags mysql:5.5' $((2*TIME_MIN)) os::cmd::try_until_success 'oc get imagestreamtags mysql:5.6' $((2*TIME_MIN)) os::cmd::try_until_success 'oc get imagestreamtags mysql:5.7' $((2*TIME_MIN)) os::cmd::expect_success_and_not_text 'oc new-app mysql -o yaml' 'image:\s*mysql' @@ -321,7 +320,7 @@ os::cmd::expect_success_and_text 'oc new-app --search ruby-hellow' 'ruby-hellowo os::cmd::expect_success_and_text 'oc new-app --search --template=ruby-hel' 'ruby-helloworld-sample' os::cmd::expect_success_and_text 'oc new-app --search --template=ruby-helloworld-sam -o yaml' 'ruby-helloworld-sample' os::cmd::expect_success_and_text 'oc new-app --search rub' "Tags:\s+2.3, 2.4, 2.5, latest" -os::cmd::expect_success_and_text 'oc new-app --search --image-stream=rub' "Tags:\s+2.3, 2.4, 2.5, latest" +os::cmd::expect_success_and_text 'oc new-app --search --image-stream=rub' "Tags:\s+2.5, latest" # check search - check correct usage of filters os::cmd::expect_failure_and_not_text 'oc new-app --search --image-stream=ruby-heloworld-sample' 'application-template-stibuild' os::cmd::expect_failure 'oc new-app --search --template=php' @@ -333,58 +332,41 @@ os::cmd::try_until_success 'oc get imagestreamtags mariadb:latest' os::cmd::try_until_success 'oc get imagestreamtags mariadb:10.1' os::cmd::try_until_success 'oc get imagestreamtags mariadb:10.2' os::cmd::try_until_success 'oc get imagestreamtags mongodb:latest' -os::cmd::try_until_success 'oc get imagestreamtags mongodb:2.4' os::cmd::try_until_success 'oc get imagestreamtags mongodb:2.6' os::cmd::try_until_success 'oc get imagestreamtags mongodb:3.2' os::cmd::try_until_success 'oc get imagestreamtags mongodb:3.4' os::cmd::try_until_success 'oc get imagestreamtags mysql:latest' -os::cmd::try_until_success 'oc get imagestreamtags mysql:5.5' os::cmd::try_until_success 'oc get imagestreamtags mysql:5.6' os::cmd::try_until_success 'oc get imagestreamtags mysql:5.7' os::cmd::try_until_success 'oc get imagestreamtags nginx:latest' -os::cmd::try_until_success 'oc get imagestreamtags nginx:1.8' -os::cmd::try_until_success 'oc get imagestreamtags nginx:1.10' -os::cmd::try_until_success 'oc get imagestreamtags nginx:1.12' +os::cmd::try_until_success 'oc get imagestreamtags nginx:1.14' +os::cmd::try_until_success 'oc get imagestreamtags nginx:1.16' os::cmd::try_until_success 'oc get imagestreamtags nodejs:latest' -os::cmd::try_until_success 'oc get imagestreamtags nodejs:0.10' -os::cmd::try_until_success 'oc get imagestreamtags nodejs:4' -os::cmd::try_until_success 'oc get imagestreamtags nodejs:6' -os::cmd::try_until_success 'oc get imagestreamtags nodejs:8' +os::cmd::try_until_success 'oc get imagestreamtags nodejs:10' +os::cmd::try_until_success 'oc get imagestreamtags nodejs:12' os::cmd::try_until_success 'oc get imagestreamtags perl:latest' -os::cmd::try_until_success 'oc get imagestreamtags perl:5.16' -os::cmd::try_until_success 'oc get imagestreamtags perl:5.20' os::cmd::try_until_success 'oc get imagestreamtags perl:5.24' +os::cmd::try_until_success 'oc get imagestreamtags perl:5.26' os::cmd::try_until_success 'oc get imagestreamtags php:latest' -os::cmd::try_until_success 'oc get imagestreamtags php:5.5' -os::cmd::try_until_success 'oc get imagestreamtags php:5.6' os::cmd::try_until_success 'oc get imagestreamtags php:7.0' os::cmd::try_until_success 'oc get imagestreamtags php:7.1' os::cmd::try_until_success 'oc get imagestreamtags postgresql:latest' -os::cmd::try_until_success 'oc get imagestreamtags postgresql:9.2' -os::cmd::try_until_success 'oc get imagestreamtags postgresql:9.4' os::cmd::try_until_success 'oc get imagestreamtags postgresql:9.5' os::cmd::try_until_success 'oc get imagestreamtags postgresql:9.6' os::cmd::try_until_success 'oc get imagestreamtags python:latest' os::cmd::try_until_success 'oc get imagestreamtags python:2.7' -os::cmd::try_until_success 'oc get imagestreamtags python:3.3' -os::cmd::try_until_success 'oc get imagestreamtags python:3.4' -os::cmd::try_until_success 'oc get imagestreamtags python:3.5' os::cmd::try_until_success 'oc get imagestreamtags python:3.6' os::cmd::try_until_success 'oc get imagestreamtags ruby:latest' os::cmd::try_until_success 'oc get imagestreamtags ruby:2.7' os::cmd::try_until_success 'oc get imagestreamtags wildfly:latest' -os::cmd::try_until_success 'oc get imagestreamtags wildfly:12.0' -os::cmd::try_until_success 'oc get imagestreamtags wildfly:11.0' -os::cmd::try_until_success 'oc get imagestreamtags wildfly:10.1' -os::cmd::try_until_success 'oc get imagestreamtags wildfly:10.0' -os::cmd::try_until_success 'oc get imagestreamtags wildfly:9.0' -os::cmd::try_until_success 'oc get imagestreamtags wildfly:8.1' +os::cmd::try_until_success 'oc get imagestreamtags wildfly:20.0' +os::cmd::try_until_success 'oc get imagestreamtags wildfly:21.0' os::cmd::expect_success_and_text 'oc new-app --search --image-stream=mariadb' "Tags:\s+10.1, 10.2, latest" -os::cmd::expect_success_and_text 'oc new-app --search --image-stream=mongodb' "Tags:\s+3.2, 3.4, 3.6, latest" +os::cmd::expect_success_and_text 'oc new-app --search --image-stream=mongodb' "Tags:\s+3.2, 3.4, latest" os::cmd::expect_success_and_text 'oc new-app --search --image-stream=mysql' "Tags:\s+5.7, latest" -os::cmd::expect_success_and_text 'oc new-app --search --image-stream=nginx' "Tags:\s+1.10, 1.12, 1.8, latest" -os::cmd::expect_success_and_text 'oc new-app --search --image-stream=nodejs' "Tags:\s+10, 11, 6, 8, 8-RHOAR, latest" +os::cmd::expect_success_and_text 'oc new-app --search --image-stream=nginx' "Tags:\s+1.14, 1.16, latest" +os::cmd::expect_success_and_text 'oc new-app --search --image-stream=nodejs' "Tags:\s+10, 12, latest" os::cmd::expect_success_and_text 'oc new-app --search --image-stream=perl' "Tags:\s+5.24, 5.26, latest" os::cmd::expect_success_and_text 'oc new-app --search --image-stream=php' "Tags:\s+7.0, 7.1, latest" os::cmd::expect_success_and_text 'oc new-app --search --image-stream=postgresql' "Tags:\s+9.5, 9.6, latest" @@ -403,8 +385,8 @@ os::cmd::expect_failure_and_text 'oc new-app --search mysql --param=FOO=BAR' "ca os::cmd::expect_failure_and_not_text 'oc new-app --template foo' 'index out of range' # set context-dir -os::cmd::expect_success_and_text 'oc new-app https://github.com/sclorg/s2i-ruby-container.git --context-dir="2.4/test/puma-test-app" -o yaml' 'contextDir: 2.4/test/puma-test-app' -os::cmd::expect_success_and_text 'oc new-app ruby~https://github.com/sclorg/s2i-ruby-container.git --context-dir="2.4/test/puma-test-app" -o yaml' 'contextDir: 2.4/test/puma-test-app' +os::cmd::expect_success_and_text 'oc new-app https://github.com/sclorg/s2i-ruby-container.git --context-dir="2.5/test/puma-test-app" -o yaml' 'contextDir: 2.5/test/puma-test-app' +os::cmd::expect_success_and_text 'oc new-app ruby~https://github.com/sclorg/s2i-ruby-container.git --context-dir="2.5/test/puma-test-app" -o yaml' 'contextDir: 2.5/test/puma-test-app' # set strategy os::cmd::expect_success_and_text 'oc new-app ruby~https://github.com/openshift/ruby-hello-world.git --strategy=docker -o yaml' 'dockerStrategy' @@ -454,7 +436,7 @@ os::cmd::expect_success_and_text 'oc new-build --binary --image=ruby --strategy= # latest tag, new-app should fail. # when latest exists, we default to it and match it. os::cmd::expect_success 'oc new-app --image-stream ruby https://github.com/sclorg/rails-ex --dry-run' -# when latest does not exist, there are multiple partial matches (2.2, 2.3, 2.4, 2.5) +# when latest does not exist, there are multiple partial matches (2.5, 2.6) os::cmd::expect_success 'oc delete imagestreamtag ruby:latest' os::cmd::expect_failure_and_text 'oc new-app --image-stream ruby https://github.com/sclorg/rails-ex --dry-run' 'error: multiple images or templates matched \"ruby\"' # when only 2.6 exists, there is a single partial match (2.6) @@ -557,16 +539,16 @@ os::cmd::expect_success_and_not_text 'oc new-app https://github.com/openshift/ru os::cmd::expect_success 'oc new-app https://raw.githubusercontent.com/openshift/origin/master/examples/quickstarts/rails-postgresql.json --dry-run' # ensure that --strategy sets the build strategy -os::cmd::expect_success_and_text 'oc new-build --name sourcetest python~https://github.com/sclorg/django-ex --source-image centos:latest --source-image-path /tmp --strategy source --dry-run -o yaml' 'sourceStrategy' -os::cmd::expect_success_and_text 'oc new-build --name sourcetest python~https://github.com/sclorg/django-ex --source-image centos:latest --source-image-path /tmp --strategy pipeline --dry-run -o yaml' 'jenkinsPipelineStrategy' -os::cmd::expect_success_and_text 'oc new-build --name sourcetest python~https://github.com/sclorg/django-ex --source-image centos:latest --source-image-path /tmp --strategy docker --dry-run -o yaml' 'dockerStrategy' +os::cmd::expect_success_and_text 'oc new-build --name sourcetest python~https://github.com/sclorg/django-ex --source-image registry.centos.org/centos/centos:latest --source-image-path /tmp --strategy source --dry-run -o yaml' 'sourceStrategy' +os::cmd::expect_success_and_text 'oc new-build --name sourcetest python~https://github.com/sclorg/django-ex --source-image registry.centos.org/centos/centos:latest --source-image-path /tmp --strategy pipeline --dry-run -o yaml' 'jenkinsPipelineStrategy' +os::cmd::expect_success_and_text 'oc new-build --name sourcetest python~https://github.com/sclorg/django-ex --source-image registry.centos.org/centos/centos:latest --source-image-path /tmp --strategy docker --dry-run -o yaml' 'dockerStrategy' -os::cmd::expect_success 'oc create -f examples/image-streams/image-streams-centos7.json' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/image-streams/image-streams-centos7.json' os::cmd::try_until_success 'oc get imagestreamtags nodejs:latest' # ensure that a build can be created with just image inputs without the --binary flag -os::cmd::expect_success_and_text 'oc new-build --name sourcetest --source-image centos:latest --source-image-path /tmp --image-stream nodejs --dry-run -o yaml' 'sourceStrategy' +os::cmd::expect_success_and_text 'oc new-build --name sourcetest --source-image registry.centos.org/centos/centos:latest --source-image-path /tmp --image-stream nodejs --dry-run -o yaml' 'sourceStrategy' # ensure that using only image inputs and the --binary flag results in an error -os::cmd::expect_failure_and_text 'oc new-build --name sourcetest --source-image centos:latest --source-image-path /tmp --image-stream nodejs --binary --dry-run -o yaml' 'specifying binary builds and source repositories at the same time is not allowed' +os::cmd::expect_failure_and_text 'oc new-build --name sourcetest --source-image registry.centos.org/centos/centos:latest --source-image-path /tmp --image-stream nodejs --binary --dry-run -o yaml' 'specifying binary builds and source repositories at the same time is not allowed' os::cmd::expect_success 'oc delete imagestreams --all --ignore-not-found' # new-app different syntax for new-app functionality @@ -585,32 +567,32 @@ os::cmd::expect_success 'oc new-app -i ruby-27-centos7:latest --code ./test/test os::cmd::expect_success 'oc new-app --code ./test/testdata/testapp --name test' os::cmd::expect_success_and_text 'oc get bc test --template={{.spec.strategy.dockerStrategy.from.name}}' 'ruby-27-centos7:latest' -os::cmd::expect_success 'oc new-app -i php-55-centos7:latest --code ./test/testdata/testapp --name test2' -os::cmd::expect_success_and_text 'oc get bc test2 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-55-centos7:latest' +os::cmd::expect_success 'oc new-app -i php-70-centos7:latest --code ./test/testdata/testapp --name test2' +os::cmd::expect_success_and_text 'oc get bc test2 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-70-centos7:latest' -os::cmd::expect_success 'oc new-app -i php-55-centos7:latest~https://github.com/openshift/ruby-hello-world.git --name test3' -os::cmd::expect_success_and_text 'oc get bc test3 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-55-centos7:latest' +os::cmd::expect_success 'oc new-app -i php-70-centos7:latest~https://github.com/openshift/ruby-hello-world.git --name test3' +os::cmd::expect_success_and_text 'oc get bc test3 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-70-centos7:latest' -os::cmd::expect_success 'oc new-app php-55-centos7:latest~https://github.com/openshift/ruby-hello-world.git --name test4' -os::cmd::expect_success_and_text 'oc get bc test4 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-55-centos7:latest' +os::cmd::expect_success 'oc new-app php-70-centos7:latest~https://github.com/openshift/ruby-hello-world.git --name test4' +os::cmd::expect_success_and_text 'oc get bc test4 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-70-centos7:latest' -os::cmd::expect_success 'oc new-app -i php-55-centos7:latest https://github.com/openshift/ruby-hello-world.git --name test5' -os::cmd::expect_success_and_text 'oc get bc test5 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-55-centos7:latest' +os::cmd::expect_success 'oc new-app -i php-70-centos7:latest https://github.com/openshift/ruby-hello-world.git --name test5' +os::cmd::expect_success_and_text 'oc get bc test5 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-70-centos7:latest' -os::cmd::expect_success 'oc new-app php-55-centos7:latest --code https://github.com/openshift/ruby-hello-world.git --name test6' -os::cmd::expect_success_and_text 'oc get bc test6 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-55-centos7:latest' +os::cmd::expect_success 'oc new-app php-70-centos7:latest --code https://github.com/openshift/ruby-hello-world.git --name test6' +os::cmd::expect_success_and_text 'oc get bc test6 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-70-centos7:latest' os::cmd::expect_success 'oc new-app https://github.com/openshift/ruby-hello-world.git --name test7' os::cmd::expect_success_and_text 'oc get bc test7 --template={{.spec.strategy.dockerStrategy.from.name}}' 'ruby-27-centos7:latest' -os::cmd::expect_success 'oc new-app php-55-centos7:latest https://github.com/openshift/ruby-hello-world.git --name test8' -os::cmd::expect_success_and_text 'oc get bc test8 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-55-centos7:latest' +os::cmd::expect_success 'oc new-app php-70-centos7:latest https://github.com/openshift/ruby-hello-world.git --name test8' +os::cmd::expect_success_and_text 'oc get bc test8 --template={{.spec.strategy.sourceStrategy.from.name}}' 'php-70-centos7:latest' os::cmd::expect_success 'oc delete project new-app-syntax' # new-app docker build strategy with binary input os::cmd::expect_success 'oc project ${default_project}' os::cmd::expect_success 'oc delete all,templates --all' -os::cmd::expect_success 'oc create -f examples/image-streams/image-streams-centos7.json' +os::cmd::expect_success 'oc create -f ${TEST_DATA}/image-streams/image-streams-centos7.json' os::cmd::try_until_success 'oc get imagestreamtags ruby:latest' # need to wait until tags are available!? os::cmd::expect_failure_and_text 'oc new-app --strategy=docker --name my-docker-app' 'none of the arguments provided could be classified as a source code location' os::cmd::expect_success_and_text 'oc new-app --strategy=docker --binary --name my-docker-app' 'A binary build was created' diff --git a/test/extended/testdata/cmd/test/cmd/observe.sh b/test/extended/testdata/cmd/test/cmd/observe.sh deleted file mode 100755 index f0bf24dfa2db..000000000000 --- a/test/extended/testdata/cmd/test/cmd/observe.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT - -# Cleanup cluster resources created by this test -( - set +e - exit 0 -) &>/dev/null - -os::test::junit::declare_suite_start "cmd/observe" - -# basic scenarios -os::cmd::expect_failure_and_text 'oc observe' 'you must specify at least one argument containing the resource to observe' -os::cmd::expect_success_and_text 'oc observe serviceaccounts --once' 'Sync ended' -os::cmd::expect_success_and_text 'oc observe daemonsets --once' 'Nothing to sync, exiting immediately' -os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces' 'default kubernetes' -os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces --print-metrics-on-exit' 'observe_counts{type="Sync"}' -os::cmd::expect_failure_and_text 'oc observe services --once --names echo' '\-\-delete and \-\-names must both be specified' -os::cmd::expect_success_and_text 'oc observe services --exit-after=1s' 'Shutting down after 1s ...' -os::cmd::expect_success_and_text 'oc observe services --exit-after=1s --all-namespaces --print-metrics-on-exit' 'observe_counts{type="Sync"}' -os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces' 'default kubernetes' -os::cmd::expect_success_and_text 'oc observe services --once --exit-after=3s --all-namespaces --names echo --names default/notfound --delete echo --delete remove' 'remove default notfound' - -# error counting -os::cmd::expect_failure_and_text 'oc observe services --exit-after=1m --all-namespaces --maximum-errors=1 -- /bin/sh -c "exit 1"' 'reached maximum error limit of 1, exiting' -os::cmd::expect_failure_and_text 'oc observe services --exit-after=1m --all-namespaces --retry-on-exit-code=2 --maximum-errors=1 --loglevel=4 -- /bin/sh -c "exit 2"' 'retrying command: exit status 2' - -# argument templates -os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces -a "{ .spec.clusterIP }"' '172.30.0.1' -os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces -a "{{ .spec.clusterIP }}" --output=gotemplate' '172.30.0.1' -os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces -a "bad{ .missingkey }key"' 'badkey' -os::cmd::expect_failure_and_text 'oc observe services --once --all-namespaces -a "bad{ .missingkey }key" --strict-templates' 'missingkey is not found' -os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces -a "{{ .unknown }}" --output=gotemplate' '""' -os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces -a "bad{{ or (.unknown) \"\" }}key" --output=gotemplate' 'badkey' -# TODO: bring back when oc#472 merges -# os::cmd::expect_success_and_text 'oc observe services --once --all-namespaces -a "bad{{ .unknown }}key" --output=gotemplate --strict-templates' 'map has no entry for key' - -# --type-env-var -os::cmd::expect_success_and_text 'MYENV=should_be_passed oc observe services --once --all-namespaces --type-env-var=EVENT -- /bin/sh -c "echo \$EVENT \$MYENV"' 'Sync should_be_passed' - -echo "observe: ok" -os::test::junit::declare_suite_end diff --git a/test/extended/testdata/cmd/test/cmd/policy-storage-admin.sh b/test/extended/testdata/cmd/test/cmd/policy-storage-admin.sh deleted file mode 100755 index e0a068525abf..000000000000 --- a/test/extended/testdata/cmd/test/cmd/policy-storage-admin.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT - -project="$( oc project -q )" - -os::test::junit::declare_suite_start "cmd/policy-storage-admin" - -# Test storage-admin role and impersonation -os::cmd::expect_success 'oc adm policy add-cluster-role-to-user storage-admin storage-adm' -os::cmd::expect_success 'oc adm policy add-cluster-role-to-user storage-admin storage-adm2' -os::cmd::expect_success 'oc adm policy add-role-to-user admin storage-adm2' -os::cmd::expect_success_and_text 'oc policy who-can impersonate storage-admin' 'cluster-admin' - -# Test storage-admin role as user level -#os::cmd::expect_success 'oc login -u storage-adm -p pw' -#os::cmd::expect_success_and_text 'oc whoami' "storage-adm" -#os::cmd::expect_failure 'oc whoami --as=basic-user' -#os::cmd::expect_failure 'oc whoami --as=cluster-admin' - -# Test storage-admin can not do normal project scoped tasks -os::cmd::expect_failure_and_text 'oc auth can-i --as=storage-adm create pods --all-namespaces' 'no' -os::cmd::expect_failure_and_text 'oc auth can-i --as=storage-adm create projects' 'no' -os::cmd::expect_failure_and_text 'oc auth can-i --as=storage-adm create pvc' 'no' - -# Test storage-admin can read pvc and pods, and create pv and storageclass -os::cmd::expect_success_and_text 'oc auth can-i --as=storage-adm get pvc --all-namespaces' 'yes' -os::cmd::expect_success_and_text 'oc auth can-i --as=storage-adm get storageclass' 'yes' -os::cmd::expect_success_and_text 'oc auth can-i --as=storage-adm create pv' 'yes' -os::cmd::expect_success_and_text 'oc auth can-i --as=storage-adm create storageclass' 'yes' -os::cmd::expect_success_and_text 'oc auth can-i --as=storage-adm get pods --all-namespaces' 'yes' - -# Test failure to change policy on users for storage-admin -os::cmd::expect_failure_and_text 'oc policy --as=storage-adm add-role-to-user admin storage-adm' ' cannot list resource "rolebindings" in API group "rbac.authorization.k8s.io"' -os::cmd::expect_failure_and_text 'oc policy --as=storage-adm remove-user screeley' ' cannot list resource "rolebindings" in API group "rbac.authorization.k8s.io"' -#os::cmd::expect_success 'oc logout' - -# Test that scoped storage-admin now an admin in project foo -#os::cmd::expect_success 'oc login -u storage-adm2 -p pw' -#os::cmd::expect_success_and_text 'oc whoami' "storage-adm2" -os::cmd::expect_success 'oc new-project --as=storage-adm2 --as-group=system:authenticated:oauth --as-group=system:authenticated policy-can-i' -os::cmd::expect_failure_and_text 'oc auth can-i --as=storage-adm2 create pod --all-namespaces' 'no' -os::cmd::expect_success_and_text 'oc auth can-i --as=storage-adm2 create pod' 'yes' -os::cmd::expect_success_and_text 'oc auth can-i --as=storage-adm2 create pvc' 'yes' -os::cmd::expect_success_and_text 'oc auth can-i --as=storage-adm2 create endpoints' 'yes' -os::cmd::expect_success 'oc delete project policy-can-i' diff --git a/test/extended/testdata/cmd/test/cmd/printer.sh b/test/extended/testdata/cmd/test/cmd/printer.sh index a4af23ca75b7..bf2d1e3b5a11 100755 --- a/test/extended/testdata/cmd/test/cmd/printer.sh +++ b/test/extended/testdata/cmd/test/cmd/printer.sh @@ -5,7 +5,7 @@ trap os::test::junit::reconcile_output EXIT # Test that resource printer includes resource kind on multiple resources os::test::junit::declare_suite_start "cmd/basicresources/printer" os::cmd::expect_success 'oc create imagestream test1' -os::cmd::expect_success 'oc new-app node' +os::cmd::expect_success 'oc new-app openshift/nodejs' os::cmd::expect_success_and_text 'oc get all' 'imagestream.image.openshift.io/test1' os::cmd::expect_success_and_not_text 'oc get is' 'imagestream.image.openshift.io/test1' @@ -15,8 +15,8 @@ os::cmd::expect_success_and_text 'oc new-app ruby-helloworld-sample' 'deployment os::cmd::expect_success_and_text 'oc get all --all-namespaces' 'cmd-printer[\ ]+buildconfig.build.openshift.io\/ruby\-sample\-build' # Test that infos printer supports all outputFormat options -os::cmd::expect_success_and_text 'oc new-app node --dry-run -o yaml | oc set env --local -f - MYVAR=value' 'deployment.*.apps.*/node updated' -os::cmd::expect_success_and_text 'oc new-app node --dry-run -o yaml | oc set env --local -f - MYVAR=value -o yaml' 'apiVersion: apps.*/v1' -os::cmd::expect_success_and_text 'oc new-app node --dry-run -o yaml | oc set env --local -f - MYVAR=value -o json' '"apiVersion": "apps.*/v1"' +os::cmd::expect_success_and_text 'oc new-app openshift/nodejs --dry-run -o yaml | oc set env --local -f - MYVAR=value' 'deployment.*.apps.*/nodejs updated' +os::cmd::expect_success_and_text 'oc new-app openshift/nodejs --dry-run -o yaml | oc set env --local -f - MYVAR=value -o yaml' 'apiVersion: apps.*/v1' +os::cmd::expect_success_and_text 'oc new-app openshift/nodejs --dry-run -o yaml | oc set env --local -f - MYVAR=value -o json' '"apiVersion": "apps.*/v1"' echo "resource printer: ok" os::test::junit::declare_suite_end diff --git a/test/extended/testdata/cmd/test/cmd/quota.sh b/test/extended/testdata/cmd/test/cmd/quota.sh index 05bc82f4ce5e..814ed5eaf13d 100755 --- a/test/extended/testdata/cmd/test/cmd/quota.sh +++ b/test/extended/testdata/cmd/test/cmd/quota.sh @@ -26,7 +26,7 @@ os::cmd::expect_success 'oc create clusterquota for-deads --project-label-select os::cmd::try_until_text 'oc get appliedclusterresourcequota -n quota-foo --as deads -o name' "for-deads" os::cmd::try_until_text 'oc get secrets --all-namespaces; oc get appliedclusterresourcequota/for-deads -n quota-foo --as deads -o jsonpath=used={.status.total.used.secrets}' "used=9" -os::cmd::expect_failure_and_text 'oc create clusterquota for-deads-malformed --project-annotation-selector="openshift.#$%/requester=deads"' "prefix part a DNS-1123 subdomain must consist of lower case alphanumeric characters" +os::cmd::expect_failure_and_text 'oc create clusterquota for-deads-malformed --project-annotation-selector="openshift.#$%/requester=deads"' "prefix part a (DNS-1123|lowercase RFC 1123) subdomain must consist of lower case alphanumeric characters" os::cmd::expect_failure_and_text 'oc create clusterquota for-deads-malformed --project-annotation-selector=openshift.io/requester=deads,openshift.io/novalue' "Malformed annotation selector" os::cmd::expect_success 'oc create clusterquota for-deads-by-annotation --project-annotation-selector=openshift.io/requester=deads --hard=secrets=50' os::cmd::expect_success 'oc create clusterquota for-deads-email-by-annotation --project-annotation-selector=openshift.io/requester=deads@deads.io --hard=secrets=50' @@ -55,7 +55,7 @@ os::cmd::expect_success 'oc new-project quota-images --as=deads --as-group=syst os::cmd::expect_success 'oc create quota -n quota-images is-quota --hard openshift.io/imagestreams=1' os::cmd::try_until_success 'oc tag -n quota-images openshift/hello-openshift myis2:v2' os::cmd::expect_failure_and_text 'oc tag -n quota-images busybox mybox:v1' "exceeded quota" -os::cmd::expect_failure_and_text 'oc import-image centos -n quota-images --from=docker.io/centos:latest --confirm=true' "exceeded quota" +os::cmd::expect_failure_and_text 'oc import-image centos -n quota-images --from=registry.centos.org/centos:latest --confirm=true' "exceeded quota" os::cmd::expect_success 'oc delete project quota-images' echo "imagestreams: ok" diff --git a/test/extended/testdata/cmd/test/cmd/rsync.sh b/test/extended/testdata/cmd/test/cmd/rsync.sh deleted file mode 100755 index 38058730aaa1..000000000000 --- a/test/extended/testdata/cmd/test/cmd/rsync.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT - -# Cleanup cluster resources created by this test -( - set +e - oc delete all --all - exit 0 -) &>/dev/null - -os::test::junit::declare_suite_start "cmd/rsync" -# This test validates the rsync command -os::cmd::expect_success 'oc create -f - << __EOF__ -apiVersion: v1 -kind: Pod -metadata: - name: valid-pod - labels: - name: valid-pod -spec: - containers: - - name: kubernetes-serve-hostname - image: k8s.gcr.io/serve_hostname - resources: - limits: - cpu: "1" - memory: 512Mi -__EOF__' - -temp_dir=$(mktemp -d) -include_file=$(mktemp -p $temp_dir) -exclude_file=$(mktemp -p $temp_dir) - -# we don't actually have a kubelet running, so no "tar" binary will be available in container because there will be no container. -# instead, ensure that the tar command to be executed is formatted correctly based on our --include and --exclude values -os::cmd::expect_failure_and_text "oc rsync --strategy=tar --include=$include_file --exclude=$exclude_file $temp_dir valid-pod:/tmp --loglevel 4" "running command: tar.*\*\*\/$include_file.*--exclude=$exclude_file" - -echo "rsync: ok" -os::test::junit::declare_suite_end diff --git a/test/extended/testdata/cmd/test/cmd/secrets.sh b/test/extended/testdata/cmd/test/cmd/secrets.sh index 31fb2f8b8527..66c82abf6040 100755 --- a/test/extended/testdata/cmd/test/cmd/secrets.sh +++ b/test/extended/testdata/cmd/test/cmd/secrets.sh @@ -26,7 +26,9 @@ os::cmd::expect_success_and_text 'oc get secret/from-file --template="{{ .type } os::cmd::expect_success_and_text 'oc create secret docker-registry dockerconfigjson --docker-username=sample-user --docker-password=sample-password --docker-email=fake@example.org --dry-run -o yaml' 'kubernetes.io/dockerconfigjson' os::cmd::expect_success_and_text 'oc create secret generic from-file-again --from-file=.dockerconfigjson=${HOME}/dockerconfigjson --type=kubernetes.io/dockerconfigjson -o yaml' 'kubernetes.io/dockerconfigjson' # check to make sure malformed names fail as expected -os::cmd::expect_failure_and_text 'oc create secret generic bad-name --from-file=.docker=cfg=${HOME}/dockerconfigjson' "error: Key names or file paths cannot contain '='" +# TODO(jchaloup): "error: Key names or file paths cannot contain '='" changed into "error: key names or file paths cannot contain '='" (s/K/k) +# Once oc rebase to 1.20 is merged, enable this test again with s/K/k +# os::cmd::expect_failure_and_text 'oc create secret generic bad-name --from-file=.docker=cfg=${HOME}/dockerconfigjson' "error: key names or file paths cannot contain '='" workingdir="$( mktemp -d )" os::cmd::try_until_success "oc get secret/dockerconfigjson" diff --git a/test/extended/testdata/cmd/test/cmd/status.sh b/test/extended/testdata/cmd/test/cmd/status.sh index e4697451c31c..44ff65c4ae47 100755 --- a/test/extended/testdata/cmd/test/cmd/status.sh +++ b/test/extended/testdata/cmd/test/cmd/status.sh @@ -81,8 +81,8 @@ os::cmd::try_until_not_text "oc get projects" "project-bar-2" os::cmd::expect_success "oc new-project project-status --display-name='my project' --description='test project'" # Verify jobs are showing in status -os::cmd::expect_success "oc create job pi --image=perl -- perl -Mbignum=bpi -wle 'print bpi(2000)'" -os::cmd::expect_success_and_text "oc status" "job/pi manages perl" +os::cmd::expect_success "oc create job pi --image=image-registry.openshift-image-registry.svc:5000/openshift/tools:latest -- perl -Mbignum=bpi -wle 'print bpi(2000)'" +os::cmd::expect_success_and_text "oc status" "job/pi manages image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" # logout #os::cmd::expect_success "oc logout" diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/README.md b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/README.md deleted file mode 100644 index 49d65ce5f32a..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/README.md +++ /dev/null @@ -1,4 +0,0 @@ -All files in the folder are loaded into the API during tests, so they should: -* Not create resources that duel with each other -* Not include allocated values that could flake (like service clusterIP addresses) -* Pay attention to creation order (for example, create pods first, then statefulsets, so the create doesn't race with the statefulset controller) diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/app/Dockerfile b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/app/Dockerfile deleted file mode 100644 index 81ce429e0926..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/app/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM node:0.10.38 - -RUN mkdir /src - -RUN npm install nodemon -g - -WORKDIR /src -ADD package.json package.json -RUN npm install - -ADD nodemon.json nodemon.json diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.generated.yaml b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.generated.yaml deleted file mode 100644 index b57f99fb280c..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.generated.yaml +++ /dev/null @@ -1,307 +0,0 @@ -apiVersion: v1 -items: -- apiVersion: v1 - kind: ImageStream - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: nginx - spec: - tags: - - annotations: - openshift.io/imported-from: tutum/nginx - from: - kind: DockerImage - name: tutum/nginx - generation: null - importPolicy: {} - name: from - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: BuildConfig - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: nginx - spec: - output: - to: - kind: ImageStreamTag - name: nginx:latest - postCommit: {} - resources: {} - source: - contextDir: test/testdata/app-scenarios/docker-compose/complex/nginx - git: - ref: libcompose - uri: git@github.com:openshift/origin.git - secrets: null - type: Git - strategy: - dockerStrategy: - from: - kind: ImageStreamTag - name: nginx:from - type: Docker - triggers: - - github: - secret: IE96Fw4CdQs-g3giIjWZ - type: GitHub - - generic: - secret: B8mx-lYjIBjNY6ymP6MT - type: Generic - - type: ConfigChange - - imageChange: {} - type: ImageChange - status: - lastVersion: 0 -- apiVersion: v1 - kind: ImageStream - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: web - spec: - tags: - - annotations: - openshift.io/imported-from: node:0.10.38 - from: - kind: DockerImage - name: node:0.10.38 - generation: null - importPolicy: {} - name: from - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: BuildConfig - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: web - spec: - output: - to: - kind: ImageStreamTag - name: web:latest - postCommit: {} - resources: {} - source: - contextDir: test/testdata/app-scenarios/docker-compose/complex/app - git: - ref: libcompose - uri: git@github.com:openshift/origin.git - secrets: null - type: Git - strategy: - dockerStrategy: - from: - kind: ImageStreamTag - name: web:from - type: Docker - triggers: - - github: - secret: xMiKAo9EEZMKMxCRZSUk - type: GitHub - - generic: - secret: doIIibCQIxRvv28uyP9J - type: Generic - - type: ConfigChange - - imageChange: {} - type: ImageChange - status: - lastVersion: 0 -- apiVersion: v1 - kind: ImageStream - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: db - spec: - tags: - - annotations: - openshift.io/imported-from: redis - from: - kind: DockerImage - name: redis - generation: null - importPolicy: {} - name: latest - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: DeploymentConfig - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: db - spec: - replicas: 1 - selector: - deploymentconfig: db - strategy: - resources: {} - template: - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - deploymentconfig: db - spec: - containers: - - image: redis - name: db - ports: - - containerPort: 6379 - resources: - limits: - cpu: 100m - memory: 1G - test: false - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - db - from: - kind: ImageStreamTag - name: db:latest - type: ImageChange - status: {} -- apiVersion: v1 - kind: DeploymentConfig - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: nginx - spec: - replicas: 1 - selector: - deploymentconfig: nginx - strategy: - resources: {} - template: - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - deploymentconfig: nginx - spec: - containers: - - image: nginx - name: nginx - ports: - - containerPort: 80 - resources: {} - volumeMounts: - - mountPath: /www/public - name: dir-1 - - mountPath: /src/app - name: dir-2 - - args: - - nodemon - - -L - - app/bin/www - image: web - name: web - ports: - - containerPort: 3000 - resources: - requests: - cpu: 500m - volumeMounts: - - mountPath: /src/app - name: dir-2 - volumes: - - emptyDir: {} - name: dir-1 - - emptyDir: {} - name: dir-2 - test: false - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - nginx - from: - kind: ImageStreamTag - name: nginx:latest - type: ImageChange - - imageChangeParams: - automatic: true - containerNames: - - web - from: - kind: ImageStreamTag - name: web:latest - type: ImageChange - status: {} -- apiVersion: v1 - kind: Service - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: redis - spec: - ports: - - name: 6379-tcp - port: 6379 - targetPort: 6379 - selector: - deploymentconfig: db - status: - loadBalancer: {} -- apiVersion: v1 - kind: Service - metadata: - annotations: - openshift.io/generated-by: OpenShiftNewApp - creationTimestamp: null - labels: - app: nginx - name: nginx - spec: - ports: - - name: 80-tcp - port: 80 - targetPort: 80 - - name: 3000-tcp - port: 3000 - targetPort: 3000 - selector: - deploymentconfig: nginx - status: - loadBalancer: {} -kind: List -metadata: {} diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.imported.yaml b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.imported.yaml deleted file mode 100644 index dfaaae8bfc15..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.imported.yaml +++ /dev/null @@ -1,343 +0,0 @@ -apiVersion: v1 -items: -- apiVersion: v1 - kind: ImageStream - metadata: - creationTimestamp: null - name: nginx - spec: - tags: - - annotations: - openshift.io/imported-from: tutum/nginx - from: - kind: DockerImage - name: tutum/nginx - generation: null - importPolicy: {} - name: from - referencePolicy: - type: "" - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: BuildConfig - metadata: - creationTimestamp: null - name: nginx - spec: - nodeSelector: null - output: - to: - kind: ImageStreamTag - name: nginx:latest - postCommit: {} - resources: {} - source: - contextDir: test/testdata/app-scenarios/docker-compose/complex/nginx - git: - ref: master - uri: git@github.com:openshift/origin.git - secrets: null - type: Git - strategy: - dockerStrategy: - from: - kind: ImageStreamTag - name: nginx:from - type: Docker - triggers: - - github: - secret: FdDzZzJCBkHQGxYMMBw0 - type: GitHub - - generic: - secret: wMAV07N8TWt9dz40LDjL - type: Generic - - type: ConfigChange - - imageChange: {} - type: ImageChange - status: - lastVersion: 0 -- apiVersion: v1 - kind: ImageStream - metadata: - creationTimestamp: null - name: web - spec: - tags: - - annotations: - openshift.io/imported-from: node:0.10.38 - from: - kind: DockerImage - name: node:0.10.38 - generation: null - importPolicy: {} - name: from - referencePolicy: - type: "" - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: BuildConfig - metadata: - creationTimestamp: null - name: web - spec: - nodeSelector: null - output: - to: - kind: ImageStreamTag - name: web:latest - postCommit: {} - resources: {} - source: - contextDir: test/testdata/app-scenarios/docker-compose/complex/app - git: - ref: master - uri: git@github.com:openshift/origin.git - secrets: null - type: Git - strategy: - dockerStrategy: - from: - kind: ImageStreamTag - name: web:from - type: Docker - triggers: - - github: - secret: 3QSLvrej6A2E-CMYSEvQ - type: GitHub - - generic: - secret: uBl0LIK0anHOaRJ8-4dI - type: Generic - - type: ConfigChange - - imageChange: {} - type: ImageChange - status: - lastVersion: 0 -- apiVersion: v1 - kind: ImageStream - metadata: - creationTimestamp: null - name: db - spec: - tags: - - annotations: - openshift.io/imported-from: redis - from: - kind: DockerImage - name: redis - generation: null - importPolicy: {} - name: latest - referencePolicy: - type: "" - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: null - name: db - spec: - replicas: 1 - selector: - deploymentconfig: db - strategy: - resources: {} - template: - metadata: - creationTimestamp: null - labels: - deploymentconfig: db - spec: - containers: - - image: redis - name: db - ports: - - containerPort: 6379 - resources: - limits: - cpu: 100m - memory: 1G - test: false - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - db - from: - kind: ImageStreamTag - name: db:latest - type: ImageChange - status: - availableReplicas: 0 - latestVersion: 0 - observedGeneration: 0 - replicas: 0 - unavailableReplicas: 0 - updatedReplicas: 0 -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: null - name: nginx - spec: - replicas: 1 - selector: - deploymentconfig: nginx - strategy: - resources: {} - template: - metadata: - creationTimestamp: null - labels: - deploymentconfig: nginx - spec: - containers: - - image: nginx - name: nginx - ports: - - containerPort: 80 - resources: {} - volumeMounts: - - mountPath: /www/public - name: dir-1 - - mountPath: /src/app - name: dir-2 - - args: - - nodemon - - -L - - app/bin/www - image: web - name: web - ports: - - containerPort: 3000 - resources: - requests: - cpu: 500m - volumeMounts: - - mountPath: /src/app - name: dir-2 - volumes: - - emptyDir: {} - name: dir-1 - - emptyDir: {} - name: dir-2 - test: false - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - nginx - from: - kind: ImageStreamTag - name: nginx:latest - type: ImageChange - - imageChangeParams: - automatic: true - containerNames: - - web - from: - kind: ImageStreamTag - name: web:latest - type: ImageChange - status: - availableReplicas: 0 - latestVersion: 0 - observedGeneration: 0 - replicas: 0 - unavailableReplicas: 0 - updatedReplicas: 0 -- apiVersion: v1 - kind: ImageStream - metadata: - creationTimestamp: null - name: no-ports - spec: - tags: - - annotations: - openshift.io/imported-from: redis - from: - kind: DockerImage - name: redis - generation: null - importPolicy: {} - name: latest - referencePolicy: - type: "" - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: null - name: no-ports - spec: - replicas: 1 - selector: - deploymentconfig: no-ports - strategy: - resources: {} - template: - metadata: - creationTimestamp: null - labels: - deploymentconfig: no-ports - spec: - containers: - - image: redis - name: no-ports - resources: {} - test: false - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - no-ports - from: - kind: ImageStreamTag - name: no-ports:latest - type: ImageChange - status: - availableReplicas: 0 - latestVersion: 0 - observedGeneration: 0 - replicas: 0 - unavailableReplicas: 0 - updatedReplicas: 0 -- apiVersion: v1 - kind: Service - metadata: - creationTimestamp: null - name: redis - spec: - ports: - - name: 6379-tcp - port: 6379 - targetPort: 6379 - selector: - deploymentconfig: db - status: - loadBalancer: {} -- apiVersion: v1 - kind: Service - metadata: - creationTimestamp: null - name: nginx - spec: - ports: - - name: 80-tcp - port: 80 - targetPort: 80 - - name: 3000-tcp - port: 3000 - targetPort: 3000 - selector: - deploymentconfig: nginx - status: - loadBalancer: {} -kind: List -metadata: {} diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.yml b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.yml deleted file mode 100644 index 2d8a8a7dd349..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/docker-compose.yml +++ /dev/null @@ -1,33 +0,0 @@ -web: - build: ./app - volumes: - - "./app:/src/app" - ports: - - "3030:3000" - links: - - "db:redis" - command: nodemon -L app/bin/www - cpu_shares: 512 - -nginx: - restart: always - build: ./nginx/ - ports: - - "80:80" - volumes: - - /www/public - volumes_from: - - web - links: - - web:web - -db: - image: redis - ports: - - "6379:6379" - cpu_quota: 10000 - mem_limit: 1000000000 - cpuset: 1 - -no-ports: - image: redis \ No newline at end of file diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/nginx/Dockerfile b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/nginx/Dockerfile deleted file mode 100644 index 2a996964e3b0..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/complex/nginx/Dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -FROM tutum/nginx -RUN rm /etc/nginx/sites-enabled/default -ADD sites-enabled/ /etc/nginx/sites-enabled diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/wordpress/docker-compose.yml b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/wordpress/docker-compose.yml deleted file mode 100644 index da75d84b0f2e..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/docker-compose/wordpress/docker-compose.yml +++ /dev/null @@ -1,24 +0,0 @@ -version: "2" -services: - WP: - image: "centurylink/wordpress:3.9.1" - links: - - "DB:DB_1" - ports: - - "8080:80" - environment: - - "DB_PASSWORD=pass@word01" - - DB_NAME=wordpress - dns: - - 8.8.8.8 - - 9.9.9.9 - hostname: wordpress - domainname: wordpress.mysite.com - DB: - image: "centurylink/mysql:5.5" - ports: - - "3306:3306" - environment: - - "MYSQL_ROOT_PASSWORD=pass@word01" - mem_limit: "1000000000" - cpu_shares: "40" diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-lonely-pod.json b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-lonely-pod.json deleted file mode 100644 index 8feae88a2363..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-lonely-pod.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "kind": "List", - "apiVersion": "v1", - "metadata": {}, - "items": [ - { - "kind": "Pod", - "apiVersion": "v1", - "metadata": { - "name": "lonely-pod", - "creationTimestamp": null, - "labels": { - "name": "lonely-pod" - } - }, - "spec": { - "containers": [ - { - "name": "lonely-pod", - "image": "openshift/hello-openshift", - "ports": [ - { - "containerPort": 8080, - "protocol": "TCP" - } - ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "capabilities": {}, - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst" - }, - "status": {} - } - ] -} \ No newline at end of file diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-sample-app.json b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-sample-app.json deleted file mode 100644 index 746fcb644c8f..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-sample-app.json +++ /dev/null @@ -1,203 +0,0 @@ -{ - "kind": "List", - "apiVersion": "v1", - "metadata": {}, - "items": [ - { - "kind": "ReplicationController", - "apiVersion": "v1", - "metadata": { - "name": "database-app-1", - "creationTimestamp": null, - "labels": { - "template": "ruby-helloworld-sample" - } - }, - "spec": { - "replicas": 1, - "selector": { - "name": "database", - "deconflict": "database.app" - }, - "template": { - "metadata": { - "creationTimestamp": null, - "labels": { - "name": "database", - "template": "ruby-helloworld-sample", - "deconflict": "database.app" - } - }, - "spec": { - "containers": [ - { - "name": "ruby-helloworld-database", - "image": "mysql", - "ports": [ - { - "containerPort": 3306, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "MYSQL_ROOT_PASSWORD", - "value": "rQHfVnTo" - }, - { - "name": "MYSQL_DATABASE", - "value": "root" - } - ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "capabilities": {}, - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst" - } - } - }, - "status": { - "replicas": 0 - } - }, - { - "kind": "ReplicationController", - "apiVersion": "v1", - "metadata": { - "name": "frontend-app-1", - "creationTimestamp": null, - "labels": { - "template": "ruby-helloworld-sample" - } - }, - "spec": { - "replicas": 3, - "selector": { - "name": "frontend", - "deconflict": "frontend.app" - }, - "template": { - "metadata": { - "creationTimestamp": null, - "labels": { - "name": "frontend", - "template": "ruby-helloworld-sample", - "deconflict": "frontend.app" - } - }, - "spec": { - "containers": [ - { - "name": "ruby-helloworld", - "image": "openshift/ruby-hello-world", - "ports": [ - { - "containerPort": 8080, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "ADMIN_USERNAME", - "value": "admin6TM" - }, - { - "name": "ADMIN_PASSWORD", - "value": "xImx1tHR" - }, - { - "name": "MYSQL_ROOT_PASSWORD", - "value": "rQHfVnTo" - }, - { - "name": "MYSQL_DATABASE", - "value": "root" - } - ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "capabilities": {}, - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst" - } - } - }, - "status": { - "replicas": 0 - } - }, - { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "database-app", - "creationTimestamp": null, - "labels": { - "template": "ruby-helloworld-sample" - } - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 5434, - "targetPort": 3306, - "nodePort": 0 - } - ], - "selector": { - "name": "database" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } - }, - { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "frontend-app", - "creationTimestamp": null, - "labels": { - "template": "ruby-helloworld-sample" - } - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 5432, - "targetPort": 8080, - "nodePort": 0 - } - ], - "selector": { - "name": "frontend" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } - } - ] -} \ No newline at end of file diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-service-pod-no-rc.json b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-service-pod-no-rc.json deleted file mode 100644 index df9d94133549..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-service-pod-no-rc.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "kind": "List", - "apiVersion": "v1", - "metadata": {}, - "items": [ - { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "hello-openshift", - "creationTimestamp": null, - "labels": { - "template": "hello-openshift" - } - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 5432, - "targetPort": 8080, - "nodePort": 0 - } - ], - "selector": { - "name": "hello-openshift" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } - }, - { - "kind": "Pod", - "apiVersion": "v1", - "metadata": { - "name": "hello-openshift", - "creationTimestamp": null, - "labels": { - "name": "hello-openshift" - } - }, - "spec": { - "containers": [ - { - "name": "hello-openshift", - "image": "openshift/hello-openshift", - "ports": [ - { - "containerPort": 8080, - "protocol": "TCP" - } - ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "capabilities": {}, - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst" - }, - "status": {} - } - ] -} \ No newline at end of file diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-service-with-nothing.json b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-service-with-nothing.json deleted file mode 100644 index 3a58a390f2d9..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-service-with-nothing.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "kind": "List", - "apiVersion": "v1", - "metadata": {}, - "items": [ - { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "empty-service", - "creationTimestamp": null, - "labels": { - "template": "empty-service" - } - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 5432, - "targetPort": 8080, - "nodePort": 0 - } - ], - "selector": { - "name": "empty-service" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } - } - ] -} \ No newline at end of file diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-unserviced-rc.json b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-unserviced-rc.json deleted file mode 100644 index 7a5d88339930..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/k8s-unserviced-rc.json +++ /dev/null @@ -1,174 +0,0 @@ -{ - "kind": "List", - "apiVersion": "v1", - "metadata": {}, - "items": [ - { - "kind": "ReplicationController", - "apiVersion": "v1", - "metadata": { - "name": "database-rc-1", - "creationTimestamp": null, - "labels": { - "template": "ruby-helloworld-sample" - } - }, - "spec": { - "replicas": 1, - "selector": { - "name": "database", - "deconflict": "database.rc" - }, - "template": { - "metadata": { - "creationTimestamp": null, - "labels": { - "name": "database", - "template": "ruby-helloworld-sample", - "deconflict": "database.rc" - } - }, - "spec": { - "containers": [ - { - "name": "ruby-helloworld-database", - "image": "mysql", - "ports": [ - { - "containerPort": 3306, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "MYSQL_ROOT_PASSWORD", - "value": "rQHfVnTo" - }, - { - "name": "MYSQL_DATABASE", - "value": "root" - } - ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "capabilities": {}, - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst" - } - } - }, - "status": { - "replicas": 0 - } - }, - { - "kind": "ReplicationController", - "apiVersion": "v1", - "metadata": { - "name": "frontend-rc-1", - "creationTimestamp": null, - "labels": { - "template": "ruby-helloworld-sample" - } - }, - "spec": { - "replicas": 3, - "selector": { - "name": "frontend", - "deconflict": "frontend.rc" - }, - "template": { - "metadata": { - "creationTimestamp": null, - "labels": { - "name": "frontend", - "template": "ruby-helloworld-sample", - "deconflict": "frontend.rc" - } - }, - "spec": { - "containers": [ - { - "name": "ruby-helloworld", - "image": "openshift/ruby-hello-world", - "ports": [ - { - "containerPort": 8080, - "protocol": "TCP" - } - ], - "env": [ - { - "name": "ADMIN_USERNAME", - "value": "admin6TM" - }, - { - "name": "ADMIN_PASSWORD", - "value": "xImx1tHR" - }, - { - "name": "MYSQL_ROOT_PASSWORD", - "value": "rQHfVnTo" - }, - { - "name": "MYSQL_DATABASE", - "value": "root" - } - ], - "resources": {}, - "terminationMessagePath": "/dev/termination-log", - "imagePullPolicy": "IfNotPresent", - "capabilities": {}, - "securityContext": { - "capabilities": {}, - "privileged": false - } - } - ], - "restartPolicy": "Always", - "dnsPolicy": "ClusterFirst" - } - } - }, - "status": { - "replicas": 0 - } - }, - { - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "database-rc", - "creationTimestamp": null, - "labels": { - "template": "ruby-helloworld-sample" - } - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 5434, - "targetPort": 3306, - "nodePort": 0 - } - ], - "selector": { - "name": "database" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } - } - ] -} \ No newline at end of file diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-deployed-app.yaml b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-deployed-app.yaml deleted file mode 100644 index 2b7c947d0af6..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-deployed-app.yaml +++ /dev/null @@ -1,550 +0,0 @@ -apiVersion: v1 -items: -- apiVersion: v1 - kind: BuildConfig - metadata: - creationTimestamp: 2015-04-07T04:12:17Z - labels: - name: ruby-sample-build - template: application-template-stibuild - name: ruby-sample-build - namespace: example - spec: - output: - to: - kind: ImageStreamTag - name: origin-ruby-sample:latest - resources: {} - source: - git: - uri: git://github.com/openshift/ruby-hello-world.git - type: Git - strategy: - sourceStrategy: - from: - kind: DockerImage - name: centos/ruby-25-centos7 - incremental: true - type: Source - triggers: - - github: - secret: secret101 - type: github - - generic: - secret: secret101 - type: generic - - imageChange: - lastTriggeredImageID: centos/ruby-25-centos7:latest - type: imageChange - status: - lastVersion: 1 -- apiVersion: v1 - kind: Build - metadata: - creationTimestamp: 2015-04-07T04:12:18Z - labels: - buildconfig: ruby-sample-build - name: ruby-sample-build - template: application-template-stibuild - name: ruby-sample-build-1 - namespace: example - spec: - output: - to: - kind: ImageStreamTag - name: origin-ruby-sample:latest - resources: {} - source: - git: - uri: git://github.com/openshift/ruby-hello-world.git - type: Git - strategy: - sourceStrategy: - from: - kind: DockerImage - name: centos/ruby-25-centos7:latest - incremental: true - type: Source - status: - completionTimestamp: 2015-04-07T04:13:01Z - config: - kind: BuildConfig - name: ruby-sample-build - - phase: Complete - startTimestamp: 2015-04-07T04:12:21Z -- apiVersion: v1 - kind: ReplicationController - metadata: - annotations: - openshift.io/deployment-config.name: database - openshift.io/deployment.phase: Running - openshift.io/deployment-config.latest-version: "2" - openshift.io/encoded-deployment-config: '{"kind":"DeploymentConfig","apiVersion":"v1beta1","metadata":{"name":"database","namespace":"test","selfLink":"/osapi/v1beta1/watch/deploymentConfigs/database","uid":"4725b5d3-dcdc-11e4-968a-080027c5bfa9","resourceVersion":"271","creationTimestamp":"2015-04-07T04:12:17Z","labels":{"template":"application-template-stibuild"}},"triggers":[{"type":"ConfigChange"}],"template":{"strategy":{"type":"Recreate"},"controllerTemplate":{"replicas":1,"replicaSelector":{"name":"database"},"podTemplate":{"desiredState":{"manifest":{"version":"v1beta2","id":"","volumes":null,"containers":[{"name":"ruby-helloworld-database","image":"centos/mysql-56-centos7","ports":[{"containerPort":3306,"protocol":"TCP"}],"env":[{"name":"MYSQL_USER","key":"MYSQL_USER","value":"user1CY"},{"name":"MYSQL_PASSWORD","key":"MYSQL_PASSWORD","value":"FfyXmsGG"},{"name":"MYSQL_DATABASE","key":"MYSQL_DATABASE","value":"root"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"PullIfNotPresent","capabilities":{}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"}},"labels":{"name":"database","template":"application-template-stibuild"}}}},"latestVersion":1,"details":{"causes":[{"type":"ConfigChange"}]}}' - pod: deploy-database-19m1he - creationTimestamp: 2015-04-07T04:12:18Z - labels: - template: application-template-stibuild - name: database-2 - namespace: example - spec: - replicas: 1 - selector: - deployment: database-2 - deploymentconfig: database - name: database - template: - metadata: - annotations: - openshift.io/deployment.name: database-2 - openshift.io/deployment-config.name: database - openshift.io/deployment-config.latest-version: "2" - creationTimestamp: null - labels: - deployment: database-2 - deploymentconfig: database - name: database - template: application-template-stibuild - spec: - containers: - - capabilities: {} - env: - - name: MYSQL_USER - value: user1CY - - name: MYSQL_PASSWORD - value: FfyXmsGG - - name: MYSQL_DATABASE - value: root - image: centos/mysql-56-centos7 - imagePullPolicy: IfNotPresent - name: ruby-helloworld-database - ports: - - containerPort: 3306 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - status: - replicas: 2 -- apiVersion: v1 - kind: ReplicationController - metadata: - annotations: - openshift.io/deployment-config.name: database - openshift.io/deployment.phase: Complete - openshift.io/deployment-config.latest-version: "1" - openshift.io/encoded-deployment-config: '{"kind":"DeploymentConfig","apiVersion":"v1beta1","metadata":{"name":"database","namespace":"test","selfLink":"/osapi/v1beta1/watch/deploymentConfigs/database","uid":"4725b5d3-dcdc-11e4-968a-080027c5bfa9","resourceVersion":"271","creationTimestamp":"2015-04-07T04:12:17Z","labels":{"template":"application-template-stibuild"}},"triggers":[{"type":"ConfigChange"}],"template":{"strategy":{"type":"Recreate"},"controllerTemplate":{"replicas":1,"replicaSelector":{"name":"database"},"podTemplate":{"desiredState":{"manifest":{"version":"v1beta2","id":"","volumes":null,"containers":[{"name":"ruby-helloworld-database","image":"centos/mysql-56-centos7","ports":[{"containerPort":3306,"protocol":"TCP"}],"env":[{"name":"MYSQL_USER","key":"MYSQL_USER","value":"user1CY"},{"name":"MYSQL_PASSWORD","key":"MYSQL_PASSWORD","value":"FfyXmsGG"},{"name":"MYSQL_DATABASE","key":"MYSQL_DATABASE","value":"root"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"PullIfNotPresent","capabilities":{}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"}},"labels":{"name":"database","template":"application-template-stibuild"}}}},"latestVersion":1,"details":{"causes":[{"type":"ConfigChange"}]}}' - pod: deploy-database-19m1he - creationTimestamp: 2015-04-07T04:12:17Z - labels: - template: application-template-stibuild - name: database-1 - namespace: example - spec: - replicas: 1 - selector: - deployment: database-1 - deploymentconfig: database - name: database - template: - metadata: - annotations: - openshift.io/deployment.name: database-1 - openshift.io/deployment-config.name: database - openshift.io/deployment-config.latest-version: "1" - creationTimestamp: null - labels: - deployment: database-1 - deploymentconfig: database - name: database - template: application-template-stibuild - spec: - containers: - - capabilities: {} - env: - - name: MYSQL_USER - value: user1CY - - name: MYSQL_PASSWORD - value: FfyXmsGG - - name: MYSQL_DATABASE - value: root - image: centos/mysql-56-centos7 - imagePullPolicy: IfNotPresent - name: ruby-helloworld-database - ports: - - containerPort: 3306 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - status: - replicas: 1 -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: 2015-04-07T04:12:17Z - labels: - template: application-template-stibuild - name: database - namespace: example - spec: - replicas: 1 - selector: - name: database - strategy: - resources: {} - type: Recreate - template: - metadata: - creationTimestamp: null - labels: - name: database - template: application-template-stibuild - spec: - containers: - - capabilities: {} - env: - - name: MYSQL_USER - value: user1CY - - name: MYSQL_PASSWORD - value: FfyXmsGG - - name: MYSQL_DATABASE - value: root - image: centos/mysql-56-centos7 - imagePullPolicy: IfNotPresent - name: ruby-helloworld-database - ports: - - containerPort: 3306 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - test: true - triggers: - - type: ConfigChange - status: - details: - causes: - - type: ConfigChange - latestVersion: 1 -- apiVersion: v1 - kind: ReplicationController - metadata: - annotations: - openshift.io/deployment-config.name: frontend - openshift.io/deployment.phase: Failed - openshift.io/deployment-config.latest-version: "2" - openshift.io/encoded-deployment-config: '{"kind":"DeploymentConfig","apiVersion":"v1beta1","metadata":{"name":"frontend","namespace":"test","selfLink":"/osapi/v1beta1/watch/deploymentConfigs/frontend","uid":"471f24e3-dcdc-11e4-968a-080027c5bfa9","resourceVersion":"346","creationTimestamp":"2015-04-07T04:12:17Z","labels":{"template":"application-template-stibuild"}},"triggers":[{"type":"ImageChange","imageChangeParams":{"automatic":true,"containerNames":["ruby-helloworld"],"from":{"kind":"ImageStreamTag","name":"origin-ruby-sample:latest"},"tag":"latest","lastTriggeredImage":"172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58"}}],"template":{"strategy":{"type":"Recreate"},"controllerTemplate":{"replicas":1,"replicaSelector":{"name":"frontend"},"podTemplate":{"desiredState":{"manifest":{"version":"v1beta2","id":"","volumes":null,"containers":[{"name":"ruby-helloworld","image":"172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58","ports":[{"containerPort":8080,"protocol":"TCP"}],"env":[{"name":"ADMIN_USERNAME","key":"ADMIN_USERNAME","value":"adminNPX"},{"name":"ADMIN_PASSWORD","key":"ADMIN_PASSWORD","value":"7q1IdEao"},{"name":"MYSQL_USER","key":"MYSQL_USER","value":"user1CY"},{"name":"MYSQL_PASSWORD","key":"MYSQL_PASSWORD","value":"FfyXmsGG"},{"name":"MYSQL_DATABASE","key":"MYSQL_DATABASE","value":"root"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"PullIfNotPresent","capabilities":{}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"}},"labels":{"name":"frontend","template":"application-template-stibuild"}}}},"latestVersion":1,"details":{"causes":[{"type":"ImageChange","imageTrigger":{"repositoryName":"172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58","tag":"latest"}}]}}' - openshift.io/deployment.status-reason: unable to contact server - pod: deploy-frontend-17mza9 - creationTimestamp: 2015-04-07T04:12:53Z - labels: - template: application-template-stibuild - name: frontend-2 - namespace: example - spec: - replicas: 1 - selector: - deployment: frontend-2 - deploymentconfig: frontend - name: frontend - template: - metadata: - annotations: - openshift.io/deployment.name: frontend-2 - openshift.io/deployment-config.name: frontend - openshift.io/deployment-config.latest-version: "2" - creationTimestamp: null - labels: - deployment: frontend-2 - deploymentconfig: frontend - name: frontend - template: application-template-stibuild - spec: - containers: - - capabilities: {} - env: - - name: ADMIN_USERNAME - value: adminNPX - - name: ADMIN_PASSWORD - value: 7q1IdEao - - name: MYSQL_USER - value: user1CY - - name: MYSQL_PASSWORD - value: FfyXmsGG - - name: MYSQL_DATABASE - value: root - image: 172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58 - imagePullPolicy: IfNotPresent - name: ruby-helloworld - ports: - - containerPort: 8080 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - status: - replicas: 0 -- apiVersion: v1 - kind: ReplicationController - metadata: - annotations: - openshift.io/deployment-config.name: frontend - openshift.io/deployment.phase: Complete - openshift.io/deployment-config.latest-version: "1" - openshift.io/encoded-deployment-config: '{"kind":"DeploymentConfig","apiVersion":"v1beta1","metadata":{"name":"frontend","namespace":"test","selfLink":"/osapi/v1beta1/watch/deploymentConfigs/frontend","uid":"471f24e3-dcdc-11e4-968a-080027c5bfa9","resourceVersion":"346","creationTimestamp":"2015-04-07T04:12:17Z","labels":{"template":"application-template-stibuild"}},"triggers":[{"type":"ImageChange","imageChangeParams":{"automatic":true,"containerNames":["ruby-helloworld"],"from":{"kind":"ImageStreamTag","name":"origin-ruby-sample:latest"},"tag":"latest","lastTriggeredImage":"172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58"}}],"template":{"strategy":{"type":"Recreate"},"controllerTemplate":{"replicas":1,"replicaSelector":{"name":"frontend"},"podTemplate":{"desiredState":{"manifest":{"version":"v1beta2","id":"","volumes":null,"containers":[{"name":"ruby-helloworld","image":"172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58","ports":[{"containerPort":8080,"protocol":"TCP"}],"env":[{"name":"ADMIN_USERNAME","key":"ADMIN_USERNAME","value":"adminNPX"},{"name":"ADMIN_PASSWORD","key":"ADMIN_PASSWORD","value":"7q1IdEao"},{"name":"MYSQL_USER","key":"MYSQL_USER","value":"user1CY"},{"name":"MYSQL_PASSWORD","key":"MYSQL_PASSWORD","value":"FfyXmsGG"},{"name":"MYSQL_DATABASE","key":"MYSQL_DATABASE","value":"root"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"PullIfNotPresent","capabilities":{}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"}},"labels":{"name":"frontend","template":"application-template-stibuild"}}}},"latestVersion":1,"details":{"causes":[{"type":"ImageChange","imageTrigger":{"repositoryName":"172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58","tag":"latest"}}]}}' - pod: deploy-frontend-17mza9 - creationTimestamp: 2015-04-07T04:12:53Z - labels: - template: application-template-stibuild - name: frontend-1 - namespace: example - spec: - replicas: 1 - selector: - deployment: frontend-1 - deploymentconfig: frontend - name: frontend - template: - metadata: - annotations: - openshift.io/deployment.name: frontend-1 - openshift.io/deployment-config.name: frontend - openshift.io/deployment-config.latest-version: "1" - creationTimestamp: null - labels: - deployment: frontend-1 - deploymentconfig: frontend - name: frontend - template: application-template-stibuild - spec: - containers: - - capabilities: {} - env: - - name: ADMIN_USERNAME - value: adminNPX - - name: ADMIN_PASSWORD - value: 7q1IdEao - - name: MYSQL_USER - value: user1CY - - name: MYSQL_PASSWORD - value: FfyXmsGG - - name: MYSQL_DATABASE - value: root - image: 172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58 - imagePullPolicy: IfNotPresent - name: ruby-helloworld - ports: - - containerPort: 8080 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - status: - replicas: 1 -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: 2015-04-07T04:12:17Z - labels: - template: application-template-stibuild - name: frontend - namespace: example - spec: - replicas: 1 - selector: - name: frontend - strategy: - resources: {} - type: Recreate - template: - metadata: - creationTimestamp: null - labels: - name: frontend - template: application-template-stibuild - spec: - containers: - - capabilities: {} - env: - - name: ADMIN_USERNAME - value: adminNPX - - name: ADMIN_PASSWORD - value: 7q1IdEao - - name: MYSQL_USER - value: user1CY - - name: MYSQL_PASSWORD - value: FfyXmsGG - - name: MYSQL_DATABASE - value: root - image: 172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58 - imagePullPolicy: IfNotPresent - name: ruby-helloworld - ports: - - containerPort: 8080 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - triggers: - - imageChangeParams: - automatic: true - containerNames: - - ruby-helloworld - from: - kind: ImageStreamTag - name: origin-ruby-sample:latest - lastTriggeredImage: 172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58 - type: ImageChange - status: - details: - causes: - - imageTrigger: - from: - kind: DockerImage - name: 172.30.17.139:5000/test/origin-ruby-sample:latest - type: ImageChange - latestVersion: 3 -- apiVersion: v1 - kind: Service - metadata: - creationTimestamp: 2015-04-07T04:12:17Z - labels: - template: application-template-stibuild - name: database - namespace: example - spec: - ports: - - nodePort: 0 - port: 5434 - protocol: TCP - targetPort: 3306 - selector: - name: database - sessionAffinity: None - type: ClusterIP - status: - loadBalancer: {} -- apiVersion: v1 - kind: Service - metadata: - creationTimestamp: 2015-04-07T04:12:17Z - labels: - template: application-template-stibuild - name: database-external - namespace: example - spec: - ports: - - nodePort: 31000 - port: 5434 - protocol: TCP - targetPort: 3306 - selector: - name: database - sessionAffinity: None - type: NodePort - status: - loadBalancer: {} -- apiVersion: v1 - kind: Service - metadata: - creationTimestamp: 2015-04-07T04:12:17Z - labels: - template: application-template-stibuild - name: frontend - namespace: example - spec: - ports: - - nodePort: 0 - port: 5432 - protocol: TCP - targetPort: 8080 - selector: - name: frontend - sessionAffinity: None - type: ClusterIP - status: - loadBalancer: {} -- apiVersion: v1 - kind: Route - metadata: - annotations: - openshift.io/host.generated: "true" - creationTimestamp: 2015-04-07T04:12:17Z - labels: - template: application-template-stibuild - name: frontend - namespace: example - resourceVersion: "393" - spec: - host: frontend-example.router.default.svc.cluster.local - port: - targetPort: 8080 - to: - kind: Service - name: frontend - status: - ingress: - - routerName: default - host: frontend-example.router.default.svc.cluster.local - - routerName: other - host: www.test.com - conditions: - - type: Admitted - status: "False" - reason: HostAlreadyClaimed -- apiVersion: v1 - kind: Route - metadata: - annotations: - openshift.io/host.generated: "true" - creationTimestamp: 2015-04-07T04:12:17Z - labels: - template: application-template-stibuild - name: other - namespace: example - resourceVersion: "393" - spec: - host: www.test.com - port: - targetPort: 8080 - to: - kind: Service - name: frontend - tls: - insecureEdgeTerminationPolicy: Redirect - type: Edge - status: - ingress: - - routerName: other - host: www.test.com - conditions: - - type: Admitted - status: "True" -kind: List -metadata: - resourceVersion: "592" diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-no-build.yaml b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-no-build.yaml deleted file mode 100644 index 4c2c6d7fc6f4..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-no-build.yaml +++ /dev/null @@ -1,106 +0,0 @@ -apiVersion: v1 -items: -- apiVersion: v1 - kind: BuildConfig - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-example-2 - spec: - output: - to: - kind: ImageStreamTag - name: sinatra-example-2:latest - resources: {} - source: - git: - uri: git://github.com/mfojtik/sinatra-example-2 - type: Git - strategy: - sourceStrategy: - from: - kind: DockerImage - name: centos/ruby-25-centos7 - type: Source - triggers: - - github: - secret: u5gRhTXiOJpOHxKSI1M6 - type: github - - generic: - secret: IDO5sRS52tsUq5hczU6o - type: generic - status: - lastVersion: 0 -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-example-2 - spec: - replicas: 1 - selector: - deploymentconfig: sinatra-example-2 - strategy: - resources: {} - type: Recreate - template: - metadata: - creationTimestamp: null - labels: - deploymentconfig: sinatra-example-2 - spec: - containers: - - capabilities: {} - image: library/sinatra-example-2:latest - imagePullPolicy: Always - name: sinatra-example-2 - ports: - - containerPort: 8080 - name: s-tcp-8080 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - sinatra-example-2 - from: - kind: ImageStreamTag - name: sinatra-example-2:latest - lastTriggeredImage: "" - type: ImageChange - status: {} -- apiVersion: v1 - kind: ImageStream - metadata: - creationTimestamp: 2015-04-06T21:18:56Z - name: sinatra-example-2 - spec: {} - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: Service - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-example-2 - spec: - ports: - - nodePort: 0 - port: 8080 - protocol: TCP - targetPort: 8080 - selector: - deploymentconfig: sinatra-example-2 - sessionAffinity: None - type: ClusterIP - status: - loadBalancer: {} -kind: List -metadata: - resourceVersion: "116" diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-one-build.yaml b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-one-build.yaml deleted file mode 100644 index e0571b61b229..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-one-build.yaml +++ /dev/null @@ -1,136 +0,0 @@ -apiVersion: v1 -items: -- apiVersion: v1 - kind: BuildConfig - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-example-1 - namespace: example - spec: - output: - to: - kind: ImageStreamTag - name: sinatra-example-1:latest - resources: {} - source: - git: - uri: git://github.com/mfojtik/sinatra-example-1 - type: Git - strategy: - sourceStrategy: - from: - kind: DockerImage - name: centos/ruby-25-centos7 - type: Source - triggers: - - github: - secret: u5gRhTXiOJpOHxKSI1M6 - type: github - - generic: - secret: IDO5sRS52tsUq5hczU6o - type: generic - status: - lastVersion: 1 -- apiVersion: v1 - kind: ImageStream - metadata: - creationTimestamp: 2015-04-06T21:18:56Z - name: sinatra-example-1 - namespace: example - spec: {} - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: Build - metadata: - creationTimestamp: 2015-04-06T21:18:56Z - labels: - buildconfig: sinatra-example-1 - name: sinatra-example-1-1 - namespace: example - spec: - output: - to: - kind: ImageStreamTag - name: sinatra-example-1:latest - resources: {} - source: - git: - uri: git://github.com/mfojtik/sinatra-example-1 - type: Git - strategy: - sourceStrategy: - from: - kind: DockerImage - name: centos/ruby-25-centos7 - type: Source - status: - phase: Running - startTimestamp: 2015-04-06T21:19:03Z -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-example-1 - namespace: example - spec: - replicas: 1 - selector: - deploymentconfig: sinatra-example-1 - strategy: - resources: {} - type: Recreate - template: - metadata: - creationTimestamp: null - labels: - deploymentconfig: sinatra-example-1 - spec: - containers: - - capabilities: {} - image: library/sinatra-example-1:latest - imagePullPolicy: Always - name: sinatra-example-1 - ports: - - containerPort: 8080 - name: s-tcp-8080 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - sinatra-example-1 - from: - kind: ImageStreamTag - name: sinatra-example-1:latest - lastTriggeredImage: "" - type: ImageChange - status: {} -- apiVersion: v1 - kind: Service - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-example-1 - namespace: example - spec: - ports: - - nodePort: 0 - port: 8080 - protocol: TCP - targetPort: 8080 - selector: - deploymentconfig: sinatra-example-1 - sessionAffinity: None - type: ClusterIP - status: - loadBalancer: {} -kind: List -metadata: {} diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-two-deployment-configs.yaml b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-two-deployment-configs.yaml deleted file mode 100644 index a5c373c3ca9f..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/new-project-two-deployment-configs.yaml +++ /dev/null @@ -1,186 +0,0 @@ -apiVersion: v1 -items: -- apiVersion: v1 - kind: BuildConfig - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-app-example - spec: - output: - to: - kind: ImageStreamTag - name: sinatra-app-example:latest - resources: {} - source: - git: - uri: git://github.com/mfojtik/sinatra-app-example - type: Git - strategy: - sourceStrategy: - from: - kind: DockerImage - name: centos/ruby-25-centos7 - type: Source - triggers: - - github: - secret: u5gRhTXiOJpOHxKSI1M6 - type: github - - generic: - secret: IDO5sRS52tsUq5hczU6o - type: generic - status: - lastVersion: 1 -- apiVersion: v1 - kind: ImageStream - metadata: - creationTimestamp: 2015-04-06T21:18:56Z - name: sinatra-app-example - spec: {} - status: - dockerImageRepository: "" -- apiVersion: v1 - kind: Build - metadata: - creationTimestamp: 2015-04-06T21:18:56Z - labels: - buildconfig: sinatra-app-example - name: sinatra-app-example-1 - spec: - output: - to: - kind: ImageStreamTag - name: sinatra-app-example:latest - resources: {} - revision: - git: - author: - email: someguy@outhere.com - name: Roy Programmer - commit: 7a4f354721b0c9717e46f2e132b269b495d43e2b - committer: {} - message: Prepare v1 Template types - type: git - source: - git: - uri: git://github.com/mfojtik/sinatra-app-example - type: Git - strategy: - sourceStrategy: - from: - kind: DockerImage - name: centos/ruby-25-centos7 - type: Source - status: - phase: Running - startTimestamp: 2015-04-06T21:19:03Z -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-app-example-a - spec: - replicas: 1 - selector: - deploymentconfig: sinatra-app-example - strategy: - resources: {} - type: Recreate - template: - metadata: - creationTimestamp: null - labels: - deploymentconfig: sinatra-app-example - spec: - containers: - - capabilities: {} - image: library/sinatra-app-example:latest - imagePullPolicy: Always - name: sinatra-app-example - ports: - - containerPort: 8080 - name: s-tcp-8080 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - sinatra-app-example - from: - kind: ImageStreamTag - name: sinatra-app-example:latest - lastTriggeredImage: "" - type: ImageChange - status: {} -- apiVersion: v1 - kind: DeploymentConfig - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-app-example-b - spec: - replicas: 1 - selector: - deploymentconfig: sinatra-app-example - strategy: - resources: {} - type: Recreate - template: - metadata: - creationTimestamp: null - labels: - deploymentconfig: sinatra-app-example - spec: - containers: - - capabilities: {} - image: library/sinatra-app-example:latest - imagePullPolicy: Always - name: sinatra-app-example - ports: - - containerPort: 8080 - name: s-tcp-8080 - protocol: TCP - resources: {} - securityContext: - capabilities: {} - privileged: false - terminationMessagePath: /dev/termination-log - dnsPolicy: ClusterFirst - restartPolicy: Always - triggers: - - type: ConfigChange - - imageChangeParams: - automatic: true - containerNames: - - sinatra-app-example - from: - kind: ImageStreamTag - name: sinatra-app-example:latest - lastTriggeredImage: "" - type: ImageChange - status: {} -- apiVersion: v1 - kind: Service - metadata: - creationTimestamp: 2015-04-06T21:02:00Z - name: sinatra-app-example - spec: - ports: - - nodePort: 0 - port: 8080 - protocol: TCP - targetPort: 8080 - selector: - deploymentconfig: sinatra-app-example - sessionAffinity: None - type: ClusterIP - status: - loadBalancer: {} -kind: List -metadata: {} diff --git a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/petset.yaml b/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/petset.yaml deleted file mode 100644 index e3c31116c197..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/app-scenarios/petset.yaml +++ /dev/null @@ -1,495 +0,0 @@ -apiVersion: v1 -items: -- apiVersion: v1 - kind: Service - metadata: - annotations: - service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" - creationTimestamp: 2016-07-21T15:53:09Z - labels: - app: mysql - name: galera - namespace: default - resourceVersion: "343" - selfLink: /api/v1/namespaces/default/services/galera - uid: 38fb3915-4f5b-11e6-b8a1-080027242396 - spec: - clusterIP: None - ports: - - name: mysql - port: 3306 - protocol: TCP - targetPort: 3306 - selector: - app: mysql - sessionAffinity: None - type: ClusterIP - status: - loadBalancer: {} -- apiVersion: v1 - kind: Pod - metadata: - annotations: - kubernetes.io/created-by: | - {"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"StatefulSet","namespace":"default","name":"mysql","uid":"3900c985-4f5b-11e6-b8a1-080027242396","apiVersion":"apps","resourceVersion":"6784"}} - openshift.io/scc: anyuid - pod.alpha.kubernetes.io/init-container-statuses: '[{"name":"install","state":{"terminated":{"exitCode":0,"reason":"Completed","startedAt":"2016-07-27T02:41:12Z","finishedAt":"2016-07-27T02:41:12Z","containerID":"docker://5c727d8732899605fcfe3eecbeeb02576f18f5b989496073340427a8d2134622"}},"lastState":{},"ready":true,"restartCount":0,"image":"gcr.io/google_containers/galera-install:0.1","imageID":"docker://sha256:56ef857005d0ce479f2db0e4ee0ece05e0766ebfa7e79e27e1513915262a18ec","containerID":"docker://5c727d8732899605fcfe3eecbeeb02576f18f5b989496073340427a8d2134622"},{"name":"bootstrap","state":{"terminated":{"exitCode":0,"reason":"Completed","startedAt":"2016-07-27T02:41:14Z","finishedAt":"2016-07-27T02:41:15Z","containerID":"docker://ab4ca0b3b6ec4860cd55c615534e1e2b11f4c3a33746783aab145919feb2446e"}},"lastState":{},"ready":true,"restartCount":0,"image":"debian:jessie","imageID":"docker://sha256:1b088884749bd93867ddb48ff404d4bbff09a17af8d95bc863efa5d133f87b78","containerID":"docker://ab4ca0b3b6ec4860cd55c615534e1e2b11f4c3a33746783aab145919feb2446e"}]' - pod.alpha.kubernetes.io/init-containers: '[{"name":"install","image":"gcr.io/google_containers/galera-install:0.1","args":["--work-dir=/work-dir"],"resources":{},"volumeMounts":[{"name":"workdir","mountPath":"/work-dir"},{"name":"config","mountPath":"/etc/mysql"},{"name":"default-token-au2xq","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"Always"},{"name":"bootstrap","image":"debian:jessie","command":["/work-dir/peer-finder"],"args":["-on-start=\"/work-dir/on-start.sh\"","-service=galera"],"env":[{"name":"POD_NAMESPACE","valueFrom":{"fieldRef":{"apiVersion":"v1","fieldPath":"metadata.namespace"}}}],"resources":{},"volumeMounts":[{"name":"workdir","mountPath":"/work-dir"},{"name":"config","mountPath":"/etc/mysql"},{"name":"default-token-au2xq","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}]' - pod.alpha.kubernetes.io/initialized: "true" - pod.beta.kubernetes.io/hostname: mysql-0 - pod.beta.kubernetes.io/subdomain: galera - creationTimestamp: 2016-07-27T02:41:09Z - generateName: mysql- - labels: - app: mysql - name: mysql-0 - namespace: default - resourceVersion: "7191" - selfLink: /api/v1/namespaces/default/pods/mysql-0 - uid: 92e49e79-53a3-11e6-b45a-080027242396 - spec: - containers: - - args: - - --defaults-file=/etc/mysql/my-galera.cnf - - --user=root - image: erkules/galera:basic - imagePullPolicy: IfNotPresent - name: mysql - ports: - - containerPort: 3306 - name: mysql - protocol: TCP - - containerPort: 4444 - name: sst - protocol: TCP - - containerPort: 4567 - name: replication - protocol: TCP - - containerPort: 4568 - name: ist - protocol: TCP - readinessProbe: - exec: - command: - - sh - - -c - - mysql -u root -e 'show databases;' - failureThreshold: 3 - initialDelaySeconds: 15 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 5 - resources: {} - securityContext: - capabilities: - drop: - - MKNOD - - SYS_CHROOT - privileged: false - seLinuxOptions: - level: s0:c5,c0 - terminationMessagePath: /dev/termination-log - volumeMounts: - - mountPath: /var/lib/ - name: datadir - - mountPath: /etc/mysql - name: config - - mountPath: /var/run/secrets/kubernetes.io/serviceaccount - name: default-token-au2xq - readOnly: true - dnsPolicy: ClusterFirst - host: localhost.localdomain - imagePullSecrets: - - name: default-dockercfg-pzhsj - nodeName: localhost.localdomain - restartPolicy: Always - securityContext: - seLinuxOptions: - level: s0:c5,c0 - serviceAccount: default - serviceAccountName: default - terminationGracePeriodSeconds: 30 - volumes: - - name: datadir - persistentVolumeClaim: - claimName: datadir-mysql-0 - - emptyDir: {} - name: config - - emptyDir: {} - name: workdir - - name: default-token-au2xq - secret: - secretName: default-token-au2xq - status: - conditions: - - lastProbeTime: null - lastTransitionTime: 2016-07-27T02:41:15Z - status: "True" - type: Initialized - - lastProbeTime: null - lastTransitionTime: 2016-07-27T03:00:47Z - status: "True" - type: Ready - - lastProbeTime: null - lastTransitionTime: 2016-07-27T02:41:09Z - status: "True" - type: PodScheduled - containerStatuses: - - containerID: docker://f2406b0f697c525df44b64aec6b1f6024ab88d9df80256426247dc6e9a92cb30 - image: erkules/galera:basic - imageID: docker://sha256:b4780e247a38c12612f539ce1ac8e0988e1781d56fddf719c80fb8d4d7b8bbde - lastState: {} - name: mysql - ready: true - restartCount: 0 - state: - running: - startedAt: 2016-07-27T02:41:16Z - hostIP: 10.0.2.15 - phase: Running - podIP: 172.17.0.2 - startTime: 2016-07-27T02:41:09Z -- apiVersion: v1 - kind: Pod - metadata: - annotations: - kubernetes.io/created-by: | - {"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"StatefulSet","namespace":"default","name":"mysql","uid":"3900c985-4f5b-11e6-b8a1-080027242396","apiVersion":"apps","resourceVersion":"6790"}} - openshift.io/scc: anyuid - pod.alpha.kubernetes.io/init-container-statuses: '[{"name":"install","state":{"terminated":{"exitCode":0,"reason":"Completed","startedAt":"2016-07-27T02:41:42Z","finishedAt":"2016-07-27T02:41:42Z","containerID":"docker://2538c65f65557955c02745ef4021181cf322c8dc0db62144dd1e1f8ea9f7fa54"}},"lastState":{},"ready":true,"restartCount":0,"image":"gcr.io/google_containers/galera-install:0.1","imageID":"docker://sha256:56ef857005d0ce479f2db0e4ee0ece05e0766ebfa7e79e27e1513915262a18ec","containerID":"docker://2538c65f65557955c02745ef4021181cf322c8dc0db62144dd1e1f8ea9f7fa54"},{"name":"bootstrap","state":{"terminated":{"exitCode":0,"reason":"Completed","startedAt":"2016-07-27T02:41:44Z","finishedAt":"2016-07-27T02:41:45Z","containerID":"docker://4df7188d37033c182e675d45179941766bd1e6a013469038f43fa3fecc2cc06d"}},"lastState":{},"ready":true,"restartCount":0,"image":"debian:jessie","imageID":"docker://sha256:1b088884749bd93867ddb48ff404d4bbff09a17af8d95bc863efa5d133f87b78","containerID":"docker://4df7188d37033c182e675d45179941766bd1e6a013469038f43fa3fecc2cc06d"}]' - pod.alpha.kubernetes.io/init-containers: '[{"name":"install","image":"gcr.io/google_containers/galera-install:0.1","args":["--work-dir=/work-dir"],"resources":{},"volumeMounts":[{"name":"workdir","mountPath":"/work-dir"},{"name":"config","mountPath":"/etc/mysql"},{"name":"default-token-au2xq","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"Always"},{"name":"bootstrap","image":"debian:jessie","command":["/work-dir/peer-finder"],"args":["-on-start=\"/work-dir/on-start.sh\"","-service=galera"],"env":[{"name":"POD_NAMESPACE","valueFrom":{"fieldRef":{"apiVersion":"v1","fieldPath":"metadata.namespace"}}}],"resources":{},"volumeMounts":[{"name":"workdir","mountPath":"/work-dir"},{"name":"config","mountPath":"/etc/mysql"},{"name":"default-token-au2xq","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}]' - pod.alpha.kubernetes.io/initialized: "true" - pod.beta.kubernetes.io/hostname: mysql-1 - pod.beta.kubernetes.io/subdomain: galera - creationTimestamp: 2016-07-27T02:41:39Z - generateName: mysql- - labels: - app: mysql - name: mysql-1 - namespace: default - resourceVersion: "7195" - selfLink: /api/v1/namespaces/default/pods/mysql-1 - uid: a4da4725-53a3-11e6-b45a-080027242396 - spec: - containers: - - args: - - --defaults-file=/etc/mysql/my-galera.cnf - - --user=root - image: erkules/galera:basic - imagePullPolicy: IfNotPresent - name: mysql - ports: - - containerPort: 3306 - name: mysql - protocol: TCP - - containerPort: 4444 - name: sst - protocol: TCP - - containerPort: 4567 - name: replication - protocol: TCP - - containerPort: 4568 - name: ist - protocol: TCP - readinessProbe: - exec: - command: - - sh - - -c - - mysql -u root -e 'show databases;' - failureThreshold: 3 - initialDelaySeconds: 15 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 5 - resources: {} - securityContext: - capabilities: - drop: - - MKNOD - - SYS_CHROOT - privileged: false - seLinuxOptions: - level: s0:c5,c0 - terminationMessagePath: /dev/termination-log - volumeMounts: - - mountPath: /var/lib/ - name: datadir - - mountPath: /etc/mysql - name: config - - mountPath: /var/run/secrets/kubernetes.io/serviceaccount - name: default-token-au2xq - readOnly: true - dnsPolicy: ClusterFirst - host: localhost.localdomain - imagePullSecrets: - - name: default-dockercfg-pzhsj - nodeName: localhost.localdomain - restartPolicy: Always - securityContext: - seLinuxOptions: - level: s0:c5,c0 - serviceAccount: default - serviceAccountName: default - terminationGracePeriodSeconds: 30 - volumes: - - name: datadir - persistentVolumeClaim: - claimName: datadir-mysql-1 - - emptyDir: {} - name: config - - emptyDir: {} - name: workdir - - name: default-token-au2xq - secret: - secretName: default-token-au2xq - status: - conditions: - - lastProbeTime: null - lastTransitionTime: 2016-07-27T02:41:46Z - status: "True" - type: Initialized - - lastProbeTime: null - lastTransitionTime: 2016-07-27T03:00:58Z - status: "True" - type: Ready - - lastProbeTime: null - lastTransitionTime: 2016-07-27T02:41:39Z - status: "True" - type: PodScheduled - containerStatuses: - - containerID: docker://be1d5be42ab23d1db23f4552141e9068e2385ba19c3e84596e047eb6d2762d1c - image: erkules/galera:basic - imageID: docker://sha256:b4780e247a38c12612f539ce1ac8e0988e1781d56fddf719c80fb8d4d7b8bbde - lastState: - terminated: - containerID: docker://9a662fa5b74a962fa362c6a5d632fe3642b12fefde36c8158ab1a50d8fa4e33e - exitCode: 1 - finishedAt: 2016-07-27T02:51:40Z - reason: Error - startedAt: 2016-07-27T02:51:05Z - name: mysql - ready: true - restartCount: 7 - state: - running: - startedAt: 2016-07-27T03:00:39Z - hostIP: 10.0.2.15 - phase: Running - podIP: 172.17.0.3 - startTime: 2016-07-27T02:41:39Z -- apiVersion: v1 - kind: Pod - metadata: - annotations: - kubernetes.io/created-by: | - {"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"StatefulSet","namespace":"default","name":"mysql","uid":"3900c985-4f5b-11e6-b8a1-080027242396","apiVersion":"apps","resourceVersion":"6790"}} - openshift.io/scc: anyuid - pod.alpha.kubernetes.io/init-container-statuses: '[{"name":"install","state":{"terminated":{"exitCode":0,"reason":"Completed","startedAt":"2016-07-27T03:01:01Z","finishedAt":"2016-07-27T03:01:01Z","containerID":"docker://af008b4ce59d36695fbabf40ae2f7431b51441eb2e9c6962378937c06ac69a35"}},"lastState":{},"ready":true,"restartCount":0,"image":"gcr.io/google_containers/galera-install:0.1","imageID":"docker://sha256:56ef857005d0ce479f2db0e4ee0ece05e0766ebfa7e79e27e1513915262a18ec","containerID":"docker://af008b4ce59d36695fbabf40ae2f7431b51441eb2e9c6962378937c06ac69a35"},{"name":"bootstrap","state":{"terminated":{"exitCode":0,"reason":"Completed","startedAt":"2016-07-27T03:01:02Z","finishedAt":"2016-07-27T03:01:03Z","containerID":"docker://ee97005854130335b54a65429865956260b7729e51e6363ab05e63d5c7c9ee48"}},"lastState":{},"ready":true,"restartCount":0,"image":"debian:jessie","imageID":"docker://sha256:1b088884749bd93867ddb48ff404d4bbff09a17af8d95bc863efa5d133f87b78","containerID":"docker://ee97005854130335b54a65429865956260b7729e51e6363ab05e63d5c7c9ee48"}]' - pod.alpha.kubernetes.io/init-containers: '[{"name":"install","image":"gcr.io/google_containers/galera-install:0.1","args":["--work-dir=/work-dir"],"resources":{},"volumeMounts":[{"name":"workdir","mountPath":"/work-dir"},{"name":"config","mountPath":"/etc/mysql"},{"name":"default-token-au2xq","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"Always"},{"name":"bootstrap","image":"debian:jessie","command":["/work-dir/peer-finder"],"args":["-on-start=\"/work-dir/on-start.sh\"","-service=galera"],"env":[{"name":"POD_NAMESPACE","valueFrom":{"fieldRef":{"apiVersion":"v1","fieldPath":"metadata.namespace"}}}],"resources":{},"volumeMounts":[{"name":"workdir","mountPath":"/work-dir"},{"name":"config","mountPath":"/etc/mysql"},{"name":"default-token-au2xq","readOnly":true,"mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"}],"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}]' - pod.alpha.kubernetes.io/initialized: "true" - pod.beta.kubernetes.io/hostname: mysql-2 - pod.beta.kubernetes.io/subdomain: galera - creationTimestamp: 2016-07-27T03:00:58Z - generateName: mysql- - labels: - app: mysql - name: mysql-2 - namespace: default - resourceVersion: "7226" - selfLink: /api/v1/namespaces/default/pods/mysql-2 - uid: 57e618f1-53a6-11e6-b215-080027242396 - spec: - containers: - - args: - - --defaults-file=/etc/mysql/my-galera.cnf - - --user=root - image: erkules/galera:basic - imagePullPolicy: IfNotPresent - name: mysql - ports: - - containerPort: 3306 - name: mysql - protocol: TCP - - containerPort: 4444 - name: sst - protocol: TCP - - containerPort: 4567 - name: replication - protocol: TCP - - containerPort: 4568 - name: ist - protocol: TCP - readinessProbe: - exec: - command: - - sh - - -c - - mysql -u root -e 'show databases;' - failureThreshold: 3 - initialDelaySeconds: 15 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 5 - resources: {} - securityContext: - capabilities: - drop: - - MKNOD - - SYS_CHROOT - privileged: false - seLinuxOptions: - level: s0:c5,c0 - terminationMessagePath: /dev/termination-log - volumeMounts: - - mountPath: /var/lib/ - name: datadir - - mountPath: /etc/mysql - name: config - - mountPath: /var/run/secrets/kubernetes.io/serviceaccount - name: default-token-au2xq - readOnly: true - dnsPolicy: ClusterFirst - host: localhost.localdomain - imagePullSecrets: - - name: default-dockercfg-pzhsj - nodeName: localhost.localdomain - restartPolicy: Always - securityContext: - seLinuxOptions: - level: s0:c5,c0 - serviceAccount: default - serviceAccountName: default - terminationGracePeriodSeconds: 30 - volumes: - - name: datadir - persistentVolumeClaim: - claimName: datadir-mysql-2 - - emptyDir: {} - name: config - - emptyDir: {} - name: workdir - - name: default-token-au2xq - secret: - secretName: default-token-au2xq - status: - conditions: - - lastProbeTime: null - lastTransitionTime: 2016-07-27T03:01:03Z - status: "True" - type: Initialized - - lastProbeTime: null - lastTransitionTime: 2016-07-27T03:01:28Z - status: "True" - type: Ready - - lastProbeTime: null - lastTransitionTime: 2016-07-27T03:00:58Z - status: "True" - type: PodScheduled - containerStatuses: - - containerID: docker://82b774855cdb5d12d98e7bc34f4f9d4e88e757e9cc2da1593e2e2f66e3241e5f - image: erkules/galera:basic - imageID: docker://sha256:b4780e247a38c12612f539ce1ac8e0988e1781d56fddf719c80fb8d4d7b8bbde - lastState: {} - name: mysql - ready: true - restartCount: 0 - state: - running: - startedAt: 2016-07-27T03:01:04Z - hostIP: 10.0.2.15 - phase: Running - podIP: 172.17.0.4 - startTime: 2016-07-27T03:00:58Z -- apiVersion: apps/v1 - kind: StatefulSet - metadata: - creationTimestamp: 2016-07-21T15:53:09Z - generation: 3 - labels: - app: mysql - name: mysql - namespace: default - resourceVersion: "6790" - selfLink: /apis/apps/v1/namespaces/default/statefulsets/mysql - uid: 3900c985-4f5b-11e6-b8a1-080027242396 - spec: - replicas: 3 - selector: - matchLabels: - app: mysql - serviceName: galera - template: - metadata: - annotations: - pod.alpha.kubernetes.io/init-containers: '[{"name":"install","image":"gcr.io/google_containers/galera-install:0.1","args":["--work-dir=/work-dir"],"resources":{},"volumeMounts":[{"name":"workdir","mountPath":"/work-dir"},{"name":"config","mountPath":"/etc/mysql"}],"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"Always"},{"name":"bootstrap","image":"debian:jessie","command":["/work-dir/peer-finder"],"args":["-on-start=\"/work-dir/on-start.sh\"","-service=galera"],"env":[{"name":"POD_NAMESPACE","valueFrom":{"fieldRef":{"apiVersion":"v1","fieldPath":"metadata.namespace"}}}],"resources":{},"volumeMounts":[{"name":"workdir","mountPath":"/work-dir"},{"name":"config","mountPath":"/etc/mysql"}],"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}]' - pod.alpha.kubernetes.io/initialized: "true" - creationTimestamp: null - labels: - app: mysql - spec: - containers: - - args: - - --defaults-file=/etc/mysql/my-galera.cnf - - --user=root - image: erkules/galera:basic - imagePullPolicy: IfNotPresent - name: mysql - ports: - - containerPort: 3306 - name: mysql - protocol: TCP - - containerPort: 4444 - name: sst - protocol: TCP - - containerPort: 4567 - name: replication - protocol: TCP - - containerPort: 4568 - name: ist - protocol: TCP - readinessProbe: - exec: - command: - - sh - - -c - - mysql -u root -e 'show databases;' - failureThreshold: 3 - initialDelaySeconds: 15 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 5 - resources: {} - terminationMessagePath: /dev/termination-log - volumeMounts: - - mountPath: /var/lib/ - name: datadir - - mountPath: /etc/mysql - name: config - dnsPolicy: ClusterFirst - restartPolicy: Always - securityContext: {} - terminationGracePeriodSeconds: 30 - volumes: - - emptyDir: {} - name: config - - emptyDir: {} - name: workdir - volumeClaimTemplates: - - metadata: - annotations: - volume.alpha.kubernetes.io/storage-class: anything - creationTimestamp: null - name: datadir - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi - status: - phase: Pending - status: - replicas: 3 -kind: List -metadata: {} diff --git a/test/extended/testdata/cmd/test/cmd/testdata/application-template-custombuild.json b/test/extended/testdata/cmd/test/cmd/testdata/application-template-custombuild.json index 277a3cf07db4..0dd74be64b1a 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/application-template-custombuild.json +++ b/test/extended/testdata/cmd/test/cmd/testdata/application-template-custombuild.json @@ -401,7 +401,7 @@ "containers": [ { "name": "ruby-helloworld-database", - "image": "centos/mysql-57-centos7:latest", + "image": "image-registry.openshift-image-registry.svc:5000/openshift/mysql:5.7", "ports": [ { "containerPort": 3306, diff --git a/test/extended/testdata/cmd/test/cmd/testdata/application-template-dockerbuild.json b/test/extended/testdata/cmd/test/cmd/testdata/application-template-dockerbuild.json index 1aa52b11e3ca..7deb14d2afa0 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/application-template-dockerbuild.json +++ b/test/extended/testdata/cmd/test/cmd/testdata/application-template-dockerbuild.json @@ -355,7 +355,7 @@ "containers": [ { "name": "ruby-helloworld-database", - "image": "centos/mysql-57-centos7:latest", + "image": "image-registry.openshift-image-registry.svc:5000/openshift/mysql:5.7", "ports": [ { "containerPort": 3306, diff --git a/test/extended/testdata/cmd/test/cmd/testdata/application-template-stibuild.json b/test/extended/testdata/cmd/test/cmd/testdata/application-template-stibuild.json index 76c98b37d051..f4c1fec78e9e 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/application-template-stibuild.json +++ b/test/extended/testdata/cmd/test/cmd/testdata/application-template-stibuild.json @@ -400,7 +400,7 @@ "containers": [ { "name": "ruby-helloworld-database", - "image": "centos/mysql-57-centos7:latest", + "image": "image-registry.openshift-image-registry.svc:5000/openshift/mysql:5.7", "ports": [ { "containerPort": 3306, diff --git a/test/extended/testdata/cmd/test/cmd/testdata/hello-openshift/hello-pod.json b/test/extended/testdata/cmd/test/cmd/testdata/hello-openshift/hello-pod.json index ad40533746c7..98c9027fefec 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/hello-openshift/hello-pod.json +++ b/test/extended/testdata/cmd/test/cmd/testdata/hello-openshift/hello-pod.json @@ -12,7 +12,8 @@ "containers": [ { "name": "hello-openshift", - "image": "openshift/hello-openshift", + "image": "k8s.gcr.io/e2e-test-images/agnhost:2.20", + "args": ["netexec"], "ports": [ { "containerPort": 8080, diff --git a/test/extended/testdata/cmd/test/cmd/testdata/idling-dc.yaml b/test/extended/testdata/cmd/test/cmd/testdata/idling-dc.yaml index 1143cef9b00f..2acaa47622fc 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/idling-dc.yaml +++ b/test/extended/testdata/cmd/test/cmd/testdata/idling-dc.yaml @@ -16,7 +16,7 @@ spec: deploymentconfig: idling-echo spec: containers: - - image: openshift/origin-base + - image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest name: idling-tcp-echo command: - /usr/bin/socat @@ -25,7 +25,7 @@ spec: ports: - containerPort: 8675 protocol: TCP - - image: openshift/origin-base + - image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest name: idling-udp-echo command: - /usr/bin/socat diff --git a/test/extended/testdata/cmd/test/cmd/testdata/image-streams/image-streams-centos7.json b/test/extended/testdata/cmd/test/cmd/testdata/image-streams/image-streams-centos7.json index cf2018d940c4..d9513f905b8d 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/image-streams/image-streams-centos7.json +++ b/test/extended/testdata/cmd/test/cmd/testdata/image-streams/image-streams-centos7.json @@ -15,56 +15,59 @@ "tags": [ { "annotations": { - "description": "Build and run .NET Core applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.1/build/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of .NET Core available on OpenShift, including major versions updates.", + "description": "Build and run .NET Core applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of .NET Core available on OpenShift, including major versions updates.", "iconClass": "icon-dotnet", "openshift.io/display-name": ".NET Core (Latest)", "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.1", + "sampleRef": "dotnetcore-3.1", "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", "supports": "dotnet", "tags": "builder,.net,dotnet,dotnetcore" }, "from": { "kind": "ImageStreamTag", - "name": "2.1" + "name": "3.1" }, - "name": "latest" + "name": "latest", + "referencePolicy": { + "type": "Local" + } }, { "annotations": { - "description": "Build and run .NET Core 2.1 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.0/build/README.md.", + "description": "Build and run .NET Core 2.2 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/blob/master/2.2/build/README.md.", "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 2.1", + "openshift.io/display-name": ".NET Core 2.2", "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.1", + "sampleRef": "dotnetcore-2.2", "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:2.1,dotnet", + "supports": "dotnet:2.2,dotnet", "tags": "builder,.net,dotnet,dotnetcore,rh-dotnet21", - "version": "2.1" + "version": "2.2" }, "from": { "kind": "DockerImage", - "name": "registry.centos.org/dotnet/dotnet-21-centos7:latest" + "name": "registry.centos.org/dotnet/dotnet-22-centos7:latest" }, - "name": "2.1" + "name": "2.2" }, { "annotations": { - "description": "RETIRED: Build and run .NET Core 2.0 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/tree/master/2.0/build/README.md.", + "description": "Build and run .NET Core 3.1 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/redhat-developer/s2i-dotnetcore/blob/master/3.1/build/README.md.", "iconClass": "icon-dotnet", - "openshift.io/display-name": ".NET Core 2.0", + "openshift.io/display-name": ".NET Core 3.1", "sampleContextDir": "app", - "sampleRef": "dotnetcore-2.0", + "sampleRef": "dotnetcore-3.1", "sampleRepo": "https://github.com/redhat-developer/s2i-dotnetcore-ex.git", - "supports": "dotnet:2.0,dotnet", - "tags": "hidden,builder,.net,dotnet,dotnetcore,rh-dotnet20", - "version": "2.0" + "supports": "dotnet:3.1,dotnet", + "tags": "builder,.net,dotnet,dotnetcore,rh-dotnet21", + "version": "3.1" }, "from": { "kind": "DockerImage", - "name": "registry.centos.org/dotnet/dotnet-20-centos7:latest" + "name": "registry.centos.org/dotnet/dotnet-31-centos7:latest" }, - "name": "2.0" + "name": "3.1" } ] } @@ -82,7 +85,7 @@ "tags": [ { "annotations": { - "description": "Build and serve static content via Apache HTTP Server (httpd) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/httpd-container/blob/master/2.4/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Httpd available on OpenShift, including major versions updates.", + "description": "Build and serve static content via Apache HTTP Server (httpd) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/httpd-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Httpd available on OpenShift, including major versions updates.", "iconClass": "icon-apache", "openshift.io/display-name": "Apache HTTP Server (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -112,7 +115,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/httpd-24-centos7:latest" + "name": "registry.centos.org/centos/httpd-24-centos7:latest" }, "name": "2.4", "referencePolicy": { @@ -184,7 +187,7 @@ "tags": [ { "annotations": { - "description": "Provides a MariaDB database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.2/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MariaDB available on OpenShift, including major versions updates.", + "description": "Provides a MariaDB database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/blob/master/10.2/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MariaDB available on OpenShift, including major versions updates.", "iconClass": "icon-mariadb", "openshift.io/display-name": "MariaDB (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -201,7 +204,7 @@ }, { "annotations": { - "description": "Provides a MariaDB 10.1 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.1/README.md.", + "description": "Provides a MariaDB 10.1 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/blob/master/10.1/README.md.", "iconClass": "icon-mariadb", "openshift.io/display-name": "MariaDB 10.1", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -210,7 +213,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mariadb-101-centos7:latest" + "name": "registry.centos.org/centos/mariadb-101-centos7:latest" }, "name": "10.1", "referencePolicy": { @@ -219,7 +222,7 @@ }, { "annotations": { - "description": "Provides a MariaDB 10.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/tree/master/10.2/README.md.", + "description": "Provides a MariaDB 10.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mariadb-container/blob/master/10.2/README.md.", "iconClass": "icon-mariadb", "openshift.io/display-name": "MariaDB 10.2", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -228,7 +231,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mariadb-102-centos7:latest" + "name": "registry.centos.org/centos/mariadb-102-centos7:latest" }, "name": "10.2", "referencePolicy": { @@ -251,7 +254,7 @@ "tags": [ { "annotations": { - "description": "Provides a MongoDB database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.4/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MongoDB available on OpenShift, including major versions updates.", + "description": "Provides a MongoDB database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of MongoDB available on OpenShift, including major versions updates.", "iconClass": "icon-mongodb", "openshift.io/display-name": "MongoDB (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -259,7 +262,7 @@ }, "from": { "kind": "ImageStreamTag", - "name": "3.6" + "name": "3.4" }, "name": "latest", "referencePolicy": { @@ -277,7 +280,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mongodb-26-centos7:latest" + "name": "registry.centos.org/centos/mongodb-26-centos7:latest" }, "name": "2.7", "referencePolicy": { @@ -286,7 +289,7 @@ }, { "annotations": { - "description": "Provides a MongoDB 3.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.2/README.md.", + "description": "Provides a MongoDB 3.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/blob/master/3.2/README.md.", "iconClass": "icon-mongodb", "openshift.io/display-name": "MongoDB 3.2", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -295,7 +298,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mongodb-32-centos7:latest" + "name": "registry.centos.org/centos/mongodb-32-centos7:latest" }, "name": "3.2", "referencePolicy": { @@ -304,7 +307,7 @@ }, { "annotations": { - "description": "Provides a MongoDB 3.4 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.4/README.md.", + "description": "Provides a MongoDB 3.4 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/blob/master/3.4/README.md.", "iconClass": "icon-mongodb", "openshift.io/display-name": "MongoDB 3.4", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -313,30 +316,12 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mongodb-34-centos7:latest" + "name": "registry.centos.org/centos/mongodb-34-centos7:latest" }, "name": "3.4", "referencePolicy": { "type": "Local" } - }, - { - "annotations": { - "description": "Provides a MongoDB 3.6 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mongodb-container/tree/master/3.6/README.md.", - "iconClass": "icon-mongodb", - "openshift.io/display-name": "MongoDB 3.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,mongodb", - "version": "3.6" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/mongodb-36-centos7:latest" - }, - "name": "3.6", - "referencePolicy": { - "type": "Local" - } } ] } @@ -369,24 +354,6 @@ "type": "Local" } }, - { - "annotations": { - "description": "Provides a MySQL 5.5 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/README.md.", - "iconClass": "icon-mysql-database", - "openshift.io/display-name": "MySQL 5.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,mysql", - "version": "5.5" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/mysql-55-centos7:latest" - }, - "name": "5.5", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Provides a MySQL 5.6 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/mysql-container/blob/master/README.md.", @@ -398,7 +365,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mysql-56-centos7:latest" + "name": "registry.centos.org/centos/mysql-56-centos7:latest" }, "name": "5.6", "referencePolicy": { @@ -416,7 +383,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/mysql-57-centos7:latest" + "name": "registry.centos.org/centos/mysql-57-centos7:latest" }, "name": "5.7", "referencePolicy": { @@ -439,60 +406,40 @@ "tags": [ { "annotations": { - "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.8/README.md.", + "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.14/README.md.", "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.8", + "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.14", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/sclorg/nginx-ex.git", "supports": "nginx", "tags": "builder,nginx", - "version": "1.8" + "version": "1.14" }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/nginx-18-centos7:latest" + "name": "registry.centos.org/centos/nginx-114-centos7:latest" }, - "name": "1.8", + "name": "1.14", "referencePolicy": { "type": "Local" } }, { "annotations": { - "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.10/README.md.", + "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.16/README.md.", "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.10", + "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.16", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/sclorg/nginx-ex.git", "supports": "nginx", "tags": "builder,nginx", - "version": "1.10" + "version": "1.16" }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/nginx-110-centos7:latest" + "name": "registry.centos.org/centos/nginx-116-centos7:latest" }, - "name": "1.10", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and serve static content via Nginx HTTP Server and a reverse proxy (nginx) on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/nginx-container/blob/master/1.12/README.md.", - "iconClass": "icon-nginx", - "openshift.io/display-name": "Nginx HTTP server and a reverse proxy 1.12", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nginx-ex.git", - "supports": "nginx", - "tags": "builder,nginx", - "version": "1.12" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/nginx-112-centos7:latest" - }, - "name": "1.12", + "name": "1.16", "referencePolicy": { "type": "Local" } @@ -509,7 +456,7 @@ }, "from": { "kind": "ImageStreamTag", - "name": "1.12" + "name": "1.16" }, "name": "latest", "referencePolicy": { @@ -542,7 +489,7 @@ }, "from": { "kind": "ImageStreamTag", - "name": "11" + "name": "12" }, "name": "latest", "referencePolicy": { @@ -551,105 +498,7 @@ }, { "annotations": { - "description": "DEPRECATED: Build and run Node.js 0.10 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/0.10/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 0.10", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:0.10,nodejs:0.1,nodejs", - "tags": "hidden,nodejs", - "version": "0.10" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/nodejs-010-centos7:latest" - }, - "name": "0.10", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 4 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/4/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:4,nodejs", - "tags": "hidden,builder,nodejs", - "version": "4" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/nodejs-4-centos7:latest" - }, - "name": "4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 6 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/6/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "supports": "nodejs:6,nodejs", - "tags": "builder,nodejs", - "version": "6" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/nodejs-6-centos7:latest" - }, - "name": "6", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 8 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/8/README.md.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 8", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "tags": "builder,nodejs", - "version": "8" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/nodejs-8-centos7:latest" - }, - "name": "8", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 8 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.", - "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 8 (RHOAR)", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", - "tags": "builder,nodejs", - "version": "8" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/nodeshift/centos7-s2i-nodejs:8.x" - }, - "name": "8-RHOAR", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Node.js 10 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.", + "description": "Build and run Node.js 10 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/10/README.md.", "iconClass": "icon-nodejs", "openshift.io/display-name": "Node.js 10", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -659,7 +508,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/nodeshift/centos7-s2i-nodejs:10.x" + "name": "registry.centos.org/centos/nodejs-10-centos7:latest" }, "name": "10", "referencePolicy": { @@ -668,19 +517,19 @@ }, { "annotations": { - "description": "Build and run Node.js 11 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/nodeshift/centos7-s2i-nodejs.", + "description": "Build and run Node.js 12 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-nodejs-container/blob/master/12/README.md.", "iconClass": "icon-nodejs", - "openshift.io/display-name": "Node.js 11", + "openshift.io/display-name": "Node.js 12", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/sclorg/nodejs-ex.git", "tags": "builder,nodejs", - "version": "11" + "version": "12" }, "from": { "kind": "DockerImage", - "name": "docker.io/nodeshift/centos7-s2i-nodejs:11.x" + "name": "registry.centos.org/centos/nodejs-12-centos7:latest" }, - "name": "11", + "name": "12", "referencePolicy": { "type": "Local" } @@ -718,46 +567,6 @@ "type": "Local" } }, - { - "annotations": { - "description": "Build and run Perl 5.16 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.16/README.md.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl 5.16", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl:5.16,perl", - "tags": "hidden,builder,perl", - "version": "5.16" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/perl-516-centos7:latest" - }, - "name": "5.16", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Perl 5.20 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.20/README.md.", - "iconClass": "icon-perl", - "openshift.io/display-name": "Perl 5.20", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/dancer-ex.git", - "supports": "perl:5.20,perl", - "tags": "hidden,builder,perl", - "version": "5.20" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/perl-520-centos7:latest" - }, - "name": "5.20", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Build and run Perl 5.24 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-perl-container/blob/master/5.24/README.md.", @@ -771,7 +580,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/perl-524-centos7:latest" + "name": "registry.centos.org/centos/perl-524-centos7:latest" }, "name": "5.24", "referencePolicy": { @@ -791,7 +600,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/perl-526-centos7:latest" + "name": "registry.centos.org/centos/perl-526-centos7:latest" }, "name": "5.26", "referencePolicy": { @@ -831,46 +640,6 @@ "type": "Local" } }, - { - "annotations": { - "description": "Build and run PHP 5.5 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/5.5/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP 5.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php:5.5,php", - "tags": "hidden,builder,php", - "version": "5.5" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/php-55-centos7:latest" - }, - "name": "5.5", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run PHP 5.6 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/5.6/README.md.", - "iconClass": "icon-php", - "openshift.io/display-name": "PHP 5.6", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/cakephp-ex.git", - "supports": "php:5.6,php", - "tags": "hidden,builder,php", - "version": "5.6" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/php-56-centos7:latest" - }, - "name": "5.6", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Build and run PHP 7.0 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-php-container/blob/master/7.0/README.md.", @@ -884,7 +653,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/php-70-centos7:latest" + "name": "registry.centos.org/centos/php-70-centos7:latest" }, "name": "7.0", "referencePolicy": { @@ -904,7 +673,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/php-71-centos7:latest" + "name": "registry.centos.org/centos/php-71-centos7:latest" }, "name": "7.1", "referencePolicy": { @@ -935,49 +704,13 @@ }, "from": { "kind": "ImageStreamTag", - "name": "10" + "name": "9.6" }, "name": "latest", "referencePolicy": { "type": "Local" } }, - { - "annotations": { - "description": "Provides a PostgreSQL 9.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 9.2", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,postgresql", - "version": "9.2" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/postgresql-92-centos7:latest" - }, - "name": "9.2", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 9.4 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 9.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "hidden,database,postgresql", - "version": "9.4" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/postgresql-94-centos7:latest" - }, - "name": "9.4", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Provides a PostgreSQL 9.5 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", @@ -989,7 +722,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/postgresql-95-centos7:latest" + "name": "registry.centos.org/centos/postgresql-95-centos7:latest" }, "name": "9.5", "referencePolicy": { @@ -1007,30 +740,12 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/postgresql-96-centos7:latest" + "name": "registry.centos.org/centos/postgresql-96-centos7:latest" }, "name": "9.6", "referencePolicy": { "type": "Local" } - }, - { - "annotations": { - "description": "Provides a PostgreSQL 10 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/postgresql-container/blob/master/README.md.", - "iconClass": "icon-postgresql", - "openshift.io/display-name": "PostgreSQL 10", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "tags": "database,postgresql", - "version": "10" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/postgresql-10-centos7:latest" - }, - "name": "10", - "referencePolicy": { - "type": "Local" - } } ] } @@ -1065,26 +780,6 @@ "type": "Local" } }, - { - "annotations": { - "description": "Build and run Python 3.3 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.3/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.3", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.3,python", - "tags": "hidden,builder,python", - "version": "3.3" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/python-33-centos7:latest" - }, - "name": "3.3", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Build and run Python 2.7 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/2.7/README.md.", @@ -1098,53 +793,13 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/python-27-centos7:latest" + "name": "registry.centos.org/centos/python-27-centos7:latest" }, "name": "2.7", "referencePolicy": { "type": "Local" } }, - { - "annotations": { - "description": "Build and run Python 3.4 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.4/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.4", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.4,python", - "tags": "hidden,builder,python", - "version": "3.4" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/python-34-centos7:latest" - }, - "name": "3.4", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run Python 3.5 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.5/README.md.", - "iconClass": "icon-python", - "openshift.io/display-name": "Python 3.5", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/sclorg/django-ex.git", - "supports": "python:3.5,python", - "tags": "builder,python", - "version": "3.5" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/centos/python-35-centos7:latest" - }, - "name": "3.5", - "referencePolicy": { - "type": "Local" - } - }, { "annotations": { "description": "Build and run Python 3.6 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-python-container/blob/master/3.6/README.md.", @@ -1158,7 +813,7 @@ }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/python-36-centos7:latest" + "name": "registry.centos.org/centos/python-36-centos7:latest" }, "name": "3.6", "referencePolicy": { @@ -1181,7 +836,7 @@ "tags": [ { "annotations": { - "description": "Provides a Redis database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/tree/master/3.2/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Redis available on OpenShift, including major versions updates.", + "description": "Provides a Redis database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Redis available on OpenShift, including major versions updates.", "iconClass": "icon-redis", "openshift.io/display-name": "Redis (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -1189,7 +844,7 @@ }, "from": { "kind": "ImageStreamTag", - "name": "3.2" + "name": "5" }, "name": "latest", "referencePolicy": { @@ -1198,18 +853,18 @@ }, { "annotations": { - "description": "Provides a Redis 3.2 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/tree/master/3.2/README.md.", + "description": "Provides a Redis 5 database on CentOS 7. For more information about using this database image, including OpenShift considerations, see https://github.com/sclorg/redis-container/blob/master/5/README.md.", "iconClass": "icon-redis", - "openshift.io/display-name": "Redis 3.2", + "openshift.io/display-name": "Redis 5", "openshift.io/provider-display-name": "Red Hat, Inc.", "tags": "redis", - "version": "3.2" + "version": "5" }, "from": { "kind": "DockerImage", - "name": "docker.io/centos/redis-32-centos7:latest" + "name": "registry.centos.org/centos/redis-5-centos7:latest" }, - "name": "3.2", + "name": "5", "referencePolicy": { "type": "Local" } @@ -1230,7 +885,7 @@ "tags": [ { "annotations": { - "description": "Build and run Ruby applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/tree/master/2.3/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Ruby available on OpenShift, including major versions updates.", + "description": "Build and run Ruby applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/sclorg/s2i-ruby-container/blob/master/README.md.\n\nWARNING: By selecting this tag, your application will automatically update to use the latest version of Ruby available on OpenShift, including major versions updates.", "iconClass": "icon-ruby", "openshift.io/display-name": "Ruby (Latest)", "openshift.io/provider-display-name": "Red Hat, Inc.", @@ -1295,7 +950,7 @@ }, "from": { "kind": "ImageStreamTag", - "name": "15.0" + "name": "21.0" }, "name": "latest", "referencePolicy": { @@ -1304,180 +959,40 @@ }, { "annotations": { - "description": "Build and run WildFly 8.1 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 8.1", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:8.1,jee,java", - "tags": "builder,wildfly,java", - "version": "8.1" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-81-centos7:latest" - }, - "name": "8.1", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 9.0 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 9.0", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:9.0,jee,java", - "tags": "builder,wildfly,java", - "version": "9.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-90-centos7:latest" - }, - "name": "9.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 10.0 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 10.0", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:10.0,jee,java", - "tags": "builder,wildfly,java", - "version": "10.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-100-centos7:latest" - }, - "name": "10.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 10.1 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 10.1", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:10.1,jee,java", - "tags": "builder,wildfly,java", - "version": "10.1" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-101-centos7:latest" - }, - "name": "10.1", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 11 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 11", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:11,jee,java", - "tags": "builder,wildfly,java", - "version": "11.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-110-centos7:latest" - }, - "name": "11.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 12 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 12", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:12,jee,java", - "tags": "builder,wildfly,java", - "version": "12.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-120-centos7:latest" - }, - "name": "12.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 13 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", - "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 13", - "openshift.io/provider-display-name": "Red Hat, Inc.", - "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:13,jee,java", - "tags": "builder,wildfly,java", - "version": "13.0" - }, - "from": { - "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-130-centos7:latest" - }, - "name": "13.0", - "referencePolicy": { - "type": "Local" - } - }, - { - "annotations": { - "description": "Build and run WildFly 14 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", + "description": "Build and run WildFly 20 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 14", + "openshift.io/display-name": "WildFly 20", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:14,jee,java", + "supports": "wildfly:20,jee,java", "tags": "builder,wildfly,java", - "version": "14.0" + "version": "20.0" }, "from": { "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-140-centos7:latest" + "name": "quay.io/wildfly/wildfly-centos7:20.0" }, - "name": "14.0", + "name": "20.0", "referencePolicy": { "type": "Local" } }, { "annotations": { - "description": "Build and run WildFly 15 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", + "description": "Build and run WildFly 21 applications on CentOS 7. For more information about using this builder image, including OpenShift considerations, see https://github.com/openshift-s2i/s2i-wildfly/blob/master/README.md.", "iconClass": "icon-wildfly", - "openshift.io/display-name": "WildFly 15", + "openshift.io/display-name": "WildFly 21", "openshift.io/provider-display-name": "Red Hat, Inc.", "sampleRepo": "https://github.com/openshift/openshift-jee-sample.git", - "supports": "wildfly:15,jee,java", + "supports": "wildfly:21,jee,java", "tags": "builder,wildfly,java", - "version": "15.0" + "version": "21.0" }, "from": { "kind": "DockerImage", - "name": "docker.io/openshift/wildfly-150-centos7:latest" + "name": "quay.io/wildfly/wildfly-centos7:21.0.0" }, - "name": "15.0", + "name": "21.0", "referencePolicy": { "type": "Local" } diff --git a/test/extended/testdata/cmd/test/cmd/testdata/mixed-api-versions.yaml b/test/extended/testdata/cmd/test/cmd/testdata/mixed-api-versions.yaml index 009f88cd198d..3981ad5877ad 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/mixed-api-versions.yaml +++ b/test/extended/testdata/cmd/test/cmd/testdata/mixed-api-versions.yaml @@ -34,7 +34,7 @@ items: run: v1-job spec: containers: - - image: openshift/hello-openshift + - image: k8s.gcr.io/e2e-test-images/agnhost:2.20 name: hello-container restartPolicy: Never @@ -51,6 +51,7 @@ items: kind: DockerImage dockerImageMetadataVersion: "1.0" dockerImageReference: registry/namespace/name + dockerImageLayers: [] kind: Image metadata: annotations: diff --git a/test/extended/testdata/cmd/test/cmd/testdata/roles/empty-role.yaml b/test/extended/testdata/cmd/test/cmd/testdata/roles/empty-role.yaml deleted file mode 100644 index c4808f34039e..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/roles/empty-role.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -kind: Role -metadata: - name: empty-role diff --git a/test/extended/testdata/cmd/test/cmd/testdata/roles/policy-clusterroles.yaml b/test/extended/testdata/cmd/test/cmd/testdata/roles/policy-clusterroles.yaml deleted file mode 100644 index ae5e28cfe3de..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/roles/policy-clusterroles.yaml +++ /dev/null @@ -1,57 +0,0 @@ -apiVersion: v1 -items: -- apiVersion: v1 - kind: ClusterRole - metadata: - creationTimestamp: null - name: basic-user2 - rules: - - apiGroups: null - attributeRestrictions: null - resourceNames: - - "~" - resources: - - users - verbs: - - get - - apiGroups: null - attributeRestrictions: null - resources: - - projectrequests - verbs: - - list - - apiGroups: null - attributeRestrictions: null - resources: - - clusterroles - verbs: - - get - - list - - apiGroups: null - attributeRestrictions: null - resources: - - projects - verbs: - - list - - apiGroups: - - authorization.k8s.io - attributeRestrictions: null - resources: - - selfsubjectaccessreviews - verbs: - - create -- apiVersion: v1 - groupNames: - - system:authenticated - kind: ClusterRoleBinding - metadata: - creationTimestamp: null - name: basic-users2 - roleRef: - name: basic-user2 - subjects: - - kind: SystemGroup - name: system:authenticated - userNames: null -kind: List -metadata: {} diff --git a/test/extended/testdata/cmd/test/cmd/testdata/roles/policy-roles.yaml b/test/extended/testdata/cmd/test/cmd/testdata/roles/policy-roles.yaml deleted file mode 100644 index 7ea9c2c87185..000000000000 --- a/test/extended/testdata/cmd/test/cmd/testdata/roles/policy-roles.yaml +++ /dev/null @@ -1,65 +0,0 @@ -kind: Template -apiVersion: v1 -metadata: - name: "policy-roles-template" -labels: - createdBy: "policy-roles-template" -parameters: - - description: "The namespace to create roles in." - name: NAMESPACE - required: true -objects: - - apiVersion: v1 - kind: Role - metadata: - creationTimestamp: null - name: basic-user - rules: - - apiGroups: null - attributeRestrictions: null - resourceNames: - - "~" - resources: - - users - verbs: - - get - - apiGroups: null - attributeRestrictions: null - resources: - - projectrequests - verbs: - - list - - apiGroups: null - attributeRestrictions: null - resources: - - clusterroles - verbs: - - get - - list - - apiGroups: null - attributeRestrictions: null - resources: - - projects - verbs: - - list - - apiGroups: - - authorization.k8s.io - attributeRestrictions: null - resources: - - selfsubjectaccessreviews - verbs: - - create - - apiVersion: v1 - groupNames: - - system:authenticated - kind: RoleBinding - metadata: - creationTimestamp: null - name: basic-users - roleRef: - name: basic-user - namespace: ${NAMESPACE} - subjects: - - kind: SystemGroup - name: system:authenticated - userNames: null diff --git a/test/extended/testdata/cmd/test/cmd/testdata/rollingupdate-daemonset.yaml b/test/extended/testdata/cmd/test/cmd/testdata/rollingupdate-daemonset.yaml index 8c52ee91a06a..56ab65ac3b2e 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/rollingupdate-daemonset.yaml +++ b/test/extended/testdata/cmd/test/cmd/testdata/rollingupdate-daemonset.yaml @@ -27,4 +27,5 @@ spec: namespaces: [] containers: - name: kubernetes-pause - image: gcr.io/google-containers/pause:2.0 + image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest + command: ["/bin/sleep", "84600"] diff --git a/test/extended/testdata/cmd/test/cmd/testdata/templateinstance_objectkinds.yaml b/test/extended/testdata/cmd/test/cmd/testdata/templateinstance_objectkinds.yaml index e96055807fca..9db1c8294e14 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/templateinstance_objectkinds.yaml +++ b/test/extended/testdata/cmd/test/cmd/testdata/templateinstance_objectkinds.yaml @@ -40,7 +40,7 @@ items: spec: containers: - name: hello-openshift - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 - kind: Route apiVersion: v1 metadata: diff --git a/test/extended/testdata/cmd/test/cmd/testdata/templates/template-type-precision.json b/test/extended/testdata/cmd/test/cmd/testdata/templates/template-type-precision.json index 119f24713cad..ae370b474a47 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/templates/template-type-precision.json +++ b/test/extended/testdata/cmd/test/cmd/testdata/templates/template-type-precision.json @@ -18,7 +18,7 @@ "containers": [ { "name": "test", - "image": "busybox", + "image": "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest", "imagePullPolicy": "IfNotPresent" } ], diff --git a/test/extended/testdata/cmd/test/cmd/testdata/test-bc.yaml b/test/extended/testdata/cmd/test/cmd/testdata/test-bc.yaml index febc42d16bf7..a4f15768bcf7 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/test-bc.yaml +++ b/test/extended/testdata/cmd/test/cmd/testdata/test-bc.yaml @@ -7,7 +7,7 @@ spec: runPolicy: Serial source: git: - uri: git://github.com/openshift/ruby-hello-world.git + uri: https://github.com/openshift/ruby-hello-world.git secrets: null type: Git strategy: diff --git a/test/extended/testdata/cmd/test/cmd/testdata/test-buildcli.json b/test/extended/testdata/cmd/test/cmd/testdata/test-buildcli.json index 928f60fd74a1..7e0cbd4f9951 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/test-buildcli.json +++ b/test/extended/testdata/cmd/test/cmd/testdata/test-buildcli.json @@ -39,7 +39,7 @@ "source": { "type": "Git", "git": { - "uri": "git://github.com/openshift/ruby-hello-world.git" + "uri": "https://github.com/openshift/ruby-hello-world.git" } }, "strategy": { @@ -81,7 +81,7 @@ "source": { "type": "Git", "git": { - "uri": "git://github.com/openshift/ruby-hello-world.git" + "uri": "https://github.com/openshift/ruby-hello-world.git" } }, "strategy": { diff --git a/test/extended/testdata/cmd/test/cmd/testdata/test-deployment-config.yaml b/test/extended/testdata/cmd/test/cmd/testdata/test-deployment-config.yaml index ce3436dc507b..2db724722da0 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/test-deployment-config.yaml +++ b/test/extended/testdata/cmd/test/cmd/testdata/test-deployment-config.yaml @@ -23,7 +23,7 @@ spec: name: test-deployment spec: containers: - - image: openshift/origin-pod + - image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest imagePullPolicy: IfNotPresent name: ruby-helloworld ports: @@ -40,4 +40,3 @@ spec: name: vol1 triggers: - type: ConfigChange -status: {} diff --git a/test/extended/testdata/cmd/test/cmd/testdata/test-docker-build.json b/test/extended/testdata/cmd/test/cmd/testdata/test-docker-build.json index e0ff3f0cf495..d2547d169c05 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/test-docker-build.json +++ b/test/extended/testdata/cmd/test/cmd/testdata/test-docker-build.json @@ -13,14 +13,14 @@ "git": { "uri":"https://github.com/sclorg/nodejs-ex" }, - "dockerfile": "FROM docker.io/busybox:latest" + "dockerfile": "FROM image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" }, "strategy":{ "type":"Docker", "dockerStrategy":{ "from":{ "kind":"DockerImage", - "name":"docker.io/busybox:latest" + "name":"image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" } } }, diff --git a/test/extended/testdata/cmd/test/cmd/testdata/test-image.json b/test/extended/testdata/cmd/test/cmd/testdata/test-image.json index 9a53170e3928..8824089c062f 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/test-image.json +++ b/test/extended/testdata/cmd/test/cmd/testdata/test-image.json @@ -13,5 +13,6 @@ "ContainerConfig": {}, "Config": {} }, + "dockerImageLayers": [], "dockerImageMetadataVersion": "1.0" } diff --git a/test/extended/testdata/cmd/test/cmd/testdata/test-replication-controller.yaml b/test/extended/testdata/cmd/test/cmd/testdata/test-replication-controller.yaml index 4172877ce01d..fe5da07f9374 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/test-replication-controller.yaml +++ b/test/extended/testdata/cmd/test/cmd/testdata/test-replication-controller.yaml @@ -19,7 +19,7 @@ spec: deploymentconfig: test-deployment spec: containers: - - image: openshift/origin-pod + - image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest imagePullPolicy: IfNotPresent name: ruby-helloworld ports: diff --git a/test/extended/testdata/cmd/test/cmd/timeout.sh b/test/extended/testdata/cmd/test/cmd/timeout.sh deleted file mode 100755 index 87078a1b9267..000000000000 --- a/test/extended/testdata/cmd/test/cmd/timeout.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -source "$(dirname "${BASH_SOURCE}")/../../hack/lib/init.sh" -trap os::test::junit::reconcile_output EXIT - -# Cleanup cluster resources created by this test -( - set +e - oc delete all,templates --all - exit 0 -) &>/dev/null - - -os::test::junit::declare_suite_start "cmd/request-timeout" -# This test validates the global request-timeout option -os::cmd::expect_success 'oc create deploymentconfig testdc --image=busybox' -os::cmd::expect_success_and_text 'oc get dc/testdc -w -v=5 --request-timeout=1s 2>&1' 'request canceled' -os::cmd::expect_success_and_text 'oc get dc/testdc --request-timeout=1s' 'testdc' -os::cmd::expect_success_and_text 'oc get dc/testdc --request-timeout=1' 'testdc' -os::cmd::expect_success_and_text 'oc get pods --watch -v=5 --request-timeout=1s 2>&1' 'request canceled' - -echo "request-timeout: ok" -os::test::junit::declare_suite_end diff --git a/test/extended/testdata/cmd/test/cmd/triggers.sh b/test/extended/testdata/cmd/test/cmd/triggers.sh index 6925c6cd648a..83ff880499cc 100755 --- a/test/extended/testdata/cmd/test/cmd/triggers.sh +++ b/test/extended/testdata/cmd/test/cmd/triggers.sh @@ -93,7 +93,7 @@ os::test::junit::declare_suite_end os::test::junit::declare_suite_start "cmd/triggers/deploymentconfigs" ## Deployment configs -os::cmd::expect_success 'oc create deploymentconfig testdc --image=busybox' +os::cmd::expect_success 'oc create deploymentconfig testdc --image=image-registry.openshift-image-registry.svc:5000/openshift/tools:latest' # error conditions os::cmd::expect_failure_and_text 'oc set triggers dc/testdc --from-github' 'deployment configs do not support GitHub web hooks' @@ -121,7 +121,7 @@ os::test::junit::declare_suite_end os::test::junit::declare_suite_start "cmd/triggers/annotations" ## Deployment -os::cmd::expect_success 'oc create deployment test --image=busybox' +os::cmd::expect_success 'oc create deployment test --image=image-registry.openshift-image-registry.svc:5000/openshift/tools:latest' # error conditions os::cmd::expect_failure_and_text 'oc set triggers deploy/test --from-github' 'does not support GitHub web hooks' @@ -129,7 +129,7 @@ os::cmd::expect_failure_and_text 'oc set triggers deploy/test --from-webhook' 'd os::cmd::expect_failure_and_text 'oc set triggers deploy/test --from-gitlab' 'does not support GitLab web hooks' os::cmd::expect_failure_and_text 'oc set triggers deploy/test --from-bitbucket' 'does not support Bitbucket web hooks' os::cmd::expect_failure_and_text 'oc set triggers deploy/test --from-image=test:latest' 'you must specify --containers when setting --from-image' -os::cmd::expect_failure_and_text 'oc set triggers deploy/test --from-image=test:latest --containers=other' 'not all container names exist: other \(accepts: busybox\)' +os::cmd::expect_failure_and_text 'oc set triggers deploy/test --from-image=test:latest --containers=other' 'not all container names exist: other \(accepts: tools\)' # print os::cmd::expect_success_and_text 'oc set triggers deploy/test' 'config.*true' os::cmd::expect_success_and_not_text 'oc set triggers deploy/test' 'webhook|github|gitlab|bitbucket' @@ -142,8 +142,8 @@ os::cmd::expect_success_and_text 'oc set triggers deploy/test' 'config.*false' # auto os::cmd::expect_success_and_text 'oc set triggers deploy/test --auto' 'updated' os::cmd::expect_success_and_text 'oc set triggers deploy/test' 'config.*true' -os::cmd::expect_success_and_text 'oc set triggers deploy/test --from-image=ruby-hello-world:latest -c busybox' 'updated' -os::cmd::expect_success_and_text 'oc set triggers deploy/test' 'image.*ruby-hello-world:latest \(busybox\).*true' +os::cmd::expect_success_and_text 'oc set triggers deploy/test --from-image=ruby-hello-world:latest -c tools' 'updated' +os::cmd::expect_success_and_text 'oc set triggers deploy/test' 'image.*ruby-hello-world:latest \(tools\).*true' os::test::junit::declare_suite_end os::test::junit::declare_suite_end diff --git a/test/extended/testdata/config-map-jenkins-slave-pods.yaml b/test/extended/testdata/config-map-jenkins-slave-pods.yaml index ea4799cc30c5..85c4ead709dc 100644 --- a/test/extended/testdata/config-map-jenkins-slave-pods.yaml +++ b/test/extended/testdata/config-map-jenkins-slave-pods.yaml @@ -15,7 +15,7 @@ items: jnlp - openshift/jenkins-slave-maven-centos7 + image-registry.openshift-image-registry.svc:5000/openshift/jenkins-agent-maven:latest false false /tmp diff --git a/test/extended/testdata/csi/OWNERS b/test/extended/testdata/csi/OWNERS deleted file mode 100644 index ec422ab6e2b9..000000000000 --- a/test/extended/testdata/csi/OWNERS +++ /dev/null @@ -1,4 +0,0 @@ -approvers: -- jsafrane -- bertinatto -- gnufied diff --git a/test/extended/testdata/csi/README.md b/test/extended/testdata/csi/README.md deleted file mode 100644 index d253bd438217..000000000000 --- a/test/extended/testdata/csi/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# CSI driver installer manifests - -Each CSI driver is represented as a directory with two required files: - -``` -/install-template.yaml -/manifest.yaml -``` - -Optionally, there can also be a file for a storageClass: - -``` -/storageclass.yaml -``` - -This file is typically used to set custom parameters in the storageClass. For instance, -in order to use the [topology](https://kubernetes-csi.github.io/docs/topology.html) -feature of a CSI driver, one might want to have a custom storageClass with `volumeBindingMode` -set to `WaitForFirstConsumer`. Also, the custom storageClass needs to be refereced in the [manifest file](#manifest). - -## Driver template -`install-template.yaml` is a [golang template](https://golang.org/pkg/text/template/) of YAML file with all Kubernetes objects of a CSI driver. -It will be instantiated at the beginning of the test via `oc apply -f `, where `` is result of the template evaluation. - -It is expected that the YAML file creates also a hardcoded namespace, so multiple `oc apply -f ` are idempotent and don't install the driver multiple times. - -Following variables are available in the template: - -* Name of sidecar image to test with. It is either the last build in the appropriate 4.x branch or image build from PR that's being tested. - * `{{.AttacherImage}}` - * `{{.ProvisionerImage}}` - * `{{.ResizerImage}}` - * `{{.SnapshotterImage}}` - * `{{.NodeDriverRegistrarImage}}` - * `{{.LivenessProbeImage}}` - -* `{{.ImageFormat}}`: Generic format of image names for the test, provided in case the template wants to use a different image than the listed above. E.g. `registry.svc.ci.openshift.org/ci-op-pthpkjbt/stable:${component}`. - -## Manifest -`manifest.yaml` describes features of the CSI driver. See [upstream documentation](https://github.com/kubernetes/kubernetes/blob/master/test/e2e/storage/external/README.md) for its format and usage. - -## Usage - -CSI driver defined here can be installed and tested using: - -``` -TEST_INSTALL_CSI_DRIVERS= openshift-tests run openshift/csi -``` - -Multiple CSI drivers can be installed & tested in one run, `TEST_INSTALL_CSI_DRIVERS` is comma-separated list. diff --git a/test/extended/testdata/csi/aws-ebs/install-template.yaml b/test/extended/testdata/csi/aws-ebs/install-template.yaml deleted file mode 100644 index 9630966bd5ce..000000000000 --- a/test/extended/testdata/csi/aws-ebs/install-template.yaml +++ /dev/null @@ -1,398 +0,0 @@ -# Installation of AWS EBS CSI driver into OpenShift. -# Source: https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/e727882eae38614ec3246b243255e536aeef5a0f/deploy/kubernetes/manifest.yaml -# Tailored for OCP: -# - Run controllers with hostNetwork: true to access AWS instance metadata (https://bugzilla.redhat.com/show_bug.cgi?id=1734600) -# - Removed livenessprobe for this -# - Scaled controllers to 1 -# - Run in kube-system and use aws-creds secrets there - -# Controller Service -apiVersion: v1 -kind: ServiceAccount -metadata: - name: ebs-csi-controller-sa - namespace: kube-system - ---- - -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: ebs-external-provisioner-role -rules: - - apiGroups: [""] - resources: ["persistentvolumes"] - verbs: ["get", "list", "watch", "create", "delete"] - - apiGroups: [""] - resources: ["persistentvolumeclaims"] - verbs: ["get", "list", "watch", "update"] - - apiGroups: ["storage.k8s.io"] - resources: ["storageclasses"] - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["events"] - verbs: ["get", "list", "watch", "create", "update", "patch"] - - apiGroups: ["storage.k8s.io"] - resources: ["csinodes"] - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["nodes"] - verbs: ["get", "list", "watch"] - ---- - -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: ebs-csi-provisioner-binding -subjects: - - kind: ServiceAccount - name: ebs-csi-controller-sa - namespace: kube-system -roleRef: - kind: ClusterRole - name: ebs-external-provisioner-role - apiGroup: rbac.authorization.k8s.io - ---- - -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: ebs-external-attacher-role -rules: - - apiGroups: [""] - resources: ["persistentvolumes"] - verbs: ["get", "list", "watch", "update", "patch"] - - apiGroups: [""] - resources: ["nodes"] - verbs: ["get", "list", "watch"] - - apiGroups: ["csi.storage.k8s.io"] - resources: ["csinodeinfos"] - verbs: ["get", "list", "watch"] - - apiGroups: ["storage.k8s.io"] - resources: ["volumeattachments"] - verbs: ["get", "list", "watch", "update", "patch"] - ---- - -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: ebs-csi-attacher-binding -subjects: - - kind: ServiceAccount - name: ebs-csi-controller-sa - namespace: kube-system -roleRef: - kind: ClusterRole - name: ebs-external-attacher-role - apiGroup: rbac.authorization.k8s.io - ---- -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: ebs-external-resizer-role -rules: - - apiGroups: [""] - resources: ["persistentvolumes"] - verbs: ["get", "list", "watch", "update", "patch"] - - apiGroups: [""] - resources: ["persistentvolumeclaims"] - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["persistentvolumeclaims/status"] - verbs: ["update", "patch"] - - apiGroups: ["storage.k8s.io"] - resources: ["storageclasses"] - verbs: ["get", "list", "watch"] - - apiGroups: [""] - resources: ["events"] - verbs: ["list", "watch", "create", "update", "patch"] - ---- - -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: ebs-csi-resizer-binding -subjects: - - kind: ServiceAccount - name: ebs-csi-controller-sa - namespace: kube-system -roleRef: - kind: ClusterRole - name: ebs-external-resizer-role - apiGroup: rbac.authorization.k8s.io - ---- - -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: ebs-external-snapshotter-role -rules: -- apiGroups: [""] - resources: ["persistentvolumes"] - verbs: ["get", "list", "watch"] -- apiGroups: [""] - resources: ["persistentvolumeclaims"] - verbs: ["get", "list", "watch"] -- apiGroups: ["storage.k8s.io"] - resources: ["storageclasses"] - verbs: ["get", "list", "watch"] -- apiGroups: [""] - resources: ["events"] - verbs: ["list", "watch", "create", "update", "patch"] -- apiGroups: [""] - resources: ["secrets"] - verbs: ["get", "list"] -- apiGroups: ["snapshot.storage.k8s.io"] - resources: ["volumesnapshotclasses"] - verbs: ["get", "list", "watch"] -- apiGroups: ["snapshot.storage.k8s.io"] - resources: ["volumesnapshotcontents"] - verbs: ["create", "get", "list", "watch", "update", "delete"] -- apiGroups: ["snapshot.storage.k8s.io"] - resources: ["volumesnapshotcontents/status"] - verbs: ["update"] -- apiGroups: ["snapshot.storage.k8s.io"] - resources: ["volumesnapshots"] - verbs: ["get", "list", "watch", "update"] -- apiGroups: ["apiextensions.k8s.io"] - resources: ["customresourcedefinitions"] - verbs: ["create", "list", "watch", "delete"] -- apiGroups: ["coordination.k8s.io"] - resources: ["leases"] - verbs: ["get", "watch", "list", "delete", "update", "create"] - ---- - -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: ebs-csi-snapshotter-binding -subjects: - - kind: ServiceAccount - name: ebs-csi-controller-sa - namespace: kube-system -roleRef: - kind: ClusterRole - name: ebs-external-snapshotter-role - apiGroup: rbac.authorization.k8s.io - ---- - -kind: StatefulSet -apiVersion: apps/v1 -metadata: - name: ebs-csi-controller - namespace: kube-system -spec: - selector: - matchLabels: - app: ebs-csi-controller - serviceName: ebs-csi-controller - replicas: 1 - template: - metadata: - labels: - app: ebs-csi-controller - spec: - hostNetwork: true - serviceAccount: ebs-csi-controller-sa - priorityClassName: system-cluster-critical - tolerations: - - key: CriticalAddonsOnly - operator: Exists - containers: - - name: ebs-plugin - image: amazon/aws-ebs-csi-driver:latest - args: - - --endpoint=$(CSI_ENDPOINT) - - --logtostderr - - --v=5 - env: - - name: CSI_ENDPOINT - value: unix:///var/lib/csi/sockets/pluginproxy/csi.sock - - name: AWS_ACCESS_KEY_ID - valueFrom: - secretKeyRef: - name: aws-creds - key: aws_access_key_id - optional: true - - name: AWS_SECRET_ACCESS_KEY - valueFrom: - secretKeyRef: - name: aws-creds - key: aws_secret_access_key - optional: true - ports: - - name: healthz - containerPort: 19808 - protocol: TCP - volumeMounts: - - name: socket-dir - mountPath: /var/lib/csi/sockets/pluginproxy/ - - name: csi-provisioner - image: {{.ProvisionerImage}} - args: - - --provisioner=ebs.csi.aws.com - - --csi-address=$(ADDRESS) - - --v=5 - - --feature-gates=Topology=true - env: - - name: ADDRESS - value: /var/lib/csi/sockets/pluginproxy/csi.sock - volumeMounts: - - name: socket-dir - mountPath: /var/lib/csi/sockets/pluginproxy/ - - name: csi-attacher - image: {{.AttacherImage}} - args: - - --csi-address=$(ADDRESS) - - --v=5 - env: - - name: ADDRESS - value: /var/lib/csi/sockets/pluginproxy/csi.sock - volumeMounts: - - name: socket-dir - mountPath: /var/lib/csi/sockets/pluginproxy/ - - name: csi-resizer - image: {{.ResizerImage}} - args: - - --csi-address=$(ADDRESS) - - --v=5 - env: - - name: ADDRESS - value: /var/lib/csi/sockets/pluginproxy/csi.sock - volumeMounts: - - name: socket-dir - mountPath: /var/lib/csi/sockets/pluginproxy/ - - name: csi-snapshotter - image: {{.SnapshotterImage}} - args: - - --csi-address=$(ADDRESS) - - --v=5 - env: - - name: ADDRESS - value: /var/lib/csi/sockets/pluginproxy/csi.sock - volumeMounts: - - mountPath: /var/lib/csi/sockets/pluginproxy/ - name: socket-dir - volumes: - - name: socket-dir - emptyDir: {} - ---- - -# Node Service -kind: DaemonSet -apiVersion: apps/v1 -metadata: - name: ebs-csi-node - namespace: kube-system -spec: - selector: - matchLabels: - app: ebs-csi-node - template: - metadata: - labels: - app: ebs-csi-node - spec: - hostNetwork: true - priorityClassName: system-node-critical - tolerations: - - key: CriticalAddonsOnly - operator: Exists - containers: - - name: ebs-plugin - securityContext: - privileged: true - image: amazon/aws-ebs-csi-driver:latest - args: - - --endpoint=$(CSI_ENDPOINT) - - --logtostderr - - --v=5 - env: - - name: CSI_ENDPOINT - value: unix:/csi/csi.sock - volumeMounts: - - name: kubelet-dir - mountPath: /var/lib/kubelet - mountPropagation: "Bidirectional" - - name: plugin-dir - mountPath: /csi - - name: device-dir - mountPath: /dev - ports: - - name: healthz - containerPort: 9808 - protocol: TCP - livenessProbe: - httpGet: - path: /healthz - port: healthz - initialDelaySeconds: 10 - timeoutSeconds: 3 - periodSeconds: 10 - failureThreshold: 5 - - name: node-driver-registrar - securityContext: - privileged: true - image: {{.NodeDriverRegistrarImage}} - args: - - --csi-address=$(ADDRESS) - - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH) - - --v=5 - lifecycle: - preStop: - exec: - command: ["/bin/sh", "-c", "rm -rf /registration/ebs.csi.aws.com-reg.sock /csi/csi.sock"] - env: - - name: ADDRESS - value: /csi/csi.sock - - name: DRIVER_REG_SOCK_PATH - value: /var/lib/kubelet/plugins/ebs.csi.aws.com/csi.sock - volumeMounts: - - name: plugin-dir - mountPath: /csi - - name: registration-dir - mountPath: /registration - - name: liveness-probe - image: {{.LivenessProbeImage}} - args: - - --csi-address=/csi/csi.sock - - --probe-timeout=3s - volumeMounts: - - name: plugin-dir - mountPath: /csi - volumes: - - name: kubelet-dir - hostPath: - path: /var/lib/kubelet - type: Directory - - name: plugin-dir - hostPath: - path: /var/lib/kubelet/plugins/ebs.csi.aws.com/ - type: DirectoryOrCreate - - name: registration-dir - hostPath: - path: /var/lib/kubelet/plugins_registry/ - type: Directory - - name: device-dir - hostPath: - path: /dev - type: Directory - ---- - -apiVersion: storage.k8s.io/v1beta1 -kind: CSIDriver -metadata: - name: ebs.csi.aws.com -spec: - attachRequired: true - podInfoOnMount: false diff --git a/test/extended/testdata/csi/aws-ebs/manifest.yaml b/test/extended/testdata/csi/aws-ebs/manifest.yaml deleted file mode 100644 index 8415182a4129..000000000000 --- a/test/extended/testdata/csi/aws-ebs/manifest.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Test manifest for https://github.com/kubernetes/kubernetes/tree/master/test/e2e/storage/external -ShortName: ebs -StorageClass: - FromFile: storageclass.yaml -SnapshotClass: - FromName: true -DriverInfo: - Name: ebs.csi.aws.com - SupportedSizeRange: - Min: 1Gi - Max: 16Ti - SupportedFsType: - xfs: {} - ext4: {} - SupportedMountOption: - dirsync: {} - TopologyKeys: ["topology.ebs.csi.aws.com/zone"] - Capabilities: - persistence: true - fsGroup: true - block: true - exec: true - volumeLimits: false - controllerExpansion: true - nodeExpansion: true - snapshotDataSource: true diff --git a/test/extended/testdata/csi/aws-ebs/storageclass.yaml b/test/extended/testdata/csi/aws-ebs/storageclass.yaml deleted file mode 100644 index 469d20f518f4..000000000000 --- a/test/extended/testdata/csi/aws-ebs/storageclass.yaml +++ /dev/null @@ -1,6 +0,0 @@ -kind: StorageClass -apiVersion: storage.k8s.io/v1 -metadata: - name: ebs.csi.aws.com -provisioner: ebs.csi.aws.com -volumeBindingMode: WaitForFirstConsumer diff --git a/test/extended/testdata/deployments/custom-deployment.yaml b/test/extended/testdata/deployments/custom-deployment.yaml index 999675940875..d8397116d361 100644 --- a/test/extended/testdata/deployments/custom-deployment.yaml +++ b/test/extended/testdata/deployments/custom-deployment.yaml @@ -36,7 +36,7 @@ spec: spec: terminationGracePeriodSeconds: 0 containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: myapp command: diff --git a/test/extended/testdata/deployments/deployment-history-limit.yaml b/test/extended/testdata/deployments/deployment-history-limit.yaml index 6aa01f629901..229eb91f269c 100644 --- a/test/extended/testdata/deployments/deployment-history-limit.yaml +++ b/test/extended/testdata/deployments/deployment-history-limit.yaml @@ -12,7 +12,7 @@ spec: name: history-limit spec: containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: myapp command: diff --git a/test/extended/testdata/deployments/deployment-ignores-deployer.yaml b/test/extended/testdata/deployments/deployment-ignores-deployer.yaml index adc35c7fb6d4..d7c0e7a3bd65 100644 --- a/test/extended/testdata/deployments/deployment-ignores-deployer.yaml +++ b/test/extended/testdata/deployments/deployment-ignores-deployer.yaml @@ -15,7 +15,7 @@ spec: spec: terminationGracePeriodSeconds: 0 containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: myapp command: diff --git a/test/extended/testdata/deployments/deployment-image-resolution-is.yaml b/test/extended/testdata/deployments/deployment-image-resolution-is.yaml index 5b9aec8d94fd..9fdeebffcab6 100644 --- a/test/extended/testdata/deployments/deployment-image-resolution-is.yaml +++ b/test/extended/testdata/deployments/deployment-image-resolution-is.yaml @@ -7,12 +7,12 @@ spec: - name: pullthrough from: kind: DockerImage - name: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + name: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" referencePolicy: type: Local - name: direct from: kind: DockerImage - name: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + name: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" referencePolicy: type: Source diff --git a/test/extended/testdata/deployments/deployment-min-ready-seconds.yaml b/test/extended/testdata/deployments/deployment-min-ready-seconds.yaml index 82ef3fad4ff0..cbdbe16932d9 100644 --- a/test/extended/testdata/deployments/deployment-min-ready-seconds.yaml +++ b/test/extended/testdata/deployments/deployment-min-ready-seconds.yaml @@ -14,7 +14,7 @@ spec: spec: terminationGracePeriodSeconds: 0 containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: myapp command: diff --git a/test/extended/testdata/deployments/deployment-simple.yaml b/test/extended/testdata/deployments/deployment-simple.yaml index 653c05eb09d0..e3259b5e1494 100644 --- a/test/extended/testdata/deployments/deployment-simple.yaml +++ b/test/extended/testdata/deployments/deployment-simple.yaml @@ -15,7 +15,7 @@ spec: name: deployment-simple spec: containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent command: - /bin/sleep diff --git a/test/extended/testdata/deployments/deployment-with-ref-env.yaml b/test/extended/testdata/deployments/deployment-with-ref-env.yaml index 8bba633a98e2..64485cedc277 100644 --- a/test/extended/testdata/deployments/deployment-with-ref-env.yaml +++ b/test/extended/testdata/deployments/deployment-with-ref-env.yaml @@ -27,7 +27,7 @@ spec: name: deployment-simple spec: containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" command: [ "/bin/bash", "-c", "sleep infinity" ] imagePullPolicy: IfNotPresent name: myapp diff --git a/test/extended/testdata/deployments/failing-pre-hook.yaml b/test/extended/testdata/deployments/failing-pre-hook.yaml index a03973336479..cfe1eb83b350 100644 --- a/test/extended/testdata/deployments/failing-pre-hook.yaml +++ b/test/extended/testdata/deployments/failing-pre-hook.yaml @@ -23,7 +23,7 @@ spec: name: hook spec: containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" command: - /bin/sleep - infinity diff --git a/test/extended/testdata/deployments/generation-test.yaml b/test/extended/testdata/deployments/generation-test.yaml index dc7301893656..dbe1779a3e85 100644 --- a/test/extended/testdata/deployments/generation-test.yaml +++ b/test/extended/testdata/deployments/generation-test.yaml @@ -22,7 +22,7 @@ spec: name: generation-test spec: containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: myapp command: diff --git a/test/extended/testdata/deployments/paused-deployment.yaml b/test/extended/testdata/deployments/paused-deployment.yaml index cf895b0f41ed..958a8036b679 100644 --- a/test/extended/testdata/deployments/paused-deployment.yaml +++ b/test/extended/testdata/deployments/paused-deployment.yaml @@ -11,7 +11,7 @@ spec: name: paused spec: containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: myapp command: diff --git a/test/extended/testdata/deployments/readiness-test.yaml b/test/extended/testdata/deployments/readiness-test.yaml index 17ae13ab1ce3..3b5e83065d04 100644 --- a/test/extended/testdata/deployments/readiness-test.yaml +++ b/test/extended/testdata/deployments/readiness-test.yaml @@ -17,7 +17,7 @@ spec: - command: - /bin/sleep - "infinity" - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: never-ready readinessProbe: diff --git a/test/extended/testdata/deployments/tag-images-deployment.yaml b/test/extended/testdata/deployments/tag-images-deployment.yaml index fb6f605a2024..c1381efd68f5 100644 --- a/test/extended/testdata/deployments/tag-images-deployment.yaml +++ b/test/extended/testdata/deployments/tag-images-deployment.yaml @@ -23,9 +23,11 @@ spec: labels: name: tag-images spec: + terminationGracePeriodSeconds: 1 containers: - - image: openshift/origin-pod + - image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest imagePullPolicy: IfNotPresent + command: ["/bin/sh", "-c", "sleep 300"] name: sample-name ports: - containerPort: 8080 diff --git a/test/extended/testdata/deployments/test-deployment-broken.yaml b/test/extended/testdata/deployments/test-deployment-broken.yaml index e0cb239e5b33..13041ea9c98d 100644 --- a/test/extended/testdata/deployments/test-deployment-broken.yaml +++ b/test/extended/testdata/deployments/test-deployment-broken.yaml @@ -21,7 +21,7 @@ spec: name: brokendeployment spec: containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: myapp command: diff --git a/test/extended/testdata/deployments/test-deployment-test.yaml b/test/extended/testdata/deployments/test-deployment-test.yaml index 55890b8b7dd1..4cc2fcf47b15 100644 --- a/test/extended/testdata/deployments/test-deployment-test.yaml +++ b/test/extended/testdata/deployments/test-deployment-test.yaml @@ -26,7 +26,7 @@ spec: spec: terminationGracePeriodSeconds: 0 containers: - - image: "registry.access.redhat.com/ubi8/ubi-minimal:latest" + - image: "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" imagePullPolicy: IfNotPresent name: myapp command: diff --git a/test/extended/testdata/disaster-recovery/restore-etcd.sh b/test/extended/testdata/disaster-recovery/restore-etcd.sh deleted file mode 100755 index e709848c560f..000000000000 --- a/test/extended/testdata/disaster-recovery/restore-etcd.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash -set -euo pipefail - -if [ -z "${BASTION_HOST}" ]; then exit 1; fi -if [ -z "${MASTERHOSTS}" ]; then exit 1; fi -if [ -z "${KUBE_SSH_KEY_PATH}" ]; then exit 1; fi - -MASTERS=(${MASTERHOSTS}) -FIRST_MASTER="${MASTERS[0]}" - -function retry() { - local ATTEMPTS="${1}" - local rc=0 - shift - for i in $(seq 0 $((ATTEMPTS-1))); do - echo "--> ${@}" - set +e - "${@}" - rc="$?" - set -e - echo "--> exit code: $rc" - test "${rc}" = 0 && break - sleep 10 - done - return "${rc}" -} - -function bastion_ssh() { - retry 60 \ - ssh -o LogLevel=error -o ConnectionAttempts=100 -o ConnectTimeout=30 -o StrictHostKeyChecking=no \ - -o ProxyCommand="ssh -A -o StrictHostKeyChecking=no -o LogLevel=error -o ServerAliveInterval=30 -o ConnectionAttempts=100 -o ConnectTimeout=30 -W %h:%p core@${BASTION_HOST} 2>/dev/null" \ - $@ -} - -echo "Distribute snapshot across all masters" -for master in "${MASTERS[@]}" -do - scp -o StrictHostKeyChecking=no -o ProxyCommand="ssh -A -o StrictHostKeyChecking=no -o ServerAliveInterval=30 -W %h:%p core@${BASTION_HOST}" ${KUBE_SSH_KEY_PATH} "core@${master}":/home/core/.ssh/id_rsa - bastion_ssh "core@${master}" "sudo -i chmod 0600 /home/core/.ssh/id_rsa" - bastion_ssh "core@${FIRST_MASTER}" "scp -o StrictHostKeyChecking=no /tmp/snapshot.db core@${master}:/tmp/snapshot.db" -done - -echo "Collect etcd names" -for master in "${MASTERS[@]}" -do - bastion_ssh "core@${master}" 'echo "etcd-member-$(hostname -f)" > /tmp/etcd_name && source /run/etcd/environment && echo "https://${ETCD_DNS_NAME}:2380" > /tmp/etcd_uri' - bastion_ssh "core@${FIRST_MASTER}" "mkdir -p /tmp/etcd/${master} && scp -o StrictHostKeyChecking=no core@${master}:/tmp/etcd_name /tmp/etcd/${master}/etcd_name && scp -o StrictHostKeyChecking=no core@${master}:/tmp/etcd_uri /tmp/etcd/${master}/etcd_uri" - bastion_ssh "core@${FIRST_MASTER}" "cat /tmp/etcd/${master}/etcd_name" - bastion_ssh "core@${FIRST_MASTER}" "cat /tmp/etcd/${master}/etcd_uri" -done - -echo "Assemble etcd connection string" -bastion_ssh "core@${FIRST_MASTER}" 'rm -rf /tmp/etcd/connstring && mapfile -t MASTERS < <(ls /tmp/etcd) && echo ${MASTERS[@]} && for master in "${MASTERS[@]}"; do echo -n "$(cat /tmp/etcd/${master}/etcd_name)=$(cat /tmp/etcd/${master}/etcd_uri)," >> /tmp/etcd/connstring; done && sed -i '"'$ s/.$//'"' /tmp/etcd/connstring' - -echo "Restore etcd cluster from snapshot" -for master in "${MASTERS[@]}" -do - echo "Running /usr/local/bin/etcd-snapshot-restore.sh on ${master}" - bastion_ssh "core@${FIRST_MASTER}" "scp -o StrictHostKeyChecking=no /tmp/etcd/connstring core@${master}:/tmp/etcd_connstring" - bastion_ssh "core@${master}" 'sudo -i /bin/bash -x /usr/local/bin/etcd-snapshot-restore.sh /tmp/snapshot.db $(cat /tmp/etcd_connstring)' -done diff --git a/test/extended/testdata/disaster-recovery/rollback-A.yaml b/test/extended/testdata/disaster-recovery/rollback-A.yaml deleted file mode 100644 index 9634a704cf9e..000000000000 --- a/test/extended/testdata/disaster-recovery/rollback-A.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: machineconfiguration.openshift.io/v1 -kind: MachineConfig -metadata: - labels: - machineconfiguration.openshift.io/role: master - name: 99-rollback-test -spec: - config: - ignition: - version: 2.2.0 - storage: - files: - - contents: - source: data:,A - filesystem: root - mode: 420 - path: /etc/rollback-test diff --git a/test/extended/testdata/disaster-recovery/rollback-B.yaml b/test/extended/testdata/disaster-recovery/rollback-B.yaml deleted file mode 100644 index f731af036ab7..000000000000 --- a/test/extended/testdata/disaster-recovery/rollback-B.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: machineconfiguration.openshift.io/v1 -kind: MachineConfig -metadata: - labels: - machineconfiguration.openshift.io/role: master - name: 99-rollback-test -spec: - config: - ignition: - version: 2.2.0 - storage: - files: - - contents: - source: data:,B - filesystem: root - mode: 420 - path: /etc/rollback-test diff --git a/test/extended/testdata/disaster-recovery/ssh-bastion/clusterrole.yaml b/test/extended/testdata/disaster-recovery/ssh-bastion/clusterrole.yaml deleted file mode 100644 index f7ce7f35641c..000000000000 --- a/test/extended/testdata/disaster-recovery/ssh-bastion/clusterrole.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: ssh-bastion -rules: -- apiGroups: - - "machineconfiguration.openshift.io" - resources: - - "machineconfigs" - verbs: - - get -- apiGroups: - - "" - resources: - - "nodes" - verbs: - - list - - get diff --git a/test/extended/testdata/disaster-recovery/ssh-bastion/clusterrolebinding.yaml b/test/extended/testdata/disaster-recovery/ssh-bastion/clusterrolebinding.yaml deleted file mode 100644 index cdad0df9e50f..000000000000 --- a/test/extended/testdata/disaster-recovery/ssh-bastion/clusterrolebinding.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - annotations: - openshift.io/description: Allows ssh-pod to read nodes and machineconfigs - name: ssh-bastion -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: ssh-bastion -subjects: -- apiGroup: rbac.authorization.k8s.io - kind: User - name: system:serviceaccount:ssh-bastion:ssh-bastion diff --git a/test/extended/testdata/disaster-recovery/ssh-bastion/deployment.yaml b/test/extended/testdata/disaster-recovery/ssh-bastion/deployment.yaml deleted file mode 100644 index 7e707120aa14..000000000000 --- a/test/extended/testdata/disaster-recovery/ssh-bastion/deployment.yaml +++ /dev/null @@ -1,49 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - run: ssh-bastion - name: ssh-bastion - namespace: ssh-bastion -spec: - replicas: 1 - selector: - matchLabels: - run: ssh-bastion - template: - metadata: - labels: - run: ssh-bastion - spec: - serviceAccountName: "ssh-bastion" - containers: - - image: quay.io/eparis/ssh:latest - imagePullPolicy: Always - name: ssh-bastion - ports: - - containerPort: 22 - name: ssh - protocol: TCP - volumeMounts: - - name: ssh-host-keys - mountPath: "/etc/ssh/" - readOnly: true - securityContext: - privileged: true - volumes: - - name: ssh-host-keys - secret: - secretName: ssh-host-keys - items: - - key: ssh_host_rsa_key - path: ssh_host_rsa_key - mode: 256 - - key: ssh_host_ecdsa_key - path: ssh_host_ecdsa_key - mode: 256 - - key: ssh_host_ed25519_key - path: ssh_host_ed25519_key - mode: 256 - - key: sshd_config - path: sshd_config - restartPolicy: Always diff --git a/test/extended/testdata/disaster-recovery/ssh-bastion/namespace.yaml b/test/extended/testdata/disaster-recovery/ssh-bastion/namespace.yaml deleted file mode 100644 index 41fe6775c02c..000000000000 --- a/test/extended/testdata/disaster-recovery/ssh-bastion/namespace.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: ssh-bastion - labels: - openshift.io/run-level: "0" - diff --git a/test/extended/testdata/disaster-recovery/ssh-bastion/role.yaml b/test/extended/testdata/disaster-recovery/ssh-bastion/role.yaml deleted file mode 100644 index 825d93b554ac..000000000000 --- a/test/extended/testdata/disaster-recovery/ssh-bastion/role.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: ssh-bastion - namespace: ssh-bastion -rules: -- apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - verbs: - - use - resourceNames: - - privileged diff --git a/test/extended/testdata/disaster-recovery/ssh-bastion/rolebinding.yaml b/test/extended/testdata/disaster-recovery/ssh-bastion/rolebinding.yaml deleted file mode 100644 index ba2e2f2b4bdb..000000000000 --- a/test/extended/testdata/disaster-recovery/ssh-bastion/rolebinding.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - annotations: - openshift.io/description: Allows ssh-pod to run as root - name: ssh-bastion - namespace: ssh-bastion -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: ssh-bastion -subjects: -- apiGroup: rbac.authorization.k8s.io - kind: User - name: system:serviceaccount:ssh-bastion:ssh-bastion diff --git a/test/extended/testdata/disaster-recovery/ssh-bastion/service.yaml b/test/extended/testdata/disaster-recovery/ssh-bastion/service.yaml deleted file mode 100644 index 63fb71775799..000000000000 --- a/test/extended/testdata/disaster-recovery/ssh-bastion/service.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - run: ssh-bastion - name: ssh-bastion - namespace: ssh-bastion -spec: - externalTrafficPolicy: Local - ports: - - name: ssh - port: 22 - protocol: TCP - targetPort: ssh - selector: - run: ssh-bastion - type: LoadBalancer diff --git a/test/extended/testdata/disaster-recovery/ssh-bastion/serviceaccount.yaml b/test/extended/testdata/disaster-recovery/ssh-bastion/serviceaccount.yaml deleted file mode 100644 index 729a2330c7e3..000000000000 --- a/test/extended/testdata/disaster-recovery/ssh-bastion/serviceaccount.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: ssh-bastion - namespace: ssh-bastion diff --git a/test/extended/testdata/disaster-recovery/ssh-bastion/sshd_config b/test/extended/testdata/disaster-recovery/ssh-bastion/sshd_config deleted file mode 100644 index 1f1b17167049..000000000000 --- a/test/extended/testdata/disaster-recovery/ssh-bastion/sshd_config +++ /dev/null @@ -1,18 +0,0 @@ -HostKey /etc/ssh/ssh_host_rsa_key -HostKey /etc/ssh/ssh_host_ecdsa_key -HostKey /etc/ssh/ssh_host_ed25519_key -SyslogFacility AUTHPRIV -PermitRootLogin no -AuthorizedKeysFile /home/core/.ssh/authorized_keys -PasswordAuthentication no -ChallengeResponseAuthentication no -GSSAPIAuthentication yes -GSSAPICleanupCredentials no -UsePAM yes -X11Forwarding yes -PrintMotd no -AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES -AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT -AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE -AcceptEnv XMODIFIERS -Subsystem sftp /usr/libexec/openssh/sftp-server diff --git a/test/extended/testdata/disaster-recovery/update_route_53.py b/test/extended/testdata/disaster-recovery/update_route_53.py deleted file mode 100644 index a549aee25c5a..000000000000 --- a/test/extended/testdata/disaster-recovery/update_route_53.py +++ /dev/null @@ -1,46 +0,0 @@ -import boto3 -import os -import sys -from time import sleep - -if len(sys.argv) < 4: - print("Usage: ./update_route_53.py ") - sys.exit(1) - -attempts = 10 -pause = 10 - -domain = sys.argv[1] -record = sys.argv[2] -ip = sys.argv[3] -print("record: %s" % record) -print("ip: %s" % ip) - -client = boto3.client('route53') -r = client.list_hosted_zones_by_name(DNSName=domain, MaxItems="1") -zone_id = r['HostedZones'][0]['Id'].split('/')[-1] - -response = client.change_resource_record_sets( - HostedZoneId=zone_id, - ChangeBatch= { - 'Comment': 'add %s -> %s' % (record, ip), - 'Changes': [ - { - 'Action': 'UPSERT', - 'ResourceRecordSet': { - 'Name': record, - 'Type': 'A', - 'TTL': 60, - 'ResourceRecords': [{'Value': ip}] - } - }] -}) -for i in range(attempts): - print('response: %s' % response) - changeID = response['ChangeInfo']['Id'] - if response['ChangeInfo']['Status'] == "INSYNC": - print('insync found, response: %s' % response) - break - print('waiting for response to complete') - sleep(pause) - response = client.get_change(Id=changeID) diff --git a/test/extended/testdata/image/test-image.json b/test/extended/testdata/image/test-image.json index 90386e06c3fd..4966c068a305 100644 --- a/test/extended/testdata/image/test-image.json +++ b/test/extended/testdata/image/test-image.json @@ -13,5 +13,6 @@ "ContainerConfig": {}, "Config": {} }, + "dockerImageLayers": [], "dockerImageMetadataVersion": "1.0" } diff --git a/test/extended/testdata/imagestream-jenkins-slave-pods.yaml b/test/extended/testdata/imagestream-jenkins-slave-pods.yaml index 560ffc778e51..e52f393769b7 100644 --- a/test/extended/testdata/imagestream-jenkins-slave-pods.yaml +++ b/test/extended/testdata/imagestream-jenkins-slave-pods.yaml @@ -7,8 +7,9 @@ metadata: spec: tags: - from: - kind: DockerImage - name: docker.io/openshift/jenkins-slave-maven-centos7:latest + kind: ImageStreamTag + name: jenkins-agent-maven:latest + namespace: openshift name: base - from: kind: ImageStreamTag diff --git a/test/extended/testdata/imagestreamtag-jenkins-slave-pods.yaml b/test/extended/testdata/imagestreamtag-jenkins-slave-pods.yaml index 6d9697f7e093..51d9ed124f3d 100644 --- a/test/extended/testdata/imagestreamtag-jenkins-slave-pods.yaml +++ b/test/extended/testdata/imagestreamtag-jenkins-slave-pods.yaml @@ -5,8 +5,9 @@ metadata: spec: tags: - from: - kind: DockerImage - name: quay.io/openshift/origin-jenkins-agent-maven:latest + kind: ImageStreamTag + name: jenkins-agent-maven:latest + namespace: openshift name: base - annotations: role: jenkins-slave diff --git a/test/extended/testdata/jobs/v1.yaml b/test/extended/testdata/jobs/v1.yaml index 51ab23652802..604940de3dc8 100644 --- a/test/extended/testdata/jobs/v1.yaml +++ b/test/extended/testdata/jobs/v1.yaml @@ -11,6 +11,6 @@ spec: spec: containers: - name: simplev1 - image: docker.io/busybox + image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest command: ["/bin/sh", "-c", "exit 0"] restartPolicy: Never diff --git a/test/extended/testdata/ldap/groupsync.sh b/test/extended/testdata/ldap/groupsync.sh new file mode 100644 index 000000000000..b2f0c0aec35f --- /dev/null +++ b/test/extended/testdata/ldap/groupsync.sh @@ -0,0 +1,202 @@ +#!/bin/bash +# +# This scripts starts the OpenShift server with a default configuration. +# The OpenShift Docker registry and router are installed. +# It will run all tests that are imported into test/extended. +source "/usr/hack/lib/init.sh" +os::util::environment::setup_time_vars +os::build::setup_env + +export KUBECONFIG="${ADMIN_KUBECONFIG}" +LDAP_SERVICE_IP="${LDAP_SERVICE}" + +function cleanup() { + return_code=$? + os::test::junit::generate_report + os::cleanup::all + os::util::describe_return_code "${return_code}" + exit "${return_code}" +} +trap "cleanup" EXIT + +function compare_and_cleanup() { + validation_file=$1 + actual_file=actual-${validation_file} + rm -f ${WORKINGDIR}/${actual_file} + oc get groups --no-headers | awk '{print $1}' | sort | xargs -I{} oc get --export group {} -o yaml >> ${WORKINGDIR}/${actual_file} + os::util::sed '/sync-time/d' ${WORKINGDIR}/${actual_file} + diff ${validation_file} ${WORKINGDIR}/${actual_file} + oc delete groups --all + echo -e "\tSUCCESS" +} + +os::log::info "Running extended tests" + +schema=('rfc2307' 'ad' 'augmented-ad') + +for (( i=0; i<${#schema[@]}; i++ )); do + current_schema=${schema[$i]} + os::log::info "Testing schema: ${current_schema}" + os::test::junit::declare_suite_start "extended/ldap-groups/${current_schema}" + + WORKINGDIR=${BASETMPDIR}/${current_schema} + mkdir ${WORKINGDIR} + + os::log::info "working dir ${WORKINGDIR}" + # create a temp copy of the test files + cp /tmp/ldap/${current_schema}/* ${WORKINGDIR} + pushd ${WORKINGDIR} > /dev/null + + # load OpenShift and LDAP group UIDs, needed for literal whitelists + # use awk instead of sed for compatibility (see os::util::sed) + group1_ldapuid=$(awk 'NR == 1 {print $0}' ldapgroupuids.txt) + group2_ldapuid=$(awk 'NR == 2 {print $0}' ldapgroupuids.txt) + group3_ldapuid=$(awk 'NR == 3 {print $0}' ldapgroupuids.txt) + + group1_osuid=$(awk 'NR == 1 {print $0}' osgroupuids.txt) + group2_osuid=$(awk 'NR == 2 {print $0}' osgroupuids.txt) + group3_osuid=$(awk 'NR == 3 {print $0}' osgroupuids.txt) + + # update sync-configs and validation files with the LDAP server's IP + config_files=sync-config*.yaml + validation_files=valid*.yaml + for config in ${config_files} ${validation_files} + do + os::util::sed "s/LDAP_SERVICE_IP/${LDAP_SERVICE_IP}/g" ${config} + os::util::sed "s@LDAP_CA@${LDAP_CA}@g" ${config} + done + + echo -e "\tTEST: Sync all LDAP groups from LDAP server" + oc adm groups sync --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_all_ldap_sync.yaml + + + # WHITELISTS + echo -e "\tTEST: Sync subset of LDAP groups from LDAP server using whitelist file" + oc adm groups sync --whitelist=whitelist_ldap.txt --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_whitelist_sync.yaml + + echo -e "\tTEST: Sync subset of LDAP groups from LDAP server using literal whitelist" + oc adm groups sync ${group1_ldapuid} --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_whitelist_sync.yaml + + echo -e "\tTEST: Sync subset of LDAP groups from LDAP server using union of literal whitelist and whitelist file" + oc adm groups sync ${group2_ldapuid} --whitelist=whitelist_ldap.txt --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_whitelist_union_sync.yaml + + echo -e "\tTEST: Sync subset of OpenShift groups from LDAP server using whitelist file" + oc adm groups sync ${group1_ldapuid} --sync-config=sync-config.yaml --confirm + oc patch group ${group1_osuid} -p 'users: []' + oc adm groups sync --type=openshift --whitelist=whitelist_openshift.txt --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_whitelist_sync.yaml + + echo -e "\tTEST: Sync subset of OpenShift groups from LDAP server using literal whitelist" + # sync group from LDAP + oc adm groups sync ${group1_ldapuid} --sync-config=sync-config.yaml --confirm + oc patch group ${group1_osuid} -p 'users: []' + oc adm groups sync --type=openshift ${group1_osuid} --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_whitelist_sync.yaml + + echo -e "\tTEST: Sync subset of OpenShift groups from LDAP server using union of literal whitelist and whitelist file" + # sync groups from LDAP + oc adm groups sync ${group1_ldapuid} ${group2_ldapuid} --sync-config=sync-config.yaml --confirm + oc patch group ${group1_osuid} -p 'users: []' + oc patch group ${group2_osuid} -p 'users: []' + oc adm groups sync --type=openshift group/${group2_osuid} --whitelist=whitelist_openshift.txt --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_whitelist_union_sync.yaml + + + # BLACKLISTS + echo -e "\tTEST: Sync subset of LDAP groups from LDAP server using whitelist and blacklist file" + # oc adm groups sync --whitelist=ldapgroupuids.txt --blacklist=blacklist_ldap.txt --blacklist-group="${group1_ldapuid}" --sync-config=sync-config.yaml --confirm + oc adm groups sync --whitelist=ldapgroupuids.txt --blacklist=blacklist_ldap.txt --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_all_blacklist_sync.yaml + + echo -e "\tTEST: Sync subset of LDAP groups from LDAP server using blacklist" + # oc adm groups sync --blacklist=blacklist_ldap.txt --blacklist-group=${group1_ldapuid} --sync-config=sync-config.yaml --confirm + oc adm groups sync --blacklist=blacklist_ldap.txt --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_all_blacklist_sync.yaml + + echo -e "\tTEST: Sync subset of OpenShift groups from LDAP server using whitelist and blacklist file" + oc adm groups sync --sync-config=sync-config.yaml --confirm + oc get group -o name --no-headers | xargs -n 1 oc patch -p 'users: []' + # oc adm groups sync --type=openshift --whitelist=osgroupuids.txt --blacklist=blacklist_openshift.txt --blacklist-group=${group1_osuid} --sync-config=sync-config.yaml --confirm + oc adm groups sync --type=openshift --whitelist=osgroupuids.txt --blacklist=blacklist_openshift.txt --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_all_openshift_blacklist_sync.yaml + + + # MAPPINGS + echo -e "\tTEST: Sync all LDAP groups from LDAP server using a user-defined mapping" + oc adm groups sync --sync-config=sync-config-user-defined.yaml --confirm + compare_and_cleanup valid_all_ldap_sync_user_defined.yaml + + echo -e "\tTEST: Sync all LDAP groups from LDAP server using a partially user-defined mapping" + oc adm groups sync --sync-config=sync-config-partially-user-defined.yaml --confirm + compare_and_cleanup valid_all_ldap_sync_partially_user_defined.yaml + + echo -e "\tTEST: Sync based on OpenShift groups respecting OpenShift mappings" + oc adm groups sync --sync-config=sync-config-user-defined.yaml --confirm + oc get group -o name --no-headers | xargs -n 1 oc patch -p 'users: []' + oc adm groups sync --type=openshift --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_all_ldap_sync_user_defined.yaml + + echo -e "\tTEST: Sync all LDAP groups from LDAP server using DN as attribute whenever possible" + oc adm groups sync --sync-config=sync-config-dn-everywhere.yaml --confirm + compare_and_cleanup valid_all_ldap_sync_dn_everywhere.yaml + + echo -e "\tTEST: Sync based on OpenShift groups respecting OpenShift mappings and whitelist file" + os::cmd::expect_success_and_text 'oc adm groups sync --whitelist=ldapgroupuids.txt --sync-config=sync-config-user-defined.yaml --confirm' 'group/' + os::cmd::expect_success_and_text 'oc get group -o jsonpath={.items[*].metadata.name}' 'firstgroup secondgroup thirdgroup' + os::cmd::expect_success_and_text 'oc adm groups sync --type=openshift --whitelist=ldapgroupuids.txt --sync-config=sync-config-user-defined.yaml --confirm' 'group/' + os::cmd::expect_success_and_text 'oc get group -o jsonpath={.items[*].metadata.name}' 'firstgroup secondgroup thirdgroup' + os::cmd::expect_success_and_text 'oc delete groups --all' 'deleted' + os::cmd::expect_success_and_text 'oc get group -o jsonpath={.items[*].metadata.name} | wc -l' '0' + + # PRUNING + echo -e "\tTEST: Sync all LDAP groups from LDAP server, change LDAP UID, then prune OpenShift groups" + oc adm groups sync --sync-config=sync-config.yaml --confirm + oc patch group ${group2_osuid} -p "{\"metadata\":{\"annotations\":{\"openshift.io/ldap.uid\":\"cn=garbage,${group2_ldapuid}\"}}}" + oc adm groups prune --sync-config=sync-config.yaml --confirm + compare_and_cleanup valid_all_ldap_sync_prune.yaml + + echo -e "\tTEST: Sync all LDAP groups from LDAP server using whitelist file, then prune OpenShift groups using the same whitelist file" + os::cmd::expect_success_and_text 'oc adm groups sync --whitelist=ldapgroupuids.txt --sync-config=sync-config-user-defined.yaml --confirm' 'group/' + os::cmd::expect_success_and_text 'oc get group -o jsonpath={.items[*].metadata.name}' 'firstgroup secondgroup thirdgroup' + os::cmd::expect_success_and_text 'oc adm groups prune --whitelist=ldapgroupuids.txt --sync-config=sync-config-user-defined.yaml --confirm | wc -l' '0' + os::cmd::expect_success_and_text 'oc get group -o jsonpath={.items[*].metadata.name}' 'firstgroup secondgroup thirdgroup' + os::cmd::expect_success_and_text 'oc patch group secondgroup -p "{\"metadata\":{\"annotations\":{\"openshift.io/ldap.uid\":\"cn=garbage\"}}}"' 'group.user.openshift.io/secondgroup patched' + os::cmd::expect_success_and_text 'oc adm groups prune --whitelist=ldapgroupuids.txt --sync-config=sync-config-user-defined.yaml --confirm' 'group/secondgroup' + os::cmd::expect_success_and_text 'oc get group -o jsonpath={.items[*].metadata.name}' 'firstgroup thirdgroup' + os::cmd::expect_success_and_text 'oc delete groups --all' 'deleted' + os::cmd::expect_success_and_text 'oc get group -o jsonpath={.items[*].metadata.name} | wc -l' '0' + + + # PAGING + echo -e "\tTEST: Sync all LDAP groups from LDAP server using paged queries" + oc adm groups sync --sync-config=sync-config-paging.yaml --confirm + compare_and_cleanup valid_all_ldap_sync.yaml + + + os::test::junit::declare_suite_end + popd > /dev/null +done + +# special test for RFC2307 +pushd ${BASETMPDIR}/rfc2307 > /dev/null +echo -e "\tTEST: Sync groups from LDAP server, tolerating errors" +oc adm groups sync --sync-config=sync-config-tolerating.yaml --confirm 2>"${LOG_DIR}/tolerated-output.txt" +grep 'For group "cn=group1,ou=groups,ou=incomplete\-rfc2307,dc=example,dc=com", ignoring member "cn=INVALID,ou=people,ou=rfc2307,dc=example,dc=com"' "${LOG_DIR}/tolerated-output.txt" +grep 'For group "cn=group2,ou=groups,ou=incomplete\-rfc2307,dc=example,dc=com", ignoring member "cn=OUTOFSCOPE,ou=people,ou=OUTOFSCOPE,dc=example,dc=com"' "${LOG_DIR}/tolerated-output.txt" +grep 'For group "cn=group3,ou=groups,ou=incomplete\-rfc2307,dc=example,dc=com", ignoring member "cn=INVALID,ou=people,ou=rfc2307,dc=example,dc=com"' "${LOG_DIR}/tolerated-output.txt" +grep 'For group "cn=group3,ou=groups,ou=incomplete\-rfc2307,dc=example,dc=com", ignoring member "cn=OUTOFSCOPE,ou=people,ou=OUTOFSCOPE,dc=example,dc=com"' "${LOG_DIR}/tolerated-output.txt" +compare_and_cleanup valid_all_ldap_sync_tolerating.yaml +popd > /dev/null + +# special test for augmented-ad +pushd ${BASETMPDIR}/augmented-ad > /dev/null +echo -e "\tTEST: Sync all LDAP groups from LDAP server, remove LDAP group metadata entry, then prune OpenShift groups" +oc adm groups sync --sync-config=sync-config.yaml --confirm +ldapdelete -x -h $LDAP_SERVICE_IP -p 389 -D cn=Manager,dc=example,dc=com -w admin "${group1_ldapuid}" +oc adm groups prune --sync-config=sync-config.yaml --confirm +compare_and_cleanup valid_all_ldap_sync_delete_prune.yaml +popd > /dev/null \ No newline at end of file diff --git a/test/extended/testdata/long_names/fixture.json b/test/extended/testdata/long_names/fixture.json index d3a35eefd312..efd3d23b10e9 100644 --- a/test/extended/testdata/long_names/fixture.json +++ b/test/extended/testdata/long_names/fixture.json @@ -17,7 +17,7 @@ "source": { "type": "Git", "git": { - "uri": "git://github.com/openshift/ruby-hello-world.git" + "uri": "https://github.com/openshift/ruby-hello-world.git" } }, "strategy": { @@ -46,7 +46,7 @@ "source": { "type": "Git", "git": { - "uri": "git://github.com/openshift/ruby-hello-world.git" + "uri": "https://github.com/openshift/ruby-hello-world.git" } }, "strategy": { diff --git a/test/extended/testdata/roles/policy-clusterroles.yaml b/test/extended/testdata/roles/policy-clusterroles.yaml index ae5e28cfe3de..8cd97e4b2e23 100644 --- a/test/extended/testdata/roles/policy-clusterroles.yaml +++ b/test/extended/testdata/roles/policy-clusterroles.yaml @@ -1,12 +1,24 @@ +kind: Template apiVersion: v1 -items: -- apiVersion: v1 +metadata: + name: "policy-roles-template" +labels: + createdBy: "policy-roles-template" +parameters: + - description: "The name for the cluster role." + name: ROLE_NAME + required: true + - description: "The name for the cluster role binding." + name: BINDING_NAME + required: true +objects: +- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - creationTimestamp: null - name: basic-user2 + name: ${ROLE_NAME} rules: - - apiGroups: null + - apiGroups: + - "" attributeRestrictions: null resourceNames: - "~" @@ -14,20 +26,23 @@ items: - users verbs: - get - - apiGroups: null + - apiGroups: + - project.openshift.io attributeRestrictions: null resources: - projectrequests verbs: - list - - apiGroups: null + - apiGroups: + - rbac.authorization.k8s.io attributeRestrictions: null resources: - clusterroles verbs: - get - list - - apiGroups: null + - apiGroups: + - project.openshift.io attributeRestrictions: null resources: - projects @@ -40,18 +55,15 @@ items: - selfsubjectaccessreviews verbs: - create -- apiVersion: v1 - groupNames: - - system:authenticated +- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - creationTimestamp: null - name: basic-users2 + name: ${BINDING_NAME} roleRef: - name: basic-user2 + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: ${ROLE_NAME} subjects: - - kind: SystemGroup + - apiGroup: rbac.authorization.k8s.io + kind: Group name: system:authenticated - userNames: null -kind: List -metadata: {} diff --git a/test/extended/testdata/roles/policy-roles.yaml b/test/extended/testdata/roles/policy-roles.yaml index 7ea9c2c87185..5b013337e3f2 100644 --- a/test/extended/testdata/roles/policy-roles.yaml +++ b/test/extended/testdata/roles/policy-roles.yaml @@ -9,13 +9,13 @@ parameters: name: NAMESPACE required: true objects: - - apiVersion: v1 + - apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - creationTimestamp: null name: basic-user rules: - - apiGroups: null + - apiGroups: + - "" attributeRestrictions: null resourceNames: - "~" @@ -23,20 +23,23 @@ objects: - users verbs: - get - - apiGroups: null + - apiGroups: + - project.openshift.io attributeRestrictions: null resources: - projectrequests verbs: - list - - apiGroups: null + - apiGroups: + - rbac.authorization.k8s.io attributeRestrictions: null resources: - clusterroles verbs: - get - list - - apiGroups: null + - apiGroups: + - project.openshift.io attributeRestrictions: null resources: - projects @@ -49,17 +52,19 @@ objects: - selfsubjectaccessreviews verbs: - create - - apiVersion: v1 + - apiVersion: rbac.authorization.k8s.io/v1 groupNames: - system:authenticated kind: RoleBinding metadata: - creationTimestamp: null + namespace: ${NAMESPACE} name: basic-users roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role name: basic-user - namespace: ${NAMESPACE} subjects: - - kind: SystemGroup + - apiGroup: rbac.authorization.k8s.io + kind: Group name: system:authenticated userNames: null diff --git a/test/extended/testdata/router/ingress.yaml b/test/extended/testdata/router/ingress.yaml index 8f8ca483971e..94205b964e86 100644 --- a/test/extended/testdata/router/ingress.yaml +++ b/test/extended/testdata/router/ingress.yaml @@ -79,7 +79,8 @@ items: terminationGracePeriodSeconds: 1 containers: - name: test - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] ports: - containerPort: 8080 name: http @@ -96,7 +97,8 @@ items: terminationGracePeriodSeconds: 1 containers: - name: test - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] ports: - containerPort: 8080 name: http diff --git a/test/extended/testdata/router/reencrypt-serving-cert.yaml b/test/extended/testdata/router/reencrypt-serving-cert.yaml index cb8fa49af6f5..a433b4378cf1 100644 --- a/test/extended/testdata/router/reencrypt-serving-cert.yaml +++ b/test/extended/testdata/router/reencrypt-serving-cert.yaml @@ -9,7 +9,7 @@ items: app: serving-cert spec: containers: - - image: nginx:1.15.3 + - image: docker.io/library/nginx:1.15-alpine name: serve command: - /usr/sbin/nginx diff --git a/test/extended/testdata/router/router-common.yaml b/test/extended/testdata/router/router-common.yaml index 198449377c15..0c6c3550aef1 100644 --- a/test/extended/testdata/router/router-common.yaml +++ b/test/extended/testdata/router/router-common.yaml @@ -99,8 +99,8 @@ objects: terminationGracePeriodSeconds: 1 containers: - name: test - image: openshift/hello-openshift - # image: openshift/deployment-example:v1 + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] ports: - containerPort: 8080 name: http diff --git a/test/extended/testdata/router/router-config-manager.yaml b/test/extended/testdata/router/router-config-manager.yaml index 4f47ca4084c1..2d88d4886a69 100644 --- a/test/extended/testdata/router/router-config-manager.yaml +++ b/test/extended/testdata/router/router-config-manager.yaml @@ -136,7 +136,8 @@ objects: terminationGracePeriodSeconds: 1 containers: - name: test - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] ports: - containerPort: 8080 name: http @@ -150,7 +151,7 @@ objects: app: secure-endpoint spec: containers: - - image: nginx:1.15.3 + - image: docker.io/library/nginx:1.15-alpine name: serve command: - /usr/sbin/nginx diff --git a/test/extended/testdata/router/router-http-echo-server.yaml b/test/extended/testdata/router/router-http-echo-server.yaml index ad793cb92bc4..eb7e9401a97b 100644 --- a/test/extended/testdata/router/router-http-echo-server.yaml +++ b/test/extended/testdata/router/router-http-echo-server.yaml @@ -20,7 +20,7 @@ items: deploymentconfig: router-http-echo spec: containers: - - image: openshift/origin-node + - image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest name: router-http-echo command: - /usr/bin/socat diff --git a/test/extended/testdata/router/router-metrics.yaml b/test/extended/testdata/router/router-metrics.yaml index 7db21a010d39..e82e8220622e 100644 --- a/test/extended/testdata/router/router-metrics.yaml +++ b/test/extended/testdata/router/router-metrics.yaml @@ -19,8 +19,8 @@ items: - name: weightedendpoints2 kind: Service weight: 50 - ports: - - targetPort: 8080 + port: + targetPort: 8080 # a route that has multiple services but all weights are zero - apiVersion: v1 @@ -40,8 +40,8 @@ items: - name: weightedendpoints2 kind: Service weight: 0 - ports: - - targetPort: 8080 + port: + targetPort: 8080 # two services that can be routed to - apiVersion: v1 @@ -80,7 +80,8 @@ items: terminationGracePeriodSeconds: 1 containers: - name: test - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] ports: - containerPort: 8080 name: http @@ -97,7 +98,8 @@ items: terminationGracePeriodSeconds: 1 containers: - name: test - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] ports: - containerPort: 8080 name: http diff --git a/test/extended/testdata/router/weighted-router.yaml b/test/extended/testdata/router/weighted-router.yaml index 6a0c1ddfffa9..d29aea59e9bd 100644 --- a/test/extended/testdata/router/weighted-router.yaml +++ b/test/extended/testdata/router/weighted-router.yaml @@ -122,7 +122,8 @@ objects: terminationGracePeriodSeconds: 1 containers: - name: test - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] ports: - containerPort: 8080 name: http @@ -139,7 +140,8 @@ objects: terminationGracePeriodSeconds: 1 containers: - name: test - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] ports: - containerPort: 8080 name: http @@ -156,7 +158,8 @@ objects: terminationGracePeriodSeconds: 1 containers: - name: test - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 + args: ["netexec"] ports: - containerPort: 8080 name: http diff --git a/test/extended/testdata/cmd/test/cmd/testdata/stable-busybox.yaml b/test/extended/testdata/stable-busybox.yaml similarity index 99% rename from test/extended/testdata/cmd/test/cmd/testdata/stable-busybox.yaml rename to test/extended/testdata/stable-busybox.yaml index dc754da74d6f..6bcfa398a3cc 100644 --- a/test/extended/testdata/cmd/test/cmd/testdata/stable-busybox.yaml +++ b/test/extended/testdata/stable-busybox.yaml @@ -30,6 +30,7 @@ items: ] } dockerImageManifestMediaType: application/vnd.docker.distribution.manifest.v2+json + dockerImageLayers: [] dockerImageMetadata: Architecture: amd64 Config: diff --git a/test/extended/testdata/templates/templateinstance_badobject.yaml b/test/extended/testdata/templates/templateinstance_badobject.yaml index 31766824cbd4..f7fb93cdccdc 100644 --- a/test/extended/testdata/templates/templateinstance_badobject.yaml +++ b/test/extended/testdata/templates/templateinstance_badobject.yaml @@ -28,4 +28,4 @@ items: spec: containers: - name: hello-openshift - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 diff --git a/test/extended/testdata/templates/templateinstance_objectkinds.yaml b/test/extended/testdata/templates/templateinstance_objectkinds.yaml index e96055807fca..9db1c8294e14 100644 --- a/test/extended/testdata/templates/templateinstance_objectkinds.yaml +++ b/test/extended/testdata/templates/templateinstance_objectkinds.yaml @@ -40,7 +40,7 @@ items: spec: containers: - name: hello-openshift - image: openshift/hello-openshift + image: k8s.gcr.io/e2e-test-images/agnhost:2.20 - kind: Route apiVersion: v1 metadata: diff --git a/test/extended/testdata/test-cli-debug.yaml b/test/extended/testdata/test-cli-debug.yaml index 86a5b35f10ec..82436082bfd5 100644 --- a/test/extended/testdata/test-cli-debug.yaml +++ b/test/extended/testdata/test-cli-debug.yaml @@ -15,7 +15,7 @@ items: type: Docker source: type: Git - dockerfile: "FROM busybox:latest\n" + dockerfile: "FROM image-registry.openshift-image-registry.svc:5000/openshift/tools:latest\n" output: to: kind: ImageStreamTag @@ -94,7 +94,7 @@ items: spec: containers: - name: busybox - image: busybox + image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest - kind: DeploymentConfig apiVersion: v1 @@ -111,7 +111,7 @@ items: spec: containers: - name: busybox - image: busybox + image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest command: - foo - bar diff --git a/test/integration/testdata/test-deployment-config.yaml b/test/extended/testdata/test-deployment-config.yaml similarity index 90% rename from test/integration/testdata/test-deployment-config.yaml rename to test/extended/testdata/test-deployment-config.yaml index ce3436dc507b..2db724722da0 100644 --- a/test/integration/testdata/test-deployment-config.yaml +++ b/test/extended/testdata/test-deployment-config.yaml @@ -23,7 +23,7 @@ spec: name: test-deployment spec: containers: - - image: openshift/origin-pod + - image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest imagePullPolicy: IfNotPresent name: ruby-helloworld ports: @@ -40,4 +40,3 @@ spec: name: vol1 triggers: - type: ConfigChange -status: {} diff --git a/test/extended/testdata/test-env-pod.json b/test/extended/testdata/test-env-pod.json index 766767a7ddc4..6f4f34d2d8be 100644 --- a/test/extended/testdata/test-env-pod.json +++ b/test/extended/testdata/test-env-pod.json @@ -11,7 +11,7 @@ "containers":[ { "name":"test", - "image":"centos:centos7", + "image":"image-registry.openshift-image-registry.svc:5000/openshift/tools:latest", "env": [ { "name":"podname", diff --git a/test/integration/testdata/test-replication-controller.yaml b/test/extended/testdata/test-replication-controller.yaml similarity index 89% rename from test/integration/testdata/test-replication-controller.yaml rename to test/extended/testdata/test-replication-controller.yaml index 4172877ce01d..fe5da07f9374 100644 --- a/test/integration/testdata/test-replication-controller.yaml +++ b/test/extended/testdata/test-replication-controller.yaml @@ -19,7 +19,7 @@ spec: deploymentconfig: test-deployment spec: containers: - - image: openshift/origin-pod + - image: image-registry.openshift-image-registry.svc:5000/openshift/tools:latest imagePullPolicy: IfNotPresent name: ruby-helloworld ports: diff --git a/test/extended/topology_manager/README.md b/test/extended/topology_manager/README.md index d72efedc6d1a..cd91c4c7e7d6 100644 --- a/test/extended/topology_manager/README.md +++ b/test/extended/topology_manager/README.md @@ -47,3 +47,9 @@ Use this variable to set the SRIOV network to join to exercise the connectivity. The testsuite runs a basic connectivity test to ensure the NUMA-aligned devices are functional. Use this variable to set the IP family to use for the test: "v4" or "v6". Default is "v4". + +### `NETWORK_CHECK_IMAGE` + +The testsuite runs a basic connectivity test to ensure the NUMA-aligned devices are functional. +Use this variable to set the image URL to use to check the network is working between pods which requested, and got, aligned resources. +If this value is not set (default), the connectivity test will skip. diff --git a/test/extended/topology_manager/utils.go b/test/extended/topology_manager/utils.go index fc99a23270d9..96b306d4f00e 100644 --- a/test/extended/topology_manager/utils.go +++ b/test/extended/topology_manager/utils.go @@ -13,9 +13,9 @@ import ( "time" exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/wait" clientset "k8s.io/client-go/kubernetes" @@ -28,6 +28,7 @@ import ( ) const ( + networkCheckImageEnvVar = "NETWORK_CHECK_IMAGE" strictCheckEnvVar = "TOPOLOGY_MANAGER_TEST_STRICT" roleWorkerEnvVar = "ROLE_WORKER" resourceNameEnvVar = "RESOURCE_NAME" @@ -40,9 +41,6 @@ const ( // no default for sriovNetworkNamespace: use the e2e test framework default defaultSriovNetwork = "sriov-network" defaultIPFamily = "v4" - - namespaceMachineConfigOperator = "openshift-machine-config-operator" - containerMachineConfigDaemon = "machine-config-daemon" ) const ( @@ -86,6 +84,18 @@ func findNodeWithMultiNuma(nodes []corev1.Node, c clientset.Interface, oc *exuti return nil, 0 } +func filterNodesWithMachineConfigDaemon(workerNodes []corev1.Node, client clientset.Interface) []corev1.Node { + var mcdEnabledNodes []corev1.Node + for _, node := range workerNodes { + if _, err := exutil.GetMachineConfigDaemonByNode(client, &node); err != nil { + e2e.Logf("MCD not running on worker node %qw", node.Name) + continue + } + mcdEnabledNodes = append(mcdEnabledNodes, node) + } + return mcdEnabledNodes +} + func filterNodeWithTopologyManagerPolicy(workerNodes []corev1.Node, client clientset.Interface, oc *exutil.CLI, policy string) []corev1.Node { ocRaw := (*oc).WithoutNamespace() @@ -118,23 +128,6 @@ func getNodeByRole(c clientset.Interface, role string) ([]corev1.Node, error) { return nodes.Items, nil } -func getMachineConfigDaemonByNode(c clientset.Interface, node *corev1.Node) (*corev1.Pod, error) { - listOptions := metav1.ListOptions{ - FieldSelector: fields.SelectorFromSet(fields.Set{"spec.nodeName": node.Name}).String(), - LabelSelector: labels.SelectorFromSet(labels.Set{"k8s-app": "machine-config-daemon"}).String(), - } - - mcds, err := c.CoreV1().Pods(namespaceMachineConfigOperator).List(context.Background(), listOptions) - if err != nil { - return nil, err - } - - if len(mcds.Items) < 1 { - return nil, fmt.Errorf("failed to get machine-config-daemon pod for the node %q", node.Name) - } - return &mcds.Items[0], nil -} - const ( sysFSNumaNodePath = "/sys/devices/system/node" ) @@ -196,27 +189,10 @@ func makeAllowedCpuListEnv(out string) string { return fmt.Sprintf("CPULIST_ALLOWED=%s\n", strings.TrimSpace(pair[1])) } -// execCommandOnMachineConfigDaemon returns the output of the command execution on the machine-config-daemon pod that runs on the specified node -func execCommandOnMachineConfigDaemon(c clientset.Interface, oc *exutil.CLI, node *corev1.Node, command []string) (string, error) { - mcd, err := getMachineConfigDaemonByNode(c, node) - if err != nil { - return "", err - } - - initialArgs := []string{ - "-n", namespaceMachineConfigOperator, - "-c", containerMachineConfigDaemon, - "--request-timeout", "30", - mcd.Name, - } - args := append(initialArgs, command...) - return oc.AsAdmin().Run("rsh").Args(args...).Output() -} - // getKubeletConfig returns KubeletConfiguration loaded from the node /etc/kubernetes/kubelet.conf func getKubeletConfig(c clientset.Interface, oc *exutil.CLI, node *corev1.Node) (*kubeletconfigv1beta1.KubeletConfiguration, error) { command := []string{"cat", path.Join("/rootfs", filePathKubeletConfig)} - kubeletData, err := execCommandOnMachineConfigDaemon(c, oc, node, command) + kubeletData, err := exutil.ExecCommandOnMachineConfigDaemon(c, oc, node, command) if err != nil { return nil, err } @@ -249,7 +225,7 @@ func parseSysfsNodeOnline(data string) (int, error) { func getNumaNodeCountFromNode(c clientset.Interface, oc *exutil.CLI, node *corev1.Node) (int, error) { command := []string{"cat", "/sys/devices/system/node/online"} - out, err := execCommandOnMachineConfigDaemon(c, oc, node, command) + out, err := exutil.ExecCommandOnMachineConfigDaemon(c, oc, node, command) if err != nil { return 0, err } @@ -276,7 +252,7 @@ func makeBusyboxPod(namespace string) *corev1.Pod { Containers: []corev1.Container{ { Name: "test", - Image: "busybox", + Image: image.ShellImage(), Command: []string{"sleep", "10h"}, }, }, diff --git a/test/extended/util/annotate/generated/zz_generated.annotations.go b/test/extended/util/annotate/generated/zz_generated.annotations.go index 4e320da08906..197ae9b014ac 100644 --- a/test/extended/util/annotate/generated/zz_generated.annotations.go +++ b/test/extended/util/annotate/generated/zz_generated.annotations.go @@ -275,6 +275,8 @@ var annotations = map[string]string{ "[Top Level] [k8s.io] [sig-node] Pods Extended [k8s.io] Pod Container Status should never report success for a pending container": "should never report success for a pending container [Suite:openshift/conformance/parallel] [Suite:k8s]", + "[Top Level] [k8s.io] [sig-node] Pods Extended [k8s.io] Pod Container lifecycle should not create extra sandbox if all containers are done": "should not create extra sandbox if all containers are done [Suite:openshift/conformance/parallel] [Suite:k8s]", + "[Top Level] [k8s.io] [sig-node] Pods Extended [k8s.io] Pods Set QOS Class should be set on Pods with matching resource requests and limits for memory and cpu [Conformance]": "should be set on Pods with matching resource requests and limits for memory and cpu [Conformance] [Suite:openshift/conformance/parallel/minimal] [Suite:k8s]", "[Top Level] [k8s.io] [sig-node] PreStop graceful pod terminated should wait until preStop hook completes the process [Flaky]": "graceful pod terminated should wait until preStop hook completes the process [Flaky] [Suite:k8s]", @@ -535,14 +537,16 @@ var annotations = map[string]string{ "[Top Level] [sig-api-machinery][Feature:APIServer][Late] API LBs follow /readyz of kube-apiserver and stop sending requests": "API LBs follow /readyz of kube-apiserver and stop sending requests [Suite:openshift/conformance/parallel]", - "[Top Level] [sig-api-machinery][Feature:APIServer][Late] kube-apiserver terminates within graceful termination period": "kube-apiserver terminates within graceful termination period [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-api-machinery][Feature:APIServer][Late] kube-apiserver terminates within graceful termination period": "kube-apiserver terminates within graceful termination period [Skipped:Disruptive] [Suite:openshift/conformance/parallel]", - "[Top Level] [sig-api-machinery][Feature:APIServer][Late] kubelet terminates kube-apiserver gracefully": "kubelet terminates kube-apiserver gracefully [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-api-machinery][Feature:APIServer][Late] kubelet terminates kube-apiserver gracefully": "kubelet terminates kube-apiserver gracefully [Skipped:Disruptive] [Suite:openshift/conformance/parallel]", "[Top Level] [sig-api-machinery][Feature:Audit] Basic audit should audit API calls": "should audit API calls [Disabled:SpecialConfig]", "[Top Level] [sig-api-machinery][Feature:ClusterResourceQuota] Cluster resource quota should control resource limits across namespaces": "should control resource limits across namespaces [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-api-machinery][Feature:ResourceQuota] Object count should properly count the number of imagestreams resources": "should properly count the number of imagestreams resources [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-api-machinery][Feature:ServerSideApply] Server-Side Apply should work for apps.openshift.io/v1, Resource=deploymentconfigs": "should work for apps.openshift.io/v1, Resource=deploymentconfigs [Suite:openshift/conformance/parallel]", "[Top Level] [sig-api-machinery][Feature:ServerSideApply] Server-Side Apply should work for build.openshift.io/v1, Resource=buildconfigs": "should work for build.openshift.io/v1, Resource=buildconfigs [Suite:openshift/conformance/parallel]", @@ -825,6 +829,8 @@ var annotations = map[string]string{ "[Top Level] [sig-arch] Managed cluster should should expose cluster services outside the cluster": "should expose cluster services outside the cluster [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-arch] [Conformance] FIPS TestFIPS": "TestFIPS [Suite:openshift/conformance/parallel/minimal]", + "[Top Level] [sig-arch] ocp payload should be based on existing source [Serial] olm version should contain the source commit id": "[Serial] olm version should contain the source commit id [Suite:openshift/conformance/serial]", "[Top Level] [sig-arch][Early] Managed cluster should start all core operators": "start all core operators [Suite:openshift/conformance/parallel]", @@ -993,6 +999,8 @@ var annotations = map[string]string{ "[Top Level] [sig-auth][Feature:SecurityContextConstraints] TestAllowedSCCViaRBAC": "TestAllowedSCCViaRBAC [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-auth][Feature:SecurityContextConstraints] TestPodDefaultCapabilities": "TestPodDefaultCapabilities [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-auth][Feature:SecurityContextConstraints] TestPodUpdateSCCEnforcement": "TestPodUpdateSCCEnforcement [Suite:openshift/conformance/parallel]", "[Top Level] [sig-auth][Feature:UserAPI] groups should work": "groups should work [Suite:openshift/conformance/parallel]", @@ -1095,7 +1103,7 @@ var annotations = map[string]string{ "[Top Level] [sig-autoscaling] [HPA] Horizontal pod autoscaling (scale resource: Custom Metrics from Stackdriver) should scale up with two metrics of type Pod from Stackdriver [Feature:CustomMetricsAutoscaling]": "should scale up with two metrics of type Pod from Stackdriver [Feature:CustomMetricsAutoscaling] [Skipped:gce] [Suite:openshift/conformance/parallel] [Suite:k8s]", - "[Top Level] [sig-builds][Feature:Builds] Multi-stage image builds should succeed": "should succeed [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-builds][Feature:Builds] Multi-stage image builds should succeed": "should succeed [Suite:openshift/conformance/parallel]", "[Top Level] [sig-builds][Feature:Builds] Optimized image builds should succeed": "should succeed [Suite:openshift/conformance/parallel]", @@ -1111,6 +1119,8 @@ var annotations = map[string]string{ "[Top Level] [sig-builds][Feature:Builds] buildconfig secret injector should inject secrets to the appropriate buildconfigs": "should inject secrets to the appropriate buildconfigs [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-builds][Feature:Builds] clone repository using git:// protocol should clone using git:// if no proxy is configured": "should clone using git:// if no proxy is configured [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-builds][Feature:Builds] custom build with buildah being created from new-build should complete build with custom builder image": "should complete build with custom builder image [Suite:openshift/conformance/parallel]", "[Top Level] [sig-builds][Feature:Builds] imagechangetriggers imagechangetriggers should trigger builds of all types": "imagechangetriggers should trigger builds of all types [Suite:openshift/conformance/parallel]", @@ -1319,9 +1329,9 @@ var annotations = map[string]string{ "[Top Level] [sig-builds][Feature:Builds][pullsecret] docker build using a pull secret Building from a template should create a docker build that pulls using a secret run it": "should create a docker build that pulls using a secret run it [Suite:openshift/conformance/parallel]", - "[Top Level] [sig-builds][Feature:Builds][sig-devex][Feature:Jenkins][Slow] openshift pipeline build Sync plugin tests using the ephemeral template": "using the ephemeral template", + "[Top Level] [sig-builds][Feature:Builds][sig-devex][Feature:Jenkins][Slow] openshift pipeline build Sync plugin tests using the ephemeral template": "using the ephemeral template", - "[Top Level] [sig-builds][Feature:Builds][sig-devex][Feature:Jenkins][Slow] openshift pipeline build jenkins-client-plugin tests using the ephemeral template": "using the ephemeral template", + "[Top Level] [sig-builds][Feature:Builds][sig-devex][Feature:Jenkins][Slow] openshift pipeline build jenkins-client-plugin tests using the ephemeral template": "using the ephemeral template", "[Top Level] [sig-builds][Feature:Builds][timing] capture build stages and durations should record build stages and durations for docker": "should record build stages and durations for docker [Suite:openshift/conformance/parallel]", @@ -1443,25 +1453,51 @@ var annotations = map[string]string{ "[Top Level] [sig-cli] Kubectl client Update Demo should scale a replication controller [Conformance]": "should scale a replication controller [Conformance] [Suite:openshift/conformance/parallel/minimal] [Suite:k8s]", + "[Top Level] [sig-cli] oc --request-timeout works as expected": "works as expected [Suite:openshift/conformance/parallel]", + + "[Top Level] [sig-cli] oc adm build-chain": "build-chain [Suite:openshift/conformance/parallel]", + + "[Top Level] [sig-cli] oc adm cluster-role-reapers": "cluster-role-reapers [Suite:openshift/conformance/parallel]", + + "[Top Level] [sig-cli] oc adm groups": "groups [Suite:openshift/conformance/parallel]", + + "[Top Level] [sig-cli] oc adm images": "images [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-cli] oc adm must-gather runs successfully for audit logs": "runs successfully for audit logs [Suite:openshift/conformance/parallel]", "[Top Level] [sig-cli] oc adm must-gather runs successfully with options": "runs successfully with options [Suite:openshift/conformance/parallel]", "[Top Level] [sig-cli] oc adm must-gather runs successfully": "runs successfully [Suite:openshift/conformance/parallel]", - "[Top Level] [sig-cli] oc adm oc adm node-logs --boot=0": "oc adm node-logs --boot=0 [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-cli] oc adm new-project": "new-project [Suite:openshift/conformance/parallel]", + + "[Top Level] [sig-cli] oc adm node-logs": "node-logs [Suite:openshift/conformance/parallel]", + + "[Top Level] [sig-cli] oc adm policy": "policy [Suite:openshift/conformance/parallel]", + + "[Top Level] [sig-cli] oc adm role-reapers": "role-reapers [Suite:openshift/conformance/parallel]", + + "[Top Level] [sig-cli] oc adm role-selectors": "role-selectors [Suite:openshift/conformance/parallel]", + + "[Top Level] [sig-cli] oc adm serviceaccounts": "serviceaccounts [Suite:openshift/conformance/parallel]", + + "[Top Level] [sig-cli] oc adm storage-admin": "storage-admin [Suite:openshift/conformance/parallel]", + + "[Top Level] [sig-cli] oc adm ui-project-commands": "ui-project-commands [Suite:openshift/conformance/parallel]", - "[Top Level] [sig-cli] oc adm oc adm node-logs --role=master --since=-2m": "oc adm node-logs --role=master --since=-2m [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-cli] oc adm user-creation": "user-creation [Suite:openshift/conformance/parallel]", - "[Top Level] [sig-cli] oc adm oc adm node-logs --since=-2m --until=-1m": "oc adm node-logs --since=-2m --until=-1m [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-cli] oc adm who-can": "who-can [Suite:openshift/conformance/parallel]", - "[Top Level] [sig-cli] oc adm oc adm node-logs --since= --until=-1m": "oc adm node-logs --since= --until=-1m [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-cli] oc debug deployment configs from a build": "deployment configs from a build [Suite:openshift/conformance/parallel]", - "[Top Level] [sig-cli] oc adm oc adm node-logs --tail=5": "oc adm node-logs --tail=5 [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-cli] oc debug dissect deployment config debug": "dissect deployment config debug [Suite:openshift/conformance/parallel]", - "[Top Level] [sig-cli] oc adm oc adm node-logs --unit=kubelet --since=-1m": "oc adm node-logs --unit=kubelet --since=-1m [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-cli] oc debug does not require a real resource on the server": "does not require a real resource on the server [Suite:openshift/conformance/parallel]", - "[Top Level] [sig-cli] oc adm oc adm node-logs": "oc adm node-logs [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-cli] oc debug ensure debug does not depend on a container actually existing for the selected resource": "ensure debug does not depend on a container actually existing for the selected resource [Suite:openshift/conformance/parallel]", + + "[Top Level] [sig-cli] oc debug ensure it works with image streams": "ensure it works with image streams [Suite:openshift/conformance/parallel]", "[Top Level] [sig-cli] oc explain networking types when using openshift-sdn should contain proper fields description for special networking types": "should contain proper fields description for special networking types [Suite:openshift/conformance/parallel]", @@ -1489,12 +1525,8 @@ var annotations = map[string]string{ "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/config.sh": "test/cmd/config.sh", - "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/convert.sh": "test/cmd/convert.sh", - "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/create.sh": "test/cmd/create.sh", - "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/debug.sh": "test/cmd/debug.sh", - "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/deployments.sh": "test/cmd/deployments.sh", "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/describer.sh": "test/cmd/describer.sh", @@ -1515,10 +1547,6 @@ var annotations = map[string]string{ "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/images.sh": "test/cmd/images.sh", - "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/observe.sh": "test/cmd/observe.sh", - - "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/policy-storage-admin.sh": "test/cmd/policy-storage-admin.sh", - "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/printer.sh": "test/cmd/printer.sh", "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/projects.sh": "test/cmd/projects.sh", @@ -1527,8 +1555,6 @@ var annotations = map[string]string{ "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/routes.sh": "test/cmd/routes.sh", - "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/rsync.sh": "test/cmd/rsync.sh", - "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/run.sh": "test/cmd/run.sh", "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/secrets.sh": "test/cmd/secrets.sh", @@ -1549,8 +1575,6 @@ var annotations = map[string]string{ "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/templates.sh": "test/cmd/templates.sh", - "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/timeout.sh": "test/cmd/timeout.sh", - "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/triggers.sh": "test/cmd/triggers.sh", "[Top Level] [sig-cli][Feature:LegacyCommandTests][Disruptive][Serial] test-cmd: test/cmd/volumes.sh": "test/cmd/volumes.sh", @@ -1577,19 +1601,11 @@ var annotations = map[string]string{ "[Top Level] [sig-cli][Slow] can use rsync to upload files to pods using a watch should watch for changes and rsync them": "should watch for changes and rsync them", - "[Top Level] [sig-cli][Slow] oc debug should print the container image-based container entrypoint/command": "should print the container image-based container entrypoint/command", - - "[Top Level] [sig-cli][Slow] oc debug should print the imagestream-based container entrypoint/command": "should print the imagestream-based container entrypoint/command", - - "[Top Level] [sig-cli][Slow] oc debug should print the overridden container image-based container entrypoint/command": "should print the overridden container image-based container entrypoint/command", - - "[Top Level] [sig-cli][Slow] oc debug should print the overridden imagestream-based container entrypoint/command": "should print the overridden imagestream-based container entrypoint/command", - "[Top Level] [sig-cluster-lifecycle] CSRs from machines that are not recognized by the cloud provider are not approved": "CSRs from machines that are not recognized by the cloud provider are not approved [Suite:openshift/conformance/parallel]", "[Top Level] [sig-cluster-lifecycle] Pods cannot access the /config/master API endpoint": "Pods cannot access the /config/master API endpoint [Suite:openshift/conformance/parallel]", - "[Top Level] [sig-cluster-lifecycle][Feature:DisasterRecovery][Disruptive] [Feature:NodeRecovery] Cluster should survive master and worker failure and recover with machine health checks": "[Feature:NodeRecovery] Cluster should survive master and worker failure and recover with machine health checks [Serial]", + "[Top Level] [sig-cluster-lifecycle][Feature:DisasterRecovery][Disruptive] [Feature:NodeRecovery] Cluster should survive master and worker failure and recover with machine health checks": "[Feature:NodeRecovery] Cluster should survive master and worker failure and recover with machine health checks [Serial] [Skipped:Disruptive]", "[Top Level] [sig-cluster-lifecycle][Feature:Machines] Managed cluster should have machine resources": "have machine resources [Suite:openshift/conformance/parallel]", @@ -1637,6 +1653,8 @@ var annotations = map[string]string{ "[Top Level] [sig-devex][Feature:ImageEcosystem][Slow] openshift images should be SCL enabled using the SCL in s2i images \"registry.redhat.io/rhscl/ruby-27-rhel7\" should be SCL enabled": "\"registry.redhat.io/rhscl/ruby-27-rhel7\" should be SCL enabled", + "[Top Level] [sig-devex][Feature:ImageEcosystem][Slow] openshift sample application repositories [sig-devex][Feature:ImageEcosystem][nodejs] test nodejs images with nodejs-rest-http-crud db repo Building nodejs-postgresql app from new-app should build a nodejs-postgresql image and run it in a pod": "should build a nodejs-postgresql image and run it in a pod", + "[Top Level] [sig-devex][Feature:ImageEcosystem][Slow] openshift sample application repositories [sig-devex][Feature:ImageEcosystem][php] test php images with cakephp-ex db repo Building cakephp-mysql app from new-app should build a cakephp-mysql image and run it in a pod": "should build a cakephp-mysql image and run it in a pod", "[Top Level] [sig-devex][Feature:ImageEcosystem][Slow] openshift sample application repositories [sig-devex][Feature:ImageEcosystem][python] test python images with django-ex db repo Building django-psql app from new-app should build a django-psql image and run it in a pod": "should build a django-psql image and run it in a pod", @@ -1655,11 +1673,11 @@ var annotations = map[string]string{ "[Top Level] [sig-devex][Feature:ImageEcosystem][ruby][Slow] hot deploy for openshift ruby image Rails example should work with hot deploy": "should work with hot deploy", - "[Top Level] [sig-devex][Feature:JenkinsRHELImagesOnly][Slow] openshift pipeline build Sync plugin tests using the ephemeral template": "using the ephemeral template", + "[Top Level] [sig-devex][Feature:JenkinsRHELImagesOnly][Slow] openshift pipeline build Sync plugin tests using the ephemeral template": "using the ephemeral template", - "[Top Level] [sig-devex][Feature:Jenkins][Slow] Jenkins repos e2e openshift using slow openshift pipeline build Sync plugin tests using the ephemeral template": "using the ephemeral template", + "[Top Level] [sig-devex][Feature:Jenkins][Slow] Jenkins repos e2e openshift using slow openshift pipeline build Sync plugin tests using the ephemeral template": "using the ephemeral template", - "[Top Level] [sig-devex][Feature:Jenkins][Slow] Jenkins repos e2e openshift using slow openshift pipeline build Sync plugin tests using the persistent template": "using the persistent template", + "[Top Level] [sig-devex][Feature:Jenkins][Slow] Jenkins repos e2e openshift using slow openshift pipeline build Sync plugin tests using the persistent template": "using the persistent template", "[Top Level] [sig-devex][Feature:OpenShiftControllerManager] TestAutomaticCreationOfPullSecrets": "TestAutomaticCreationOfPullSecrets [Suite:openshift/conformance/parallel]", @@ -1693,12 +1711,10 @@ var annotations = map[string]string{ "[Top Level] [sig-devex][Feature:Templates] templateservicebroker security test should pass security tests": "should pass security tests [Suite:openshift/conformance/parallel]", - "[Top Level] [sig-etcd] etcd leader changes are not excessive": "leader changes are not excessive [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-etcd] etcd leader changes are not excessive [Late]": "leader changes are not excessive [Late] [Suite:openshift/conformance/parallel]", "[Top Level] [sig-etcd][Feature:DisasterRecovery][Disruptive] [Feature:EtcdRecovery] Cluster should restore itself after quorum loss": "[Feature:EtcdRecovery] Cluster should restore itself after quorum loss [Serial]", - "[Top Level] [sig-etcd][Feature:DisasterRecovery][Disruptive] [dr-etcd-snapshot] Cluster should restore itself from etcd snapshot": "[dr-etcd-snapshot] Cluster should restore itself from etcd snapshot [Serial]", - "[Top Level] [sig-imageregistry][Feature:ImageAppend] Image append should create images by appending them": "should create images by appending them [Suite:openshift/conformance/parallel]", "[Top Level] [sig-imageregistry][Feature:ImageExtract] Image extract should extract content from an image": "should extract content from an image [Suite:openshift/conformance/parallel]", @@ -1743,13 +1759,13 @@ var annotations = map[string]string{ "[Top Level] [sig-imageregistry][Feature:ImageQuota][Serial][Suite:openshift/registry/serial] Image limit range should deny an import of a repository exceeding limit on openshift.io/image-tags resource": "should deny an import of a repository exceeding limit on openshift.io/image-tags resource [Disabled:SpecialConfig]", - "[Top Level] [sig-imageregistry][Feature:ImageStreamImport][Serial][Disruptive] ImageStream API TestImportImageFromBlockedRegistry": "TestImportImageFromBlockedRegistry", + "[Top Level] [sig-imageregistry][Feature:ImageStreamImport][Serial][Slow] ImageStream API TestImportImageFromBlockedRegistry": "TestImportImageFromBlockedRegistry", - "[Top Level] [sig-imageregistry][Feature:ImageStreamImport][Serial][Disruptive] ImageStream API TestImportImageFromInsecureRegistry": "TestImportImageFromInsecureRegistry", + "[Top Level] [sig-imageregistry][Feature:ImageStreamImport][Serial][Slow] ImageStream API TestImportImageFromInsecureRegistry": "TestImportImageFromInsecureRegistry", - "[Top Level] [sig-imageregistry][Feature:ImageStreamImport][Serial][Disruptive] ImageStream API TestImportRepositoryFromBlockedRegistry": "TestImportRepositoryFromBlockedRegistry", + "[Top Level] [sig-imageregistry][Feature:ImageStreamImport][Serial][Slow] ImageStream API TestImportRepositoryFromBlockedRegistry": "TestImportRepositoryFromBlockedRegistry", - "[Top Level] [sig-imageregistry][Feature:ImageStreamImport][Serial][Disruptive] ImageStream API TestImportRepositoryFromInsecureRegistry": "TestImportRepositoryFromInsecureRegistry", + "[Top Level] [sig-imageregistry][Feature:ImageStreamImport][Serial][Slow] ImageStream API TestImportRepositoryFromInsecureRegistry": "TestImportRepositoryFromInsecureRegistry", "[Top Level] [sig-imageregistry][Feature:ImageTriggers] Annotation trigger reconciles after the image is overwritten": "reconciles after the image is overwritten [Suite:openshift/conformance/parallel]", @@ -1827,7 +1843,7 @@ var annotations = map[string]string{ "[Top Level] [sig-instrumentation] Prometheus when installed on the cluster should provide named network metrics": "should provide named network metrics [Suite:openshift/conformance/parallel]", - "[Top Level] [sig-instrumentation] Prometheus when installed on the cluster should report telemetry if a cloud.openshift.com token is present": "should report telemetry if a cloud.openshift.com token is present [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-instrumentation] Prometheus when installed on the cluster should report telemetry if a cloud.openshift.com token is present [Late]": "should report telemetry if a cloud.openshift.com token is present [Late] [Suite:openshift/conformance/parallel]", "[Top Level] [sig-instrumentation] Prometheus when installed on the cluster should start and expose a secured proxy and unsecured metrics": "should start and expose a secured proxy and unsecured metrics [Suite:openshift/conformance/parallel]", @@ -1851,7 +1867,7 @@ var annotations = map[string]string{ "[Top Level] [sig-instrumentation][Late] Alerts should have a Watchdog alert in firing state the entire cluster run": "should have a Watchdog alert in firing state the entire cluster run [Suite:openshift/conformance/parallel]", - "[Top Level] [sig-instrumentation][Late] Alerts shouldn't exceed the 500 series limit of total series sent via telemetry from each cluster": "shouldn't exceed the 500 series limit of total series sent via telemetry from each cluster [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-instrumentation][Late] Alerts shouldn't exceed the 500 series limit of total series sent via telemetry from each cluster": "shouldn't exceed the 500 series limit of total series sent via telemetry from each cluster [Skipped:Disruptive] [Suite:openshift/conformance/parallel]", "[Top Level] [sig-instrumentation][Late] Alerts shouldn't report any alerts in firing state apart from Watchdog and AlertmanagerReceiversNotConfigured": "shouldn't report any alerts in firing state apart from Watchdog and AlertmanagerReceiversNotConfigured [Suite:openshift/conformance/parallel]", @@ -1885,7 +1901,7 @@ var annotations = map[string]string{ "[Top Level] [sig-network] Conntrack should be able to preserve UDP traffic when server pod cycles for a ClusterIP service": "should be able to preserve UDP traffic when server pod cycles for a ClusterIP service [Suite:openshift/conformance/parallel] [Suite:k8s]", - "[Top Level] [sig-network] Conntrack should be able to preserve UDP traffic when server pod cycles for a NodePort service": "should be able to preserve UDP traffic when server pod cycles for a NodePort service [Skipped:Network/OVNKubernetes] [Suite:openshift/conformance/parallel] [Suite:k8s]", + "[Top Level] [sig-network] Conntrack should be able to preserve UDP traffic when server pod cycles for a NodePort service": "should be able to preserve UDP traffic when server pod cycles for a NodePort service [Suite:openshift/conformance/parallel] [Suite:k8s]", "[Top Level] [sig-network] DNS configMap federations [Feature:Federation] should be able to change federation configuration [Slow][Serial]": "should be able to change federation configuration [Slow][Serial] [Disabled:SpecialConfig] [Suite:k8s]", @@ -1993,17 +2009,17 @@ var annotations = map[string]string{ "[Top Level] [sig-network] Network should set TCP CLOSE_WAIT timeout [Privileged]": "should set TCP CLOSE_WAIT timeout [Privileged] [Disabled:Broken] [Suite:k8s]", - "[Top Level] [sig-network] NetworkPolicy [LinuxOnly] NetworkPolicy between server and client should allow egress access on one named port [Feature:NetworkPolicy]": "should allow egress access on one named port [Feature:NetworkPolicy] [Disabled:Unimplemented] [Skipped:Network/OpenShiftSDN/Multitenant] [Suite:k8s]", + "[Top Level] [sig-network] NetworkPolicy [LinuxOnly] NetworkPolicy between server and client should allow egress access on one named port [Feature:NetworkPolicy]": "should allow egress access on one named port [Feature:NetworkPolicy] [Disabled:Unimplemented] [Skipped:Network/OVNKubernetes] [Skipped:Network/OpenShiftSDN/Multitenant] [Suite:k8s]", "[Top Level] [sig-network] NetworkPolicy [LinuxOnly] NetworkPolicy between server and client should allow egress access to server in CIDR block [Feature:NetworkPolicy]": "should allow egress access to server in CIDR block [Feature:NetworkPolicy] [Disabled:Unimplemented] [Skipped:Network/OpenShiftSDN/Multitenant] [Suite:k8s]", - "[Top Level] [sig-network] NetworkPolicy [LinuxOnly] NetworkPolicy between server and client should allow ingress access from namespace on one named port [Feature:NetworkPolicy]": "should allow ingress access from namespace on one named port [Feature:NetworkPolicy] [Disabled:Unimplemented] [Skipped:Network/OpenShiftSDN/Multitenant] [Suite:k8s]", + "[Top Level] [sig-network] NetworkPolicy [LinuxOnly] NetworkPolicy between server and client should allow ingress access from namespace on one named port [Feature:NetworkPolicy]": "should allow ingress access from namespace on one named port [Feature:NetworkPolicy] [Disabled:Unimplemented] [Skipped:Network/OVNKubernetes] [Skipped:Network/OpenShiftSDN/Multitenant] [Suite:k8s]", "[Top Level] [sig-network] NetworkPolicy [LinuxOnly] NetworkPolicy between server and client should allow ingress access from updated namespace [Feature:NetworkPolicy]": "should allow ingress access from updated namespace [Feature:NetworkPolicy] [Skipped:Network/OpenShiftSDN/Multitenant] [Suite:openshift/conformance/parallel] [Suite:k8s]", "[Top Level] [sig-network] NetworkPolicy [LinuxOnly] NetworkPolicy between server and client should allow ingress access from updated pod [Feature:NetworkPolicy]": "should allow ingress access from updated pod [Feature:NetworkPolicy] [Skipped:Network/OpenShiftSDN/Multitenant] [Suite:openshift/conformance/parallel] [Suite:k8s]", - "[Top Level] [sig-network] NetworkPolicy [LinuxOnly] NetworkPolicy between server and client should allow ingress access on one named port [Feature:NetworkPolicy]": "should allow ingress access on one named port [Feature:NetworkPolicy] [Disabled:Broken] [Disabled:Unimplemented] [Skipped:Network/OpenShiftSDN/Multitenant] [Suite:k8s]", + "[Top Level] [sig-network] NetworkPolicy [LinuxOnly] NetworkPolicy between server and client should allow ingress access on one named port [Feature:NetworkPolicy]": "should allow ingress access on one named port [Feature:NetworkPolicy] [Disabled:Broken] [Disabled:Unimplemented] [Skipped:Network/OVNKubernetes] [Skipped:Network/OpenShiftSDN/Multitenant] [Suite:k8s]", "[Top Level] [sig-network] NetworkPolicy [LinuxOnly] NetworkPolicy between server and client should deny ingress access to updated pod [Feature:NetworkPolicy]": "should deny ingress access to updated pod [Feature:NetworkPolicy] [Skipped:Network/OpenShiftSDN/Multitenant] [Suite:openshift/conformance/parallel] [Suite:k8s]", @@ -2067,19 +2083,19 @@ var annotations = map[string]string{ "[Top Level] [sig-network] Networking Granular Checks: Services should function for client IP based session affinity: udp [LinuxOnly]": "should function for client IP based session affinity: udp [LinuxOnly] [Skipped:Network/OVNKubernetes] [Suite:openshift/conformance/parallel] [Suite:k8s]", - "[Top Level] [sig-network] Networking Granular Checks: Services should function for endpoint-Service: http": "should function for endpoint-Service: http [Skipped:ovirt] [Suite:openshift/conformance/parallel] [Suite:k8s]", + "[Top Level] [sig-network] Networking Granular Checks: Services should function for endpoint-Service: http": "should function for endpoint-Service: http [Suite:openshift/conformance/parallel] [Suite:k8s]", - "[Top Level] [sig-network] Networking Granular Checks: Services should function for endpoint-Service: udp": "should function for endpoint-Service: udp [Skipped:ovirt] [Suite:openshift/conformance/parallel] [Suite:k8s]", + "[Top Level] [sig-network] Networking Granular Checks: Services should function for endpoint-Service: udp": "should function for endpoint-Service: udp [Suite:openshift/conformance/parallel] [Suite:k8s]", - "[Top Level] [sig-network] Networking Granular Checks: Services should function for node-Service: http": "should function for node-Service: http [Skipped:ovirt] [Suite:openshift/conformance/parallel] [Suite:k8s]", + "[Top Level] [sig-network] Networking Granular Checks: Services should function for node-Service: http": "should function for node-Service: http [Suite:openshift/conformance/parallel] [Suite:k8s]", - "[Top Level] [sig-network] Networking Granular Checks: Services should function for node-Service: udp": "should function for node-Service: udp [Skipped:ovirt] [Suite:openshift/conformance/parallel] [Suite:k8s]", + "[Top Level] [sig-network] Networking Granular Checks: Services should function for node-Service: udp": "should function for node-Service: udp [Suite:openshift/conformance/parallel] [Suite:k8s]", - "[Top Level] [sig-network] Networking Granular Checks: Services should function for pod-Service: http": "should function for pod-Service: http [Skipped:ovirt] [Suite:openshift/conformance/parallel] [Suite:k8s]", + "[Top Level] [sig-network] Networking Granular Checks: Services should function for pod-Service: http": "should function for pod-Service: http [Suite:openshift/conformance/parallel] [Suite:k8s]", - "[Top Level] [sig-network] Networking Granular Checks: Services should function for pod-Service: sctp [Feature:SCTPConnectivity]": "should function for pod-Service: sctp [Feature:SCTPConnectivity] [Disabled:Alpha] [Skipped:ovirt] [Suite:k8s]", + "[Top Level] [sig-network] Networking Granular Checks: Services should function for pod-Service: sctp [Feature:SCTPConnectivity]": "should function for pod-Service: sctp [Feature:SCTPConnectivity] [Disabled:Alpha] [Suite:k8s]", - "[Top Level] [sig-network] Networking Granular Checks: Services should function for pod-Service: udp": "should function for pod-Service: udp [Skipped:ovirt] [Suite:openshift/conformance/parallel] [Suite:k8s]", + "[Top Level] [sig-network] Networking Granular Checks: Services should function for pod-Service: udp": "should function for pod-Service: udp [Suite:openshift/conformance/parallel] [Suite:k8s]", "[Top Level] [sig-network] Networking Granular Checks: Services should update endpoints: http": "should update endpoints: http [Suite:openshift/conformance/parallel] [Suite:k8s]", @@ -2117,7 +2133,7 @@ var annotations = map[string]string{ "[Top Level] [sig-network] SCTP [Feature:SCTP] [LinuxOnly] should create a ClusterIP Service with SCTP ports": "should create a ClusterIP Service with SCTP ports [Suite:openshift/conformance/parallel] [Suite:k8s]", - "[Top Level] [sig-network] SCTP [Feature:SCTP] [LinuxOnly] should create a Pod with SCTP HostPort": "should create a Pod with SCTP HostPort [Suite:openshift/conformance/parallel] [Suite:k8s]", + "[Top Level] [sig-network] SCTP [Feature:SCTP] [LinuxOnly] should create a Pod with SCTP HostPort": "should create a Pod with SCTP HostPort [Disabled:Broken] [Suite:k8s]", "[Top Level] [sig-network] Service endpoints latency should not be very high [Conformance]": "should not be very high [Conformance] [Serial] [Suite:openshift/conformance/serial/minimal] [Suite:k8s]", @@ -2179,7 +2195,7 @@ var annotations = map[string]string{ "[Top Level] [sig-network] Services should only allow access from service loadbalancer source ranges [Slow]": "should only allow access from service loadbalancer source ranges [Slow] [Suite:k8s]", - "[Top Level] [sig-network] Services should preserve source pod IP for traffic thru service cluster IP [LinuxOnly]": "should preserve source pod IP for traffic thru service cluster IP [LinuxOnly] [Skipped:Network/OpenShiftSDN/Multitenant] [Suite:openshift/conformance/parallel] [Suite:k8s]", + "[Top Level] [sig-network] Services should preserve source pod IP for traffic thru service cluster IP [LinuxOnly]": "should preserve source pod IP for traffic thru service cluster IP [LinuxOnly] [Suite:openshift/conformance/parallel] [Suite:k8s]", "[Top Level] [sig-network] Services should prevent NodePort collisions": "should prevent NodePort collisions [Suite:openshift/conformance/parallel] [Suite:k8s]", @@ -2313,6 +2329,8 @@ var annotations = map[string]string{ "[Top Level] [sig-node] Downward API should provide pod name, namespace and IP address as env vars [NodeConformance] [Conformance]": "should provide pod name, namespace and IP address as env vars [NodeConformance] [Conformance] [Suite:openshift/conformance/parallel/minimal] [Suite:k8s]", + "[Top Level] [sig-node] Managed cluster should report ready nodes the entire duration of the test run [Late]": "should report ready nodes the entire duration of the test run [Late] [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-node] PodTemplates should delete a collection of pod templates [Conformance]": "should delete a collection of pod templates [Conformance] [Suite:openshift/conformance/parallel/minimal] [Suite:k8s]", "[Top Level] [sig-node] PodTemplates should run the lifecycle of PodTemplates [Conformance]": "should run the lifecycle of PodTemplates [Conformance] [Suite:openshift/conformance/parallel/minimal] [Suite:k8s]", @@ -2331,6 +2349,8 @@ var annotations = map[string]string{ "[Top Level] [sig-node] supplemental groups Ensure supplemental groups propagate to docker should propagate requested groups to the container [Local]": "should propagate requested groups to the container [Local]", + "[Top Level] [sig-node][Late] should not have pod creation failures due to systemd timeouts": "should not have pod creation failures due to systemd timeouts [Suite:openshift/conformance/parallel]", + "[Top Level] [sig-operator] OLM should Implement packages API server and list packagemanifest info with namespace not NULL": "Implement packages API server and list packagemanifest info with namespace not NULL [Suite:openshift/conformance/parallel]", "[Top Level] [sig-operator] OLM should be installed with catalogsources at version v1alpha1": "be installed with catalogsources at version v1alpha1 [Suite:openshift/conformance/parallel]", @@ -9919,7 +9939,7 @@ var annotations = map[string]string{ "[Top Level] [sig-storage] In-tree Volumes [Driver: nfs] [Testpattern: Dynamic PV (default fs)] stress multiple pods should access different volumes repeatedly [Slow] [Serial]": "multiple pods should access different volumes repeatedly [Slow] [Serial] [Suite:k8s]", - "[Top Level] [sig-storage] In-tree Volumes [Driver: nfs] [Testpattern: Dynamic PV (default fs)] subPath should be able to unmount after the subpath directory is deleted": "should be able to unmount after the subpath directory is deleted [Suite:openshift/conformance/parallel] [Suite:k8s]", + "[Top Level] [sig-storage] In-tree Volumes [Driver: nfs] [Testpattern: Dynamic PV (default fs)] subPath should be able to unmount after the subpath directory is deleted": "should be able to unmount after the subpath directory is deleted [Disabled:Broken] [Suite:k8s]", "[Top Level] [sig-storage] In-tree Volumes [Driver: nfs] [Testpattern: Dynamic PV (default fs)] subPath should fail if non-existent subpath is outside the volume [Slow][LinuxOnly]": "should fail if non-existent subpath is outside the volume [Slow][LinuxOnly] [Suite:k8s]", @@ -11436,6 +11456,10 @@ var annotations = map[string]string{ "[Top Level] [sig-storage] vsphere cloud provider stress [Feature:vsphere] vsphere stress tests": "vsphere stress tests [Suite:openshift/conformance/parallel] [Suite:k8s]", "[Top Level] [sig-storage] vsphere statefulset [Feature:vsphere] vsphere statefulset testing": "vsphere statefulset testing [Suite:openshift/conformance/parallel] [Suite:k8s]", + + "[Top Level] [sig-storage][Late] Metrics should report short attach times": "should report short attach times [Suite:openshift/conformance/parallel]", + + "[Top Level] [sig-storage][Late] Metrics should report short mount times": "should report short mount times [Suite:openshift/conformance/parallel]", } func init() { diff --git a/test/extended/util/annotate/rules.go b/test/extended/util/annotate/rules.go index 44a27597cc28..9e6aae5a2121 100644 --- a/test/extended/util/annotate/rules.go +++ b/test/extended/util/annotate/rules.go @@ -1,16 +1,17 @@ package main -// NOTE: Only annotation rules targeting tests implemented in origin -// should be added to this file. -// // Rules defined here are additive to the rules already defined for // kube e2e tests in openshift/kubernetes. The kube rules are // vendored via the following file: // // vendor/k8s.io/kubernetes/openshift-hack/e2e/annotate/rules.go // -// Changes to rules for kube e2e tests should be proposed to -// openshift/kubernetes and vendored back into origin. +// Rules that are needed to pass the upstream e2e test suite in a +// "default OCP CI" configuration (eg, AWS or GCP, openshift-sdn) must +// be added to openshift/kubernetes to allow CI to pass there, and +// then vendored back into origin. Rules that only apply to +// "non-default" configurations (other clouds, other network +// providers) should be added here. var ( testMaps = map[string][]string{ @@ -31,6 +32,11 @@ var ( "[Disabled:Broken]": { `should idle the service and DeploymentConfig properly`, // idling with a single service and DeploymentConfig `should answer endpoint and wildcard queries for the cluster`, // currently not supported by dns operator https://github.com/openshift/cluster-dns-operator/issues/43 + // https://bugzilla.redhat.com/show_bug.cgi?id=1908677 + `SCTP \[Feature:SCTP\] \[LinuxOnly\] should create a Pod with SCTP HostPort`, + + // https://bugzilla.redhat.com/show_bug.cgi?id=1908645 + `\[sig-network\] Networking Granular Checks: Services should function for service endpoints using hostNetwork`, }, // tests that may work, but we don't support them "[Disabled:Unsupported]": {}, @@ -43,17 +49,15 @@ var ( // tests that must be run without competition "[Serial]": {}, "[Skipped:azure]": {}, - "[Skipped:ovirt]": { - // https://bugzilla.redhat.com/show_bug.cgi?id=1838751 - `\[sig-network\] Networking Granular Checks: Services should function for endpoint-Service`, - `\[sig-network\] Networking Granular Checks: Services should function for node-Service`, - `\[sig-network\] Networking Granular Checks: Services should function for pod-Service`, - }, - "[Skipped:gce]": {}, + "[Skipped:ovirt]": {}, + "[Skipped:gce]": {}, + + // tests that don't pass under openshift-sdn NetworkPolicy mode are specified + // in the rules file in openshift/kubernetes, not here. + // tests that don't pass under openshift-sdn multitenant mode "[Skipped:Network/OpenShiftSDN/Multitenant]": { `\[Feature:NetworkPolicy\]`, // not compatible with multitenant mode - `\[sig-network\] Services should preserve source pod IP for traffic thru service cluster IP`, // known bug, not planned to be fixed }, // tests that don't pass under OVN Kubernetes "[Skipped:Network/OVNKubernetes]": { @@ -66,8 +70,9 @@ var ( `\[sig-network\] Services should have session affinity work for service with type clusterIP`, `\[sig-network\] Services should have session affinity timeout work for NodePort service`, `\[sig-network\] Services should have session affinity timeout work for service with type clusterIP`, - // https://github.com/kubernetes/kubernetes/pull/93597: upstream is flaky - `\[sig-network\] Conntrack should be able to preserve UDP traffic when server pod cycles for a NodePort service`, + + // ovn-kubernetes does not support named ports + `NetworkPolicy.*named port`, }, "[Skipped:ibmcloud]": { // skip Gluster tests (not supported on ROKS worker nodes) @@ -101,6 +106,18 @@ var ( // https://bugzilla.redhat.com/show_bug.cgi?id=1825027 `\[Feature:Platform\] Managed cluster should ensure control plane operators do not make themselves unevictable`, }, + "[Skipped:Disruptive]": { + // DR testing induces ungraceful termination by forcefully shutting down nodes + `\[sig-api-machinery\]\[Feature:APIServer\]\[Late\] kube-apiserver terminates within graceful termination period`, + `\[sig-api-machinery\]\[Feature:APIServer\]\[Late\] kubelet terminates kube-apiserver gracefully`, + + // DR testing results in an excessive amount of alerts + `\[sig-instrumentation\]\[Late\] Alerts shouldn't exceed the 500 series limit of total series sent via telemetry from each cluster`, + + // Machine API deletion does not properly handle stopped instances on AWS or GCP + // https://bugzilla.redhat.com/show_bug.cgi?id=1905709 + `\[sig-cluster-lifecycle\]\[Feature:DisasterRecovery\]\[Disruptive\] \[Feature:NodeRecovery\] Cluster should survive master and worker failure and recover with machine health checks`, + }, } // labelExcludes temporarily block tests out of a specific suite diff --git a/test/extended/util/client.go b/test/extended/util/client.go index 5308c91b1d93..6c39b8c801a8 100644 --- a/test/extended/util/client.go +++ b/test/extended/util/client.go @@ -1,7 +1,6 @@ package util import ( - "bufio" "bytes" "context" "encoding/base64" @@ -17,6 +16,9 @@ import ( "strings" "time" + clientcorev1 "k8s.io/client-go/kubernetes/typed/core/v1" + + yaml "gopkg.in/yaml.v2" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" @@ -70,6 +72,7 @@ type CLI struct { verb string configPath string adminConfigPath string + token string username string globalArgs []string commandArgs []string @@ -107,6 +110,7 @@ func NewCLIWithFramework(kubeFramework *framework.Framework) *CLI { // namespace. Should be called outside of a Ginkgo .It() function. func NewCLI(project string) *CLI { cli := NewCLIWithoutNamespace(project) + cli.withoutNamespace = false // create our own project g.BeforeEach(func() { _ = cli.SetupProject() }) return cli @@ -126,9 +130,10 @@ func NewCLIWithoutNamespace(project string) *CLI { ClientBurst: 50, }, }, - username: "admin", - execPath: "oc", - adminConfigPath: KubeConfigPath(), + username: "admin", + execPath: "oc", + adminConfigPath: KubeConfigPath(), + withoutNamespace: true, } g.AfterEach(cli.TeardownProject) g.AfterEach(cli.kubeFramework.AfterEach) @@ -196,6 +201,31 @@ func (c CLI) WithoutNamespace() *CLI { return &c } +// WithToken instructs the command should be invoked with --token rather than --kubeconfig flag +func (c CLI) WithToken(token string) *CLI { + c.configPath = "" + c.token = token + return &c +} + +// SetupNamespace creates a namespace, without waiting for any resources except the SCC annotation to be available +func (c *CLI) SetupNamespace() string { + requiresTestStart() + newNamespace := names.SimpleNameGenerator.GenerateName(fmt.Sprintf("e2e-test-%s-", c.kubeFramework.BaseName)) + c.SetNamespace(newNamespace) + + framework.Logf("Creating namespace %q", newNamespace) + _, err := c.AdminKubeClient().CoreV1().Namespaces().Create(context.Background(), &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{Name: newNamespace}, + }, metav1.CreateOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + + c.kubeFramework.AddNamespacesToDelete(&corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: newNamespace}}) + + WaitForNamespaceSCCAnnotations(c.AdminKubeClient().CoreV1(), newNamespace) + return newNamespace +} + // SetupProject creates a new project and assign a random user to the project. // All resources will be then created within this project. // Returns the name of the new project. @@ -277,7 +307,7 @@ func (c *CLI) SetupProject() string { o.Expect(err).NotTo(o.HaveOccurred()) } - WaitForNamespaceSCCAnnotations(c.ProjectClient().ProjectV1(), newNamespace) + WaitForProjectSCCAnnotations(c.ProjectClient().ProjectV1(), newNamespace) framework.Logf("Project %q has been fully provisioned.", newNamespace) return newNamespace @@ -517,9 +547,13 @@ func (c *CLI) Run(commands ...string) *CLI { adminConfigPath: c.adminConfigPath, configPath: c.configPath, username: c.username, - globalArgs: append([]string{ - fmt.Sprintf("--kubeconfig=%s", c.configPath), - }, commands...), + globalArgs: commands, + } + if len(c.configPath) > 0 { + nc.globalArgs = append([]string{fmt.Sprintf("--kubeconfig=%s", c.configPath)}, nc.globalArgs...) + } + if len(c.configPath) == 0 && len(c.token) > 0 { + nc.globalArgs = append([]string{fmt.Sprintf("--token=%s", c.token)}, nc.globalArgs...) } if !c.withoutNamespace { nc.globalArgs = append([]string{fmt.Sprintf("--namespace=%s", c.Namespace())}, nc.globalArgs...) @@ -528,18 +562,6 @@ func (c *CLI) Run(commands ...string) *CLI { return nc.setOutput(c.stdout) } -// Template sets a Go template for the OpenShift CLI command. -// This is equivalent of running "oc get foo -o template --template='{{ .spec }}'" -func (c *CLI) Template(t string) *CLI { - if c.verb != "get" { - FatalErr("Cannot use Template() for non-get verbs.") - } - templateArgs := []string{"--output=template", fmt.Sprintf("--template=%s", t)} - commandArgs := append(c.commandArgs, templateArgs...) - c.finalArgs = append(c.globalArgs, commandArgs...) - return c -} - // InputString adds expected input to the command func (c *CLI) InputString(input string) *CLI { c.stdin.WriteString(input) @@ -549,7 +571,6 @@ func (c *CLI) InputString(input string) *CLI { // Args sets the additional arguments for the OpenShift CLI command func (c *CLI) Args(args ...string) *CLI { c.commandArgs = args - c.finalArgs = append(c.globalArgs, c.commandArgs...) return c } @@ -565,52 +586,55 @@ type ExitError struct { // Output executes the command and returns stdout/stderr combined into one string func (c *CLI) Output() (string, error) { - if c.verbose { - fmt.Printf("DEBUG: oc %s\n", c.printCmd()) - } - cmd := exec.Command(c.execPath, c.finalArgs...) - cmd.Stdin = c.stdin - framework.Logf("Running '%s %s'", c.execPath, strings.Join(c.finalArgs, " ")) - out, err := cmd.CombinedOutput() - trimmed := strings.TrimSpace(string(out)) - switch err.(type) { - case nil: - c.stdout = bytes.NewBuffer(out) - return trimmed, nil - case *exec.ExitError: - // avoid excessively long lines in the error output if a command generates a giant amount of logging - const maxLength = 809 - shortened := trimmed - if len(shortened) > maxLength { - shortened = shortened[:maxLength/2] + "\n...\n" + shortened[len(shortened)-(maxLength/2):] - } - framework.Logf("Error running %v:\n%s", cmd, shortened) - return trimmed, &ExitError{ExitError: err.(*exec.ExitError), Cmd: c.execPath + " " + strings.Join(c.finalArgs, " "), StdErr: shortened} - default: - FatalErr(fmt.Errorf("unable to execute %q: %v", c.execPath, err)) - // unreachable code - return "", nil - } + var buff bytes.Buffer + _, _, err := c.outputs(&buff, &buff) + return strings.TrimSpace(string(buff.Bytes())), err } // Outputs executes the command and returns the stdout/stderr output as separate strings func (c *CLI) Outputs() (string, string, error) { + var stdOutBuff, stdErrBuff bytes.Buffer + return c.outputs(&stdOutBuff, &stdErrBuff) +} + +// Background executes the command in the background and returns the Cmd object +// which may be killed later via cmd.Process.Kill(). It also returns buffers +// holding the stdout & stderr of the command, which may be read from only after +// calling cmd.Wait(). +func (c *CLI) Background() (*exec.Cmd, *bytes.Buffer, *bytes.Buffer, error) { + var stdOutBuff, stdErrBuff bytes.Buffer + cmd, err := c.start(&stdOutBuff, &stdErrBuff) + return cmd, &stdOutBuff, &stdErrBuff, err +} + +func (c *CLI) start(stdOutBuff, stdErrBuff *bytes.Buffer) (*exec.Cmd, error) { + c.finalArgs = append(c.globalArgs, c.commandArgs...) if c.verbose { fmt.Printf("DEBUG: oc %s\n", c.printCmd()) } cmd := exec.Command(c.execPath, c.finalArgs...) cmd.Stdin = c.stdin framework.Logf("Running '%s %s'", c.execPath, strings.Join(c.finalArgs, " ")) - //out, err := cmd.CombinedOutput() - var stdErrBuff, stdOutBuff bytes.Buffer - cmd.Stdout = &stdOutBuff - cmd.Stderr = &stdErrBuff - err := cmd.Run() + + cmd.Stdout = stdOutBuff + cmd.Stderr = stdErrBuff + err := cmd.Start() + + return cmd, err +} + +func (c *CLI) outputs(stdOutBuff, stdErrBuff *bytes.Buffer) (string, string, error) { + cmd, err := c.start(stdOutBuff, stdErrBuff) + if err != nil { + return "", "", err + } + err = cmd.Wait() stdOutBytes := stdOutBuff.Bytes() stdErrBytes := stdErrBuff.Bytes() stdOut := strings.TrimSpace(string(stdOutBytes)) stdErr := strings.TrimSpace(string(stdErrBytes)) + switch err.(type) { case nil: c.stdout = bytes.NewBuffer(stdOutBytes) @@ -626,50 +650,9 @@ func (c *CLI) Outputs() (string, string, error) { } } -// Background executes the command in the background and returns the Cmd object -// which may be killed later via cmd.Process.Kill(). It also returns buffers -// holding the stdout & stderr of the command, which may be read from only after -// calling cmd.Wait(). -func (c *CLI) Background() (*exec.Cmd, *bytes.Buffer, *bytes.Buffer, error) { - if c.verbose { - fmt.Printf("DEBUG: oc %s\n", c.printCmd()) - } - cmd := exec.Command(c.execPath, c.finalArgs...) - cmd.Stdin = c.stdin - var stdout, stderr bytes.Buffer - cmd.Stdout = bufio.NewWriter(&stdout) - cmd.Stderr = bufio.NewWriter(&stderr) - - framework.Logf("Running '%s %s'", c.execPath, strings.Join(c.finalArgs, " ")) - - err := cmd.Start() - return cmd, &stdout, &stderr, err -} - -// BackgroundRC executes the command in the background and returns the Cmd -// object which may be killed later via cmd.Process.Kill(). It returns a -// ReadCloser for stdout. If in doubt, use Background(). Consult the os/exec -// documentation. -func (c *CLI) BackgroundRC() (*exec.Cmd, io.ReadCloser, error) { - if c.verbose { - fmt.Printf("DEBUG: oc %s\n", c.printCmd()) - } - cmd := exec.Command(c.execPath, c.finalArgs...) - cmd.Stdin = c.stdin - stdout, err := cmd.StdoutPipe() - if err != nil { - return nil, nil, err - } - - framework.Logf("Running '%s %s'", c.execPath, strings.Join(c.finalArgs, " ")) - - err = cmd.Start() - return cmd, stdout, err -} - // OutputToFile executes the command and store output to a file func (c *CLI) OutputToFile(filename string) (string, error) { - content, err := c.Output() + content, _, err := c.Outputs() if err != nil { return "", err } @@ -854,3 +837,37 @@ func defaultClientTransport(rt http.RoundTripper) http.RoundTripper { transport.MaxIdleConnsPerHost = 100 return transport } + +const ( + installConfigName = "cluster-config-v1" +) + +// installConfig The subset of openshift-install's InstallConfig we parse for this test +type installConfig struct { + FIPS bool `json:"fips,omitempty"` +} + +func IsFIPS(client clientcorev1.ConfigMapsGetter) (bool, error) { + // this currently uses an install config because it has a lower dependency threshold than going directly to the node. + installConfig, err := installConfigFromCluster(client) + if err != nil { + return false, err + } + return installConfig.FIPS, nil +} + +func installConfigFromCluster(client clientcorev1.ConfigMapsGetter) (*installConfig, error) { + cm, err := client.ConfigMaps("kube-system").Get(context.Background(), installConfigName, metav1.GetOptions{}) + if err != nil { + return nil, err + } + data, ok := cm.Data["install-config"] + if !ok { + return nil, fmt.Errorf("no install-config found in kube-system/%s", installConfigName) + } + config := &installConfig{} + if err := yaml.Unmarshal([]byte(data), config); err != nil { + return nil, err + } + return config, nil +} diff --git a/test/extended/util/conditions.go b/test/extended/util/conditions.go new file mode 100644 index 000000000000..8787c1f788e6 --- /dev/null +++ b/test/extended/util/conditions.go @@ -0,0 +1,94 @@ +package util + +import ( + "os" + "strconv" + "time" +) + +// LimitTestsToStartTime returns a time.Time which should be the earliest +// that a test in the e2e suite will consider. By default this is the empty +// Time object, and if TEST_LIMIT_START_TIME is set to a unix timestamp in +// seconds from the epoch, will return that time. +// +// Tests should use this when looking at the historical record for failures - +// events that happen before this time are considered to be ignorable. +// +// Disruptive tests use this value to signal when the disruption has healed +// so that normal conformance results are not impacted. +func LimitTestsToStartTime() time.Time { + return unixTimeFromEnv("TEST_LIMIT_START_TIME") +} + +// SuiteStartTime returns a time.Time which is the beginning of the suite +// execution (the set of tests). If this is empty or invalid the Time will +// be the zero value. +// +// Tests that need to retrieve results newer than the suite start because +// they are only checking the behavior of the system while the suite is being +// run should use this time as the start of that interval. +func SuiteStartTime() time.Time { + return unixTimeFromEnv("TEST_SUITE_START_TIME") +} + +// DurationSinceStartInSeconds returns the current time minus the start +// limit time or suite time, or one hour by default. It rounds the duration +// to seconds. It always returns a one minute duration or longer, even if +// the start time is in the future. +// +// This method simplifies the default behavior of tests that check metrics +// from the current time to the preferred start time (either implicit via +// the suite start time, or explicit via TEST_LIMIT_START_TIME). Depending +// on the suite a user is running, if the invariants the suite tests should +// hold BEFORE the suite is run, then TEST_LIMIT_START_TIME should be set +// to that time, and tests will automatically check that interval as well. +func DurationSinceStartInSeconds() time.Duration { + now := time.Now() + start := LimitTestsToStartTime() + if start.IsZero() { + start = SuiteStartTime() + } + if start.IsZero() { + start = now.Add(-time.Hour) + } + interval := now.Sub(start).Round(time.Second) + switch { + case interval < time.Minute: + return time.Minute + default: + return interval + } +} + +// TolerateVersionSkewInTests returns true if the test invoker has indicated +// that version skew is known present via the TEST_UNSUPPORTED_ALLOW_VERSION_SKEW +// environment variable. Tests that may fail if the component is skewed may then +// be skipped or alter their behavior. The version skew is assumed to be one minor +// release - for instance, if a test would fail because the previous version of +// the kubelet does not yet support a value, when this function returns true it +// would be acceptable for the test to invoke Skipf(). +// +// Used by the node version skew environment (Kube @ version N, nodes @ version N-1) +// to ensure OpenShift works when control plane and worker nodes are not updated, +// as can occur during test suites. +func TolerateVersionSkewInTests() bool { + if len(os.Getenv("TEST_UNSUPPORTED_ALLOW_VERSION_SKEW")) > 0 { + return true + } + return false +} + +// unixTimeFromEnv reads a unix timestamp in seconds since the epoch and +// returns a Time object. If no env var is set or if it does not parse, a +// zero time is returned. +func unixTimeFromEnv(name string) time.Time { + s := os.Getenv(name) + if len(s) == 0 { + return time.Time{} + } + seconds, err := strconv.ParseInt(s, 10, 64) + if err != nil { + return time.Time{} + } + return time.Unix(seconds, 0) +} diff --git a/test/extended/util/disruption/controlplane/controlplane.go b/test/extended/util/disruption/controlplane/controlplane.go index cfcd5a143b0b..0a24e8099125 100644 --- a/test/extended/util/disruption/controlplane/controlplane.go +++ b/test/extended/util/disruption/controlplane/controlplane.go @@ -14,77 +14,87 @@ import ( "github.com/openshift/origin/test/extended/util/disruption" ) -// NewKubeAvailableTest tests that the Kubernetes control plane remains available during and after a cluster upgrade. -func NewKubeAvailableTest() upgrades.Test { - return &kubeAvailableTest{availableTest{name: "kubernetes-api-available"}} -} - -type kubeAvailableTest struct { - availableTest -} - -func (t kubeAvailableTest) Name() string { return t.availableTest.name } -func (kubeAvailableTest) DisplayName() string { - return "[sig-api-machinery] Kubernetes APIs remain available" -} -func (t *kubeAvailableTest) Test(f *framework.Framework, done <-chan struct{}, upgrade upgrades.UpgradeType) { - t.availableTest.test(f, done, upgrade, monitor.StartKubeAPIMonitoring) +// NewKubeAvailableWithNewConnectionsTest tests that the Kubernetes control plane remains available during and after a cluster upgrade. +func NewKubeAvailableWithNewConnectionsTest() upgrades.Test { + return &availableTest{ + testName: "[sig-api-machinery] Kubernetes APIs remain available for new connections", + name: "kubernetes-api-available-new-connections", + startMonitoring: monitor.StartKubeAPIMonitoringWithNewConnections, + } +} + +// NewOpenShiftAvailableNewConnectionsTest tests that the OpenShift APIs remains available during and after a cluster upgrade. +func NewOpenShiftAvailableNewConnectionsTest() upgrades.Test { + return &availableTest{ + testName: "[sig-api-machinery] OpenShift APIs remain available for new connections", + name: "openshift-api-available-new-connections", + startMonitoring: monitor.StartOpenShiftAPIMonitoringWithNewConnections, + } +} + +// NewOAuthAvailableNewConnectionsTest tests that the OAuth APIs remains available during and after a cluster upgrade. +func NewOAuthAvailableNewConnectionsTest() upgrades.Test { + return &availableTest{ + testName: "[sig-api-machinery] OAuth APIs remain available for new connections", + name: "oauth-api-available-new-connections", + startMonitoring: monitor.StartOpenShiftAPIMonitoringWithNewConnections, + } +} + +// NewKubeAvailableWithConnectionReuseTest tests that the Kubernetes control plane remains available during and after a cluster upgrade. +func NewKubeAvailableWithConnectionReuseTest() upgrades.Test { + return &availableTest{ + testName: "[sig-api-machinery] Kubernetes APIs remain available with reused connections", + name: "kubernetes-api-available-reused-connections", + startMonitoring: monitor.StartKubeAPIMonitoringWithConnectionReuse, + } } // NewOpenShiftAvailableTest tests that the OpenShift APIs remains available during and after a cluster upgrade. -func NewOpenShiftAvailableTest() upgrades.Test { - return &openShiftAvailableTest{availableTest{name: "openshift-api-available"}} -} - -type openShiftAvailableTest struct { - availableTest -} - -func (t openShiftAvailableTest) Name() string { return t.availableTest.name } -func (openShiftAvailableTest) DisplayName() string { - return "[sig-api-machinery] OpenShift APIs remain available" -} -func (t *openShiftAvailableTest) Test(f *framework.Framework, done <-chan struct{}, upgrade upgrades.UpgradeType) { - t.availableTest.test(f, done, upgrade, monitor.StartOpenShiftAPIMonitoring) +func NewOpenShiftAvailableWithConnectionReuseTest() upgrades.Test { + return &availableTest{ + testName: "[sig-api-machinery] OpenShift APIs remain available with reused connections", + name: "openshift-api-available-reused-connections", + startMonitoring: monitor.StartOpenShiftAPIMonitoringWithConnectionReuse, + } } // NewOauthAvailableTest tests that the OAuth APIs remains available during and after a cluster upgrade. -func NewOAuthAvailableTest() upgrades.Test { - return &oauthAvailableTest{availableTest{name: "oauth-api-available"}} -} - -// oauthAvailableTest tests that the OAuth APIs remains available during and after a cluster upgrade. -type oauthAvailableTest struct { - availableTest -} - -func (t oauthAvailableTest) Name() string { return t.availableTest.name } -func (oauthAvailableTest) DisplayName() string { - return "[sig-api-machinery] OAuth APIs remain available" -} -func (t *oauthAvailableTest) Test(f *framework.Framework, done <-chan struct{}, upgrade upgrades.UpgradeType) { - t.availableTest.test(f, done, upgrade, monitor.StartOAuthAPIMonitoring) +func NewOAuthAvailableWithConnectionReuseTest() upgrades.Test { + return &availableTest{ + testName: "[sig-api-machinery] OAuth APIs remain available with reused connections", + name: "oauth-api-available-reused-connections", + startMonitoring: monitor.StartOpenShiftAPIMonitoringWithConnectionReuse, + } } type availableTest struct { + // testName is the name to show in unit + testName string // name helps distinguish which API server in particular is unavailable. - name string + name string + startMonitoring starter } type starter func(ctx context.Context, m *monitor.Monitor, clusterConfig *rest.Config, timeout time.Duration) error +func (t availableTest) Name() string { return t.name } +func (t availableTest) DisplayName() string { + return t.testName +} + // Setup does nothing func (t *availableTest) Setup(f *framework.Framework) { } // Test runs a connectivity check to the core APIs. -func (t *availableTest) test(f *framework.Framework, done <-chan struct{}, upgrade upgrades.UpgradeType, startMonitoring starter) { +func (t *availableTest) Test(f *framework.Framework, done <-chan struct{}, upgrade upgrades.UpgradeType) { config, err := framework.LoadConfig() framework.ExpectNoError(err) ctx, cancel := context.WithCancel(context.Background()) m := monitor.NewMonitorWithInterval(time.Second) - err = startMonitoring(ctx, m, config, 15*time.Second) + err = t.startMonitoring(ctx, m, config, 15*time.Second) framework.ExpectNoError(err, "unable to monitor API") start := time.Now() diff --git a/test/extended/util/disruption/disruption.go b/test/extended/util/disruption/disruption.go index da55e356d193..5ed725bfeb20 100644 --- a/test/extended/util/disruption/disruption.go +++ b/test/extended/util/disruption/disruption.go @@ -280,9 +280,23 @@ func createTestFrameworks(tests []upgrades.Test) map[string]*framework.Framework // disruption flake if any disruption occurs, and uses reason to prefix the message. I.e. tolerate 0.1 of 10m total will fail // if the sum of the intervals is greater than 1m, or report a flake if any interval is found. func ExpectNoDisruption(f *framework.Framework, tolerate float64, total time.Duration, events monitor.EventIntervals, reason string) { + duration, describe := GetDisruption(events, "") + if percent := float64(duration) / float64(total); percent > tolerate { + framework.Failf("%s for at least %s of %s (%0.0f%%):\n\n%s", reason, duration.Truncate(time.Second), total.Truncate(time.Second), percent*100, strings.Join(describe, "\n")) + } else if duration > 0 { + FrameworkFlakef(f, "%s for at least %s of %s (%0.0f%%), this is currently sufficient to pass the test/job but not considered completely correct:\n\n%s", reason, duration.Truncate(time.Second), total.Truncate(time.Second), percent*100, strings.Join(describe, "\n")) + } +} + +// GetDisruption returns total duration of all error events and array of event description for printing. +// When requiredLocator is specified (non-empty), only events matching this locator are considered. +func GetDisruption(events monitor.EventIntervals, requiredLocator string) (time.Duration, []string) { var duration time.Duration var describe []string for _, interval := range events { + if requiredLocator != "" && requiredLocator != interval.Locator { + continue + } describe = append(describe, interval.String()) i := interval.To.Sub(interval.From) if i < time.Second { @@ -292,11 +306,7 @@ func ExpectNoDisruption(f *framework.Framework, tolerate float64, total time.Dur duration += i } } - if percent := float64(duration) / float64(total); percent > tolerate { - framework.Failf("%s for at least %s of %s (%0.0f%%):\n\n%s", reason, duration.Truncate(time.Second), total.Truncate(time.Second), percent*100, strings.Join(describe, "\n")) - } else if duration > 0 { - FrameworkFlakef(f, "%s for at least %s of %s (%0.0f%%), this is currently sufficient to pass the test/job but not considered completely correct:\n\n%s", reason, duration.Truncate(time.Second), total.Truncate(time.Second), percent*100, strings.Join(describe, "\n")) - } + return duration, describe } // FrameworkFlakef records a flake on the current framework. diff --git a/test/extended/util/disruption/imageregistry/imageregistry.go b/test/extended/util/disruption/imageregistry/imageregistry.go new file mode 100644 index 000000000000..2321af79ac1a --- /dev/null +++ b/test/extended/util/disruption/imageregistry/imageregistry.go @@ -0,0 +1,243 @@ +package imageregistry + +import ( + "context" + "crypto/tls" + "net" + "net/http" + "time" + + "github.com/onsi/ginkgo" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/events" + "k8s.io/kubernetes/test/e2e/framework" + "k8s.io/kubernetes/test/e2e/upgrades" + + routev1 "github.com/openshift/api/route/v1" + routeclient "github.com/openshift/client-go/route/clientset/versioned" + "github.com/openshift/origin/pkg/monitor" + "github.com/openshift/origin/test/extended/util/disruption" +) + +// AvailableTest tests that the image registry is available before, during, and +// after a cluster upgrade. +type AvailableTest struct { + routeRef *corev1.ObjectReference + host string +} + +func (AvailableTest) Name() string { return "image-registry-available" } +func (AvailableTest) DisplayName() string { + return "[sig-imageregistry] Image registry remain available" +} + +// Setup creates a route that exposes the registry to tests. +func (t *AvailableTest) Setup(f *framework.Framework) { + ctx := context.Background() + + config, err := framework.LoadConfig() + framework.ExpectNoError(err) + routeClient, err := routeclient.NewForConfig(config) + framework.ExpectNoError(err) + + route, err := routeClient.RouteV1().Routes("openshift-image-registry").Create(ctx, &routev1.Route{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-disruption", + }, + Spec: routev1.RouteSpec{ + To: routev1.RouteTargetReference{ + Kind: "Service", + Name: "image-registry", + }, + Port: &routev1.RoutePort{ + TargetPort: intstr.FromInt(5000), + }, + TLS: &routev1.TLSConfig{ + Termination: routev1.TLSTerminationPassthrough, + InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect, + }, + }, + }, metav1.CreateOptions{}) + framework.ExpectNoError(err) + + err = wait.PollImmediate(1*time.Second, 30*time.Second, func() (bool, error) { + route, err = routeClient.RouteV1().Routes("openshift-image-registry").Get(ctx, "test-disruption", metav1.GetOptions{}) + if err != nil { + return false, err + } + + for _, ingress := range route.Status.Ingress { + if len(ingress.Host) > 0 { + t.host = ingress.Host + return true, nil + } + } + return false, nil + }) + framework.ExpectNoError(err, "failed to get route host") + + t.routeRef = &corev1.ObjectReference{ + Kind: "Route", + Namespace: route.Namespace, + Name: route.Name, + } +} + +// Test runs a connectivity check to the service. +func (t *AvailableTest) Test(f *framework.Framework, done <-chan struct{}, upgrade upgrades.UpgradeType) { + client, err := framework.LoadClientset() + framework.ExpectNoError(err) + + stopCh := make(chan struct{}) + defer close(stopCh) + + newBroadcaster := events.NewBroadcaster(&events.EventSinkImpl{Interface: client.EventsV1()}) + r := newBroadcaster.NewRecorder(scheme.Scheme, "openshift.io/image-registry-available-test") + newBroadcaster.StartRecordingToSink(stopCh) + + ginkgo.By("continuously hitting image registry") + + ctx, cancel := context.WithCancel(context.Background()) + m := monitor.NewMonitorWithInterval(1 * time.Second) + err = t.startEndpointMonitoring(ctx, m, r) + framework.ExpectNoError(err, "unable to monitor route") + + start := time.Now() + m.StartSampling(ctx) + + // wait to ensure API is still up after the test ends + <-done + ginkgo.By("waiting for any post disruption failures") + time.Sleep(15 * time.Second) + cancel() + end := time.Now() + + disruption.ExpectNoDisruption(f, 0.20, end.Sub(start), m.Events(time.Time{}, time.Time{}), "Image registry was unreachable during disruption") +} + +// Teardown cleans up any remaining resources. +func (t *AvailableTest) Teardown(f *framework.Framework) { + ctx := context.Background() + + config, err := framework.LoadConfig() + framework.ExpectNoError(err) + routeClient, err := routeclient.NewForConfig(config) + framework.ExpectNoError(err) + + err = routeClient.RouteV1().Routes(t.routeRef.Namespace).Delete(ctx, t.routeRef.Name, metav1.DeleteOptions{}) + framework.ExpectNoError(err, "failed to delete route") +} + +func (t *AvailableTest) startEndpointMonitoring(ctx context.Context, m *monitor.Monitor, r events.EventRecorder) error { + var ( + url = "https://" + t.host + path = "/healthz" + locator = "image-registry" + ) + + // this client reuses connections and detects abrupt breaks + continuousClient, err := rest.UnversionedRESTClientFor(&rest.Config{ + Host: url, + Timeout: 10 * time.Second, + Transport: &http.Transport{ + Dial: (&net.Dialer{ + Timeout: 15 * time.Second, + }).Dial, + TLSHandshakeTimeout: 15 * time.Second, + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + ContentConfig: rest.ContentConfig{ + NegotiatedSerializer: runtime.NewSimpleNegotiatedSerializer(scheme.Codecs.SupportedMediaTypes()[0]), + }, + }) + if err != nil { + return err + } + m.AddSampler( + monitor.StartSampling(ctx, m, time.Second, func(previous bool) (condition *monitor.Condition, next bool) { + _, err := continuousClient.Get().AbsPath(path).DoRaw(ctx) + switch { + case err == nil && !previous: + condition = &monitor.Condition{ + Level: monitor.Info, + Locator: locator, + Message: "Route started responding to GET requests on reused connections", + } + case err != nil && previous: + framework.Logf("Route for image-registry is unreachable on reused connections: %v", err) + r.Eventf(t.routeRef, nil, corev1.EventTypeWarning, "Unreachable", "detected", "on reused connections") + condition = &monitor.Condition{ + Level: monitor.Error, + Locator: locator, + Message: "Route stopped responding to GET requests on reused connections", + } + case err != nil: + framework.Logf("Route for image-registry is unreachable on reused connections: %v", err) + } + return condition, err == nil + }).ConditionWhenFailing(&monitor.Condition{ + Level: monitor.Error, + Locator: locator, + Message: "Route is not responding to GET requests on reused connections", + }), + ) + + // this client creates fresh connections and detects failure to establish connections + client, err := rest.UnversionedRESTClientFor(&rest.Config{ + Host: url, + Timeout: 10 * time.Second, + Transport: &http.Transport{ + Dial: (&net.Dialer{ + Timeout: 15 * time.Second, + KeepAlive: -1, + }).Dial, + TLSHandshakeTimeout: 15 * time.Second, + IdleConnTimeout: 15 * time.Second, + DisableKeepAlives: true, + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, + ContentConfig: rest.ContentConfig{ + NegotiatedSerializer: runtime.NewSimpleNegotiatedSerializer(scheme.Codecs.SupportedMediaTypes()[0]), + }, + }) + if err != nil { + return err + } + m.AddSampler( + monitor.StartSampling(ctx, m, time.Second, func(previous bool) (condition *monitor.Condition, next bool) { + _, err := client.Get().AbsPath(path).DoRaw(ctx) + switch { + case err == nil && !previous: + condition = &monitor.Condition{ + Level: monitor.Info, + Locator: locator, + Message: "Route started responding to GET requests over new connections", + } + case err != nil && previous: + framework.Logf("Route for image-registry is unreachable on new connections: %v", err) + r.Eventf(t.routeRef, nil, corev1.EventTypeWarning, "Unreachable", "detected", "on new connections") + condition = &monitor.Condition{ + Level: monitor.Error, + Locator: locator, + Message: "Route stopped responding to GET requests over new connections", + } + case err != nil: + framework.Logf("Route for image-registry is unreachable on new connections: %v", err) + } + return condition, err == nil + }).ConditionWhenFailing(&monitor.Condition{ + Level: monitor.Error, + Locator: locator, + Message: "Route is not responding to GET requests over new connections", + }), + ) + + return nil +} diff --git a/test/extended/util/framework.go b/test/extended/util/framework.go index bf89c1bd0934..7cb92f4f3334 100644 --- a/test/extended/util/framework.go +++ b/test/extended/util/framework.go @@ -55,6 +55,7 @@ import ( "github.com/openshift/library-go/pkg/image/imageutil" "github.com/openshift/origin/test/extended/testdata" "github.com/openshift/origin/test/extended/util/ibmcloud" + utilimage "github.com/openshift/origin/test/extended/util/image" ) // WaitForInternalRegistryHostname waits for the internal registry hostname to be made available to the cluster. @@ -772,9 +773,9 @@ func (t *BuildResult) Logs() (string, error) { return t.LogDumper(t.Oc, t) } - buildOuput, err := t.Oc.Run("logs").Args("-f", t.BuildPath, "--timestamps").Output() + buildOuput, buildErr, err := t.Oc.Run("logs").Args("-f", t.BuildPath, "--timestamps", "--v", "10").Outputs() if err != nil { - return "", fmt.Errorf("Error retrieving logs for %#v: %v", *t, err) + return "", fmt.Errorf("Error retrieving logs for build %q: (%s) %v", t.BuildName, buildErr, err) } return buildOuput, nil @@ -790,9 +791,9 @@ func (t *BuildResult) LogsNoTimestamp() (string, error) { return t.LogDumper(t.Oc, t) } - buildOuput, err := t.Oc.Run("logs").Args("-f", t.BuildPath).Output() + buildOuput, buildErr, err := t.Oc.Run("logs").Args("-f", t.BuildPath).Outputs() if err != nil { - return "", fmt.Errorf("Error retrieving logs for %#v: %v", *t, err) + return "", fmt.Errorf("Error retrieving logs for build %q: (%s) %v", t.BuildName, buildErr, err) } return buildOuput, nil @@ -995,9 +996,35 @@ func WaitForServiceAccount(c corev1client.ServiceAccountInterface, name string) return wait.Poll(100*time.Millisecond, 3*time.Minute, waitFn) } -// WaitForNamespaceSCCAnnotations waits up to 2 minutes for the cluster-policy-controller to add the SCC related +// WaitForNamespaceSCCAnnotations waits up to 30s for the cluster-policy-controller to add the SCC related // annotations to the provided namespace. -func WaitForNamespaceSCCAnnotations(c projectv1typedclient.ProjectV1Interface, name string) error { +func WaitForNamespaceSCCAnnotations(c corev1client.CoreV1Interface, name string) error { + waitFn := func() (bool, error) { + ns, err := c.Namespaces().Get(context.Background(), name, metav1.GetOptions{}) + if err != nil { + // it is assumed the project was created prior to calling this, so we + // do not distinguish not found errors + return false, err + } + if ns.Annotations == nil { + return false, nil + } + for k := range ns.Annotations { + // annotations to check based off of + // https://github.com/openshift/cluster-policy-controller/blob/master/pkg/security/controller/namespace_scc_allocation_controller.go#L112 + if k == securityv1.UIDRangeAnnotation { + return true, nil + } + } + e2e.Logf("namespace %s current annotation set: %#v", name, ns.Annotations) + return false, nil + } + return wait.Poll(time.Duration(250*time.Millisecond), 30*time.Minute, waitFn) +} + +// WaitForProjectSCCAnnotations waits up to 30s for the cluster-policy-controller to add the SCC related +// annotations to the provided namespace. +func WaitForProjectSCCAnnotations(c projectv1typedclient.ProjectV1Interface, name string) error { waitFn := func() (bool, error) { proj, err := c.Projects().Get(context.Background(), name, metav1.GetOptions{}) if err != nil { @@ -1018,7 +1045,7 @@ func WaitForNamespaceSCCAnnotations(c projectv1typedclient.ProjectV1Interface, n e2e.Logf("project %s current annotation set: %#v", name, proj.Annotations) return false, nil } - return wait.Poll(time.Duration(15*time.Second), 2*time.Minute, waitFn) + return wait.Poll(time.Duration(500*time.Millisecond), 30*time.Minute, waitFn) } // WaitForAnImageStream waits for an ImageStream to fulfill the isOK function @@ -1069,12 +1096,7 @@ func WaitForAnImageStream(client imagev1typedclient.ImageStreamInterface, // WaitForAnImageStreamTag waits until an image stream with given name has non-empty history for given tag. // Defaults to waiting for 300 seconds func WaitForAnImageStreamTag(oc *CLI, namespace, name, tag string) error { - return TimedWaitForAnImageStreamTag(oc, namespace, name, tag, time.Second*300) -} - -// TimedWaitForAnImageStreamTag waits until an image stream with given name has non-empty history for given tag. -// Gives up waiting after the specified waitTimeout -func TimedWaitForAnImageStreamTag(oc *CLI, namespace, name, tag string, waitTimeout time.Duration) error { + waitTimeout := time.Second * 300 g.By(fmt.Sprintf("waiting for an is importer to import a tag %s into a stream %s", tag, name)) start := time.Now() c := make(chan error) @@ -1409,18 +1431,7 @@ func FixturePath(elem ...string) string { if testsStarted { // extract the contents to disk - if err := testdata.RestoreAssets(fixtureDir, relativePath); err != nil { - panic(err) - } - if err := filepath.Walk(fullPath, func(path string, info os.FileInfo, err error) error { - if err := os.Chmod(path, 0640); err != nil { - return err - } - if stat, err := os.Lstat(path); err == nil && stat.IsDir() { - return os.Chmod(path, 0755) - } - return nil - }); err != nil { + if err := restoreFixtureAssets(fixtureDir, relativePath); err != nil { panic(err) } @@ -1434,21 +1445,71 @@ func FixturePath(elem ...string) string { return absPath } +// restoreFixtureAsset restores an asset under the given directory and post-processes +// any changes required by the test. It hardcodes file modes to 0640 and ensures image +// values are replaced. +func restoreFixtureAsset(dir, name string) error { + data, err := testdata.Asset(name) + if err != nil { + return err + } + data, err = utilimage.ReplaceContents(data) + if err != nil { + return err + } + info, err := testdata.AssetInfo(name) + if err != nil { + return err + } + err = os.MkdirAll(assetFilePath(dir, filepath.Dir(name)), os.FileMode(0755)) + if err != nil { + return err + } + err = ioutil.WriteFile(assetFilePath(dir, name), data, 0640) + if err != nil { + return err + } + err = os.Chtimes(assetFilePath(dir, name), info.ModTime(), info.ModTime()) + if err != nil { + return err + } + return nil +} + +// restoreFixtureAssets restores an asset under the given directory recursively, changing +// any necessary content. This duplicates a method in testdata but with the additional +// requirements for setting disk permissions and for altering image content. +func restoreFixtureAssets(dir, name string) error { + children, err := testdata.AssetDir(name) + // File + if err != nil { + return restoreFixtureAsset(dir, name) + } + // Dir + for _, child := range children { + err = restoreFixtureAssets(dir, filepath.Join(name, child)) + if err != nil { + return err + } + } + return nil +} + +func assetFilePath(dir, name string) string { + cannonicalName := strings.Replace(name, "\\", "/", -1) + return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) +} + // FetchURL grabs the output from the specified url and returns it. // It will retry once per second for duration retryTimeout if an error occurs during the request. func FetchURL(oc *CLI, url string, retryTimeout time.Duration) (string, error) { - ns := oc.KubeFramework().Namespace.Name - execPodName := CreateExecPodOrFail(oc.AdminKubeClient().CoreV1(), ns, string(uuid.NewUUID())) + execPod := CreateExecPodOrFail(oc.AdminKubeClient(), ns, string(uuid.NewUUID())) defer func() { - oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPodName, *metav1.NewDeleteOptions(1)) + oc.AdminKubeClient().CoreV1().Pods(ns).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1)) }() - execPod, err := oc.AdminKubeClient().CoreV1().Pods(ns).Get(context.Background(), execPodName, metav1.GetOptions{}) - if err != nil { - return "", err - } - + var err error var response string waitFn := func() (bool, error) { e2e.Logf("Waiting up to %v to wget %s", retryTimeout, url) @@ -1553,26 +1614,6 @@ func GetEndpointAddress(oc *CLI, name string) (string, error) { return fmt.Sprintf("%s:%d", endpoint.Subsets[0].Addresses[0].IP, endpoint.Subsets[0].Ports[0].Port), nil } -// CreateExecPodOrFail creates a simple busybox pod in a sleep loop used as a -// vessel for kubectl exec commands. -// Returns the name of the created pod. -// TODO: expose upstream -func CreateExecPodOrFail(client corev1client.CoreV1Interface, ns, name string) string { - e2e.Logf("Creating new exec pod") - execPod := e2epod.NewExecPodSpec(ns, name, false) - created, err := client.Pods(ns).Create(context.Background(), execPod, metav1.CreateOptions{}) - o.Expect(err).NotTo(o.HaveOccurred()) - err = wait.PollImmediate(e2e.Poll, 5*time.Minute, func() (bool, error) { - retrievedPod, err := client.Pods(execPod.Namespace).Get(context.Background(), created.Name, metav1.GetOptions{}) - if err != nil { - return false, nil - } - return retrievedPod.Status.Phase == corev1.PodRunning, nil - }) - o.Expect(err).NotTo(o.HaveOccurred()) - return created.Name -} - // CheckForBuildEvent will poll a build for up to 1 minute looking for an event with // the specified reason and message template. func CheckForBuildEvent(client corev1client.CoreV1Interface, build *buildv1.Build, reason, message string) { @@ -1858,37 +1899,6 @@ func GetRouterPodTemplate(oc *CLI) (*corev1.PodTemplateSpec, string, error) { return nil, "", kapierrs.NewNotFound(schema.GroupResource{Group: "apps.openshift.io", Resource: "deploymentconfigs"}, "router") } -// FindImageFormatString returns a format string for components on the cluster. It returns false -// if no format string could be inferred from the cluster. OpenShift 4.0 clusters will not be able -// to infer an image format string, so you must wrap this method in one that can locate your specific -// image. -func FindImageFormatString(oc *CLI) (string, bool) { - // legacy support for 3.x clusters - template, _, err := GetRouterPodTemplate(oc) - if err == nil { - if strings.Contains(template.Spec.Containers[0].Image, "haproxy-router") { - return strings.Replace(template.Spec.Containers[0].Image, "haproxy-router", "${component}", -1), true - } - } - // in openshift 4.0, no image format can be calculated on cluster - return "openshift/origin-${component}:latest", false -} - -func FindCLIImage(oc *CLI) (string, bool) { - // look up image stream - is, err := oc.AdminImageClient().ImageV1().ImageStreams("openshift").Get(context.Background(), "cli", metav1.GetOptions{}) - if err == nil { - for _, tag := range is.Spec.Tags { - if tag.Name == "latest" && tag.From != nil && tag.From.Kind == "DockerImage" { - return tag.From.Name, true - } - } - } - - format, ok := FindImageFormatString(oc) - return strings.Replace(format, "${component}", "cli", -1), ok -} - func FindRouterImage(oc *CLI) (string, error) { configclient := oc.AdminConfigClient().ConfigV1() o, err := configclient.ClusterOperators().Get(context.Background(), "ingress", metav1.GetOptions{}) diff --git a/test/extended/util/image/OWNERS b/test/extended/util/image/OWNERS new file mode 100644 index 000000000000..98aaf1638b20 --- /dev/null +++ b/test/extended/util/image/OWNERS @@ -0,0 +1,9 @@ +# See the OWNERS docs at https://go.k8s.io/owners +reviewers: +- smarterclayton +- soltysh +- sttts +approvers: +- smarterclayton +- soltysh +- sttts diff --git a/test/extended/util/image/README.md b/test/extended/util/image/README.md new file mode 100644 index 000000000000..28c594d903c0 --- /dev/null +++ b/test/extended/util/image/README.md @@ -0,0 +1,95 @@ +# Images used by e2e tests + +We limit the set of images used by e2e to reduce duplication and to allow us to provide offline mirroring of images for customers and restricted test environments. Every image used in e2e must be part of this utility package or referenced by the upstream `k8s.io/kubernetes/test/utils/image` package. + +All images used by e2e are mirrored to: + + quay.io/openshift/community-e2e-images:TAG + +for easy mirroring by the `openshift-tests images` command. + +## To add a new image: + +1. Identify whether your use case can be solved by an existing image: + * The standard "shell" image provided by `ShellImage()` that is available on all clusters and has bash + a set of standard tools available. Use this by default. + * An upstream image that is provided by `test/utils/image`. +2. If your use case is novel, you must: + * Describe your use case in a PR to this file and have it approved + * Define a standard CI build and publish the image to quay.io in the openshift namespace + * Add the new reference to the `init()` method in this package + * Reference your image inside your tests tests using `github.com/openshift/origin/test/extended/util/image.LocationFor("my.source/image/location:versioned_tag")` + * Regenerate the verify output with `make update` and compare the diff to see your source image located + * Ensure your tests fail with "image cannot be pulled" errors. + * Have the reviewer promote the image to the quay mirror location. + * The reviewer should approve the PR and merge. + +When adding a new image, first make the code changes and compile the `openshift-tests` binary. Then run `hack/update-generated-bindata.sh` to update `test/extended/util/image/zz_generated.txt`. Contact one of the OWNERS of this directory and have them review the image for inclusion into our suite (usually granted in the process above). Before merge and after review they will run the following command to mirror the content to quay: + + openshift-tests images --upstream --to-repository quay.io/openshift/community-e2e-images | oc image mirror -f - --filter-by-os=.* + +To become an OWNER in this directory you must be given permission to push to this repo by another OWNER. + +### Kube exceptions: + +* `webserver:404` - used to access an image that does not exist +* `gcr.io/google_samples/gb-redisslave:nonexistent` - used to access an auth protected upstream image +* `gcr.io/authenticated-image-pulling/alpine:3.7` - used to access an image that is authenticated and verify that pulls fail or succeed, cannot be mirrored +* `invalid.com/invalid/alpine:3.1` + +### OpenShift exceptions + +* Temporary + * `docker.io/summerwind/h2spec:2.4.0` - for HTTP2 testing, waiting for mirror + +## When rebasing + +When a new version of Kubernetes is introduced new images will likely need to be mirrored. The failure will be pods that fail to start, usually with an ImagePullBackoff error (the image isn't available at `quay.io/openshift/community-e2e-images:*`). + +1. Perform a rebase of openshift/origin and open a pull request +2. Observe whether any tests fail due to missing images +3. Notify an OWNER in this file, who will run: + + openshift-tests images --upstream --to-repository quay.io/openshift/community-e2e-images | oc image mirror -f - --filter-by-os=.* + +4. Retest the PR, which should pass or identify new failures +5. If an upstream image is removed that OpenShift tests depend on, those tests should be refactored to use the appropriate equivalent. + +Step 3 only has to be run once per new image version introduced in a test. + + +## When reviewing + +We control images so that we are confident that if a user ran the tests binary in a controlled and protected offline environment that we are not introducing excessive risk for the user by running the tests (which run privileged). That means: + +* Using images that are reproducible - can be updated if a security vulnerability is found +* Using images that are published to a secured location - a malicious third party shouldn't be able to trivially take over the location the image is published to to inject an invalid tag +* Using images that are versioned - `latest` or rolling tags where the API of the image can be broken MUST NOT be allowed, because then a future mirror might regress old tests in old versions + +Kubernetes has a working process that we consider acceptable for upstream images documented at https://github.com/kubernetes/kubernetes/blob/master/test/images/README.md - images maintained by other communities likely do not satisfy these criteria and must be reviewed with these criteria in mind. + +OpenShift test images must be built via CI and published to quay in a versioned fashion (no regressions). + +New images should be added when: + +1. An upstream component refactors to use a different image + 1. Ask whether the upstream image is a better image (i.e. is it better managed, more generic, well built, kept up to date by some process) +2. A new test is added and needs an image AND none of the existing images are sufficient AND none of the existing images can be extended to solve it + 1. I.e. agnhost is a generic tool for simulating clients inside a pod, and so it is better to use that function OR extend it than adding a separate test simulation + 2. The shell image is the ultimate catch all - ANY bash code that isn't wierd should use that. If the bash code needs a novel new command we should add it to the `tools` image (which shell image points to) if it matches the criteria for tools (small Linux utilities that are useful for debugging an openshift cluster / node that are likely to be useful in a wide range of areas) + 3. Don't introduce new versions of an existing image unless there is no choice - i.e. if you need `redis` and are not testing a specific version of redis, just use the existing image + +### Mirroring images for approved changes before the PR is merged + +In order to merge the PR, the tests have to pass, which means the new image has to be mirrored prior to merge. + +When mirroring from a PR (granting access), you should check out the PR in question and build locally. You should probably rebase the local PR to ensure you don't stomp changes in master (checking out a PR doesn't exactly match what is tested). + +Then run + + openshift-tests images --upstream --to-repository quay.io/openshift/community-e2e-images + +to verify that all things check out. If everything looks good, run + + openshift-tests images --upstream --to-repository quay.io/openshift/community-e2e-images | oc image mirror -f - --filter-by-os=.* + +You must be logged in (to docker, using `oc registry login --registry=quay.io` or `skopeo login` or `docker login`) to a quay account that has write permission to `quay.io/openshift/community-e2e-images` which every OWNER should have. \ No newline at end of file diff --git a/test/extended/util/image/image.go b/test/extended/util/image/image.go new file mode 100644 index 000000000000..b1a7b888a19c --- /dev/null +++ b/test/extended/util/image/image.go @@ -0,0 +1,204 @@ +package image + +import ( + "crypto/sha256" + "encoding/base64" + "fmt" + "os" + "regexp" + "strings" +) + +func init() { + allowedImages = map[string]int{ + // used by open ldap tests + "docker.io/mrogers950/origin-openldap-test:fedora29": -1, + + // used by multicast test, should be moved to publish to quay + "docker.io/openshift/test-multicast:latest": -1, + + // used by oc mirror test, should be moved to publish to quay + "docker.io/library/registry:2.7.1": -1, + + // used by build s2i e2e's to verify that builder with USER root are not allowed + // the github.com/openshift/build-test-images repo is built out of github.com/openshift/release + "registry.svc.ci.openshift.org/ocp/4.7:test-build-roots2i": -1, + + // moved to GCR + "k8s.gcr.io/sig-storage/csi-attacher:v2.2.0": -1, + "k8s.gcr.io/sig-storage/csi-attacher:v3.0.0": -1, + "k8s.gcr.io/sig-storage/csi-node-driver-registrar:v1.2.0": -1, + "k8s.gcr.io/sig-storage/csi-node-driver-registrar:v1.3.0": -1, + "k8s.gcr.io/sig-storage/csi-provisioner:v1.6.0": -1, + "k8s.gcr.io/sig-storage/csi-provisioner:v2.0.0": -1, + "k8s.gcr.io/sig-storage/csi-resizer:v0.4.0": -1, + "k8s.gcr.io/sig-storage/csi-resizer:v0.5.0": -1, + "k8s.gcr.io/sig-storage/csi-snapshotter:v2.0.1": -1, + "k8s.gcr.io/sig-storage/csi-snapshotter:v2.1.0": -1, + "k8s.gcr.io/sig-storage/hostpathplugin:v1.4.0": -1, + "k8s.gcr.io/sig-storage/livenessprobe:v1.1.0": -1, + "k8s.gcr.io/sig-storage/mock-driver:v4.0.2": -1, + "k8s.gcr.io/sig-storage/snapshot-controller:v2.1.1": -1, + + // allowed upstream kube images - index and value must match upstream or + // tests will fail + "k8s.gcr.io/e2e-test-images/agnhost:2.20": 1, + "docker.io/library/nginx:1.14-alpine": 23, + "docker.io/library/nginx:1.15-alpine": 24, + "docker.io/library/redis:5.0.5-alpine": 31, + } + + images = GetMappedImages(allowedImages, os.Getenv("KUBE_TEST_REPO")) +} + +var ( + images map[string]string + allowedImages map[string]int +) + +// ReplaceContents ensures that the provided yaml or json has the +// correct embedded image content. +func ReplaceContents(data []byte) ([]byte, error) { + // exactImageFormat attempts to match a string on word boundaries + const exactImageFormat = `\b%s\b` + + patterns := make(map[string]*regexp.Regexp) + for from, to := range images { + pattern := fmt.Sprintf(exactImageFormat, regexp.QuoteMeta(from)) + re, err := regexp.Compile(pattern) + if err != nil { + return nil, err + } + patterns[to] = re + } + + for to, pattern := range patterns { + data = pattern.ReplaceAll(data, []byte(to)) + } + + return data, nil +} + +// MustReplaceContents invokes ReplaceContents and panics if any +// replacement error occurs. +func MustReplaceContents(data []byte) []byte { + data, err := ReplaceContents(data) + if err != nil { + panic(err) + } + return data +} + +// LocationFor returns the appropriate URL for the provided image. +func LocationFor(image string) string { + pull, ok := images[image] + if !ok { + panic(fmt.Sprintf(`The image %q is not one of the pre-approved test images. + +To add a new image to OpenShift tests you must follow the process described in +the test/extended/util/image/README.md file.`, image)) + } + return pull +} + +// ShellImage returns a docker pull spec that any pod on the cluster +// has access to that contains bash and standard commandline tools. +// This image should be used for all generic e2e shell scripts. This +// image has oc. +// +// If the script you are running does not have a specific tool available +// that is required, open an issue to github.com/openshift/images in the +// images/tools directory to discuss adding that package. In general, try +// to avoid the need to add packages by using simpler concepts or consider +// extending an existing image. +func ShellImage() string { + return "image-registry.openshift-image-registry.svc:5000/openshift/tools:latest" +} + +// LimitedShellImage returns a docker pull spec that any pod on the cluster +// has access to that contains bash and standard commandline tools. +// This image should be used when you only need oc and can't use the shell image. +// This image has oc. +// +// TODO: this will be removed when https://bugzilla.redhat.com/show_bug.cgi?id=1843232 +// is fixed +func LimitedShellImage() string { + return "image-registry.openshift-image-registry.svc:5000/openshift/cli:latest" +} + +// OpenLDAPTestImage returns the LDAP test image. +func OpenLDAPTestImage() string { + return LocationFor("docker.io/mrogers950/origin-openldap-test:fedora29") +} + +// OriginalImages returns a map of the original image names. +func OriginalImages() map[string]int { + images := make(map[string]int) + for k, v := range allowedImages { + images[k] = v + } + return images +} + +// Images returns a map of all images known to the test package. +func Images() map[string]struct{} { + copied := make(map[string]struct{}) + for k := range images { + copied[k] = struct{}{} + } + return copied +} + +// GetMappedImages returns the images if they were mapped to the provided +// image repository. The keys of the returned map are the same as the keys +// in originalImages and the values are the equivalent name in the target +// repo. +func GetMappedImages(originalImages map[string]int, repo string) map[string]string { + if len(repo) == 0 { + images := make(map[string]string) + for k := range originalImages { + images[k] = k + } + return images + } + configs := make(map[string]string) + reCharSafe := regexp.MustCompile(`[^\w]`) + reDashes := regexp.MustCompile(`-+`) + h := sha256.New() + + const ( + // length of hash in base64-url chosen to minimize possible collisions (64^16 possible) + hashLength = 16 + // maximum length of a Docker spec image tag + maxTagLength = 127 + // when building a tag, there are at most 6 characters in the format (e2e and 3 dashes), + // and we should allow up to 10 digits for the index and additional qualifiers we may add + // in the future + tagFormatCharacters = 6 + 10 + ) + + parts := strings.SplitN(repo, "/", 2) + registry, destination := parts[0], parts[1] + for pullSpec, index := range originalImages { + // Build a new tag with a the index, a hash of the image spec (to be unique) and + // shorten and make the pull spec "safe" so it will fit in the tag + h.Reset() + h.Write([]byte(pullSpec)) + hash := base64.RawURLEncoding.EncodeToString(h.Sum(nil))[:hashLength] + shortName := reCharSafe.ReplaceAllLiteralString(pullSpec, "-") + shortName = reDashes.ReplaceAllLiteralString(shortName, "-") + maxLength := maxTagLength - hashLength - tagFormatCharacters + if len(shortName) > maxLength { + shortName = shortName[len(shortName)-maxLength:] + } + var newTag string + if index == -1 { + newTag = fmt.Sprintf("e2e-%s-%s", shortName, hash) + } else { + newTag = fmt.Sprintf("e2e-%d-%s-%s", index, shortName, hash) + } + + configs[pullSpec] = fmt.Sprintf("%s/%s:%s", registry, destination, newTag) + } + return configs +} diff --git a/test/extended/util/image/zz_generated.txt b/test/extended/util/image/zz_generated.txt new file mode 100644 index 000000000000..bb727de8c912 --- /dev/null +++ b/test/extended/util/image/zz_generated.txt @@ -0,0 +1,53 @@ +# This file is generated by hack/update-generated-bindata.sh +docker.io/gluster/glusterdynamic-provisioner:v1.0 quay.io/openshift/community-e2e-images:e2e-14-docker-io-gluster-glusterdynamic-provisioner-v1-0-KoXS0hk-A1Z9s5b8 +docker.io/library/busybox:1.29 quay.io/openshift/community-e2e-images:e2e-7-docker-io-library-busybox-1-29-pBq11zdTXE-KGsre +docker.io/library/httpd:2.4.38-alpine quay.io/openshift/community-e2e-images:e2e-15-docker-io-library-httpd-2-4-38-alpine-PcS4HbFNhO5PfBub +docker.io/library/httpd:2.4.39-alpine quay.io/openshift/community-e2e-images:e2e-16-docker-io-library-httpd-2-4-39-alpine-Gj-c8OFZVVxvtHu2 +docker.io/library/nginx:1.14-alpine quay.io/openshift/community-e2e-images:e2e-23-docker-io-library-nginx-1-14-alpine-yxm61cIl0fz2I0Zz +docker.io/library/nginx:1.15-alpine quay.io/openshift/community-e2e-images:e2e-24-docker-io-library-nginx-1-15-alpine-l2aP4Mr7LpVdV6gu +docker.io/library/perl:5.26 quay.io/openshift/community-e2e-images:e2e-28-docker-io-library-perl-5-26-FBqTQxmHsu0UjDlZ +docker.io/library/redis:5.0.5-alpine quay.io/openshift/community-e2e-images:e2e-31-docker-io-library-redis-5-0-5-alpine-dd1_y0PD70cxSx_m +docker.io/library/registry:2.7.1 quay.io/openshift/community-e2e-images:e2e-docker-io-library-registry-2-7-1-g9zRqt2aidLQrnbe +docker.io/mrogers950/origin-openldap-test:fedora29 quay.io/openshift/community-e2e-images:e2e-docker-io-mrogers950-origin-openldap-test-fedora29-spJ_eLUO2k2GFYK_ +docker.io/openshift/test-multicast:latest quay.io/openshift/community-e2e-images:e2e-docker-io-openshift-test-multicast-latest-4AxcBBxKg_prX34z +gcr.io/kubernetes-e2e-test-images/apparmor-loader:1.0 quay.io/openshift/community-e2e-images:e2e-4-gcr-io-kubernetes-e2e-test-images-apparmor-loader-1-0-aNcoUDFEmADPugAY +gcr.io/kubernetes-e2e-test-images/cuda-vector-add:1.0 quay.io/openshift/community-e2e-images:e2e-9-gcr-io-kubernetes-e2e-test-images-cuda-vector-add-1-0-8kiue1R1E2L4K4Cu +gcr.io/kubernetes-e2e-test-images/cuda-vector-add:2.0 quay.io/openshift/community-e2e-images:e2e-10-gcr-io-kubernetes-e2e-test-images-cuda-vector-add-2-0-athN2DOyoc4ux5JO +gcr.io/kubernetes-e2e-test-images/echoserver:2.2 quay.io/openshift/community-e2e-images:e2e-12-gcr-io-kubernetes-e2e-test-images-echoserver-2-2-flifUTtzBQYThevq +gcr.io/kubernetes-e2e-test-images/ipc-utils:1.0 quay.io/openshift/community-e2e-images:e2e-18-gcr-io-kubernetes-e2e-test-images-ipc-utils-1-0-bVpFSazzlPF0h7Sh +gcr.io/kubernetes-e2e-test-images/jessie-dnsutils:1.0 quay.io/openshift/community-e2e-images:e2e-19-gcr-io-kubernetes-e2e-test-images-jessie-dnsutils-1-0-eIx8izd3E579FYKJ +gcr.io/kubernetes-e2e-test-images/kitten:1.0 quay.io/openshift/community-e2e-images:e2e-20-gcr-io-kubernetes-e2e-test-images-kitten-1-0-nyaXRBZKp1MUalek +gcr.io/kubernetes-e2e-test-images/metadata-concealment:1.2 quay.io/openshift/community-e2e-images:e2e-8-gcr-io-kubernetes-e2e-test-images-metadata-concealment-1-2-hVXHl0CaKh0yxj30 +gcr.io/kubernetes-e2e-test-images/nautilus:1.0 quay.io/openshift/community-e2e-images:e2e-21-gcr-io-kubernetes-e2e-test-images-nautilus-1-0-ot9uKfkPJ1nHoaa5 +gcr.io/kubernetes-e2e-test-images/nonewprivs:1.0 quay.io/openshift/community-e2e-images:e2e-25-gcr-io-kubernetes-e2e-test-images-nonewprivs-1-0-99FQZQqpju_wLImS +gcr.io/kubernetes-e2e-test-images/nonroot:1.0 quay.io/openshift/community-e2e-images:e2e-26-gcr-io-kubernetes-e2e-test-images-nonroot-1-0-6UP--2eZSLen4EJ- +gcr.io/kubernetes-e2e-test-images/regression-issue-74839-amd64:1.0 quay.io/openshift/community-e2e-images:e2e-32-gcr-io-kubernetes-e2e-test-images-regression-issue-74839-amd64-1-0-zKI5eDEBSTF6x1_L +gcr.io/kubernetes-e2e-test-images/resource-consumer:1.5 quay.io/openshift/community-e2e-images:e2e-33-gcr-io-kubernetes-e2e-test-images-resource-consumer-1-5-dkUnrzChb3aARMbw +gcr.io/kubernetes-e2e-test-images/sample-apiserver:1.17 quay.io/openshift/community-e2e-images:e2e-3-gcr-io-kubernetes-e2e-test-images-sample-apiserver-1-17-NgZupChxq-wmkUzw +gcr.io/kubernetes-e2e-test-images/volume/gluster:1.0 quay.io/openshift/community-e2e-images:e2e-37-gcr-io-kubernetes-e2e-test-images-volume-gluster-1-0-gLYeM8gU2klsD8wi +gcr.io/kubernetes-e2e-test-images/volume/iscsi:2.0 quay.io/openshift/community-e2e-images:e2e-36-gcr-io-kubernetes-e2e-test-images-volume-iscsi-2-0-RuKnuHHE9bwOcqDI +gcr.io/kubernetes-e2e-test-images/volume/nfs:1.0 quay.io/openshift/community-e2e-images:e2e-35-gcr-io-kubernetes-e2e-test-images-volume-nfs-1-0-AW-qOVYbJYyLsrEa +gcr.io/kubernetes-e2e-test-images/volume/rbd:1.0.1 quay.io/openshift/community-e2e-images:e2e-38-gcr-io-kubernetes-e2e-test-images-volume-rbd-1-0-1-ijh6-o3bvnWWIAFM +k8s.gcr.io/build-image/debian-iptables:v12.1.2 quay.io/openshift/community-e2e-images:e2e-11-k8s-gcr-io-build-image-debian-iptables-v12-1-2-KNXT7NtTs4Px1rYf +k8s.gcr.io/e2e-test-images/agnhost:2.20 quay.io/openshift/community-e2e-images:e2e-1-k8s-gcr-io-e2e-test-images-agnhost-2-20-1f8SSDq8Y3dr2Xfm +k8s.gcr.io/etcd:3.4.13-0 quay.io/openshift/community-e2e-images:e2e-13-k8s-gcr-io-etcd-3-4-13-0-VKSltRW2wd8-QWft +k8s.gcr.io/pause:3.2 quay.io/openshift/community-e2e-images:e2e-27-k8s-gcr-io-pause-3-2-pZ7kB8CESdFpJJRs +k8s.gcr.io/prometheus-dummy-exporter:v0.1.0 quay.io/openshift/community-e2e-images:e2e-29-k8s-gcr-io-prometheus-dummy-exporter-v0-1-0-fNZIUrKnAwcvKTvF +k8s.gcr.io/prometheus-to-sd:v0.5.0 quay.io/openshift/community-e2e-images:e2e-30-k8s-gcr-io-prometheus-to-sd-v0-5-0-6JI59Yih4oaj3oQO +k8s.gcr.io/sd-dummy-exporter:v0.2.0 quay.io/openshift/community-e2e-images:e2e-34-k8s-gcr-io-sd-dummy-exporter-v0-2-0-pPp4DDTpVamU2YNi +k8s.gcr.io/sig-storage/csi-attacher:v2.2.0 quay.io/openshift/community-e2e-images:e2e-k8s-gcr-io-sig-storage-csi-attacher-v2-2-0-rkWV0rp07ep86NLk +k8s.gcr.io/sig-storage/csi-attacher:v3.0.0 quay.io/openshift/community-e2e-images:e2e-k8s-gcr-io-sig-storage-csi-attacher-v3-0-0-aRfAQ93WCiGD8Zvq +k8s.gcr.io/sig-storage/csi-node-driver-registrar:v1.2.0 quay.io/openshift/community-e2e-images:e2e-k8s-gcr-io-sig-storage-csi-node-driver-registrar-v1-2-0-61xf9FtqLwOVEKfv +k8s.gcr.io/sig-storage/csi-node-driver-registrar:v1.3.0 quay.io/openshift/community-e2e-images:e2e-k8s-gcr-io-sig-storage-csi-node-driver-registrar-v1-3-0-2QBE0hLaWwzOxqR6 +k8s.gcr.io/sig-storage/csi-provisioner:v1.6.0 quay.io/openshift/community-e2e-images:e2e-k8s-gcr-io-sig-storage-csi-provisioner-v1-6-0-JY3N9ZcwCflk372F +k8s.gcr.io/sig-storage/csi-provisioner:v2.0.0 quay.io/openshift/community-e2e-images:e2e-k8s-gcr-io-sig-storage-csi-provisioner-v2-0-0-twLyh6EaAecaDbK8 +k8s.gcr.io/sig-storage/csi-resizer:v0.4.0 quay.io/openshift/community-e2e-images:e2e-k8s-gcr-io-sig-storage-csi-resizer-v0-4-0-XqHBnRtAgovNyXK3 +k8s.gcr.io/sig-storage/csi-resizer:v0.5.0 quay.io/openshift/community-e2e-images:e2e-k8s-gcr-io-sig-storage-csi-resizer-v0-5-0-O79EW2-1fDT39X15 +k8s.gcr.io/sig-storage/csi-snapshotter:v2.0.1 quay.io/openshift/community-e2e-images:e2e-k8s-gcr-io-sig-storage-csi-snapshotter-v2-0-1-NIPtB_SC-LRqBaeq +k8s.gcr.io/sig-storage/csi-snapshotter:v2.1.0 quay.io/openshift/community-e2e-images:e2e-k8s-gcr-io-sig-storage-csi-snapshotter-v2-1-0-1kbgyjhsZ5sWpBwq +k8s.gcr.io/sig-storage/hostpathplugin:v1.4.0 quay.io/openshift/community-e2e-images:e2e-k8s-gcr-io-sig-storage-hostpathplugin-v1-4-0-AfY5JyX6DsfCefAR +k8s.gcr.io/sig-storage/livenessprobe:v1.1.0 quay.io/openshift/community-e2e-images:e2e-k8s-gcr-io-sig-storage-livenessprobe-v1-1-0-d49j-mlARufXkhrZ +k8s.gcr.io/sig-storage/mock-driver:v4.0.2 quay.io/openshift/community-e2e-images:e2e-k8s-gcr-io-sig-storage-mock-driver-v4-0-2-GE9vfPm7mdvjzZh_ +k8s.gcr.io/sig-storage/nfs-provisioner:v2.2.2 quay.io/openshift/community-e2e-images:e2e-22-k8s-gcr-io-sig-storage-nfs-provisioner-v2-2-2-dbgtOCwYmEGggl01 +k8s.gcr.io/sig-storage/snapshot-controller:v2.1.1 quay.io/openshift/community-e2e-images:e2e-k8s-gcr-io-sig-storage-snapshot-controller-v2-1-1-n5BM_jX2npV3RxHM +registry.svc.ci.openshift.org/ocp/4.7:test-build-roots2i quay.io/openshift/community-e2e-images:e2e-registry-svc-ci-openshift-org-ocp-4-7-test-build-roots2i-ZzDWhWn0wPB9cLFM diff --git a/test/extended/util/jenkins/ref.go b/test/extended/util/jenkins/ref.go index 952981a9940d..55dced6cbe26 100644 --- a/test/extended/util/jenkins/ref.go +++ b/test/extended/util/jenkins/ref.go @@ -61,9 +61,9 @@ type Definition struct { // NewRef creates a jenkins reference from an OC client func NewRef(oc *exutil.CLI) *JenkinsRef { g.By("get ip and port for jenkins service") - serviceIP, err := oc.AsAdmin().Run("get").Args("svc", "jenkins").Template("{{.spec.clusterIP}}").Output() + serviceIP, err := oc.AsAdmin().Run("get").Args("svc", "jenkins", "--output=template", "--template={{.spec.clusterIP}}").Output() o.Expect(err).NotTo(o.HaveOccurred()) - port, err := oc.AsAdmin().Run("get").Args("svc", "jenkins").Template("{{ $x := index .spec.ports 0}}{{$x.port}}").Output() + port, err := oc.AsAdmin().Run("get").Args("svc", "jenkins", "--output=template", "--template={{ $x := index .spec.ports 0}}{{$x.port}}").Output() o.Expect(err).NotTo(o.HaveOccurred()) g.By("get token via whoami") diff --git a/test/extended/util/kubevirt/provider.go b/test/extended/util/kubevirt/provider.go new file mode 100644 index 000000000000..30caaa550b08 --- /dev/null +++ b/test/extended/util/kubevirt/provider.go @@ -0,0 +1,18 @@ +package kubevirt + +import ( + "k8s.io/kubernetes/test/e2e/framework" +) + +func init() { + framework.RegisterProvider("kubevirt", newProvider) +} + +func newProvider() (framework.ProviderInterface, error) { + return &Provider{}, nil +} + +// Provider is a structure to handle kubevirt for e2e testing +type Provider struct { + framework.NullProvider +} diff --git a/test/extended/util/ldap.go b/test/extended/util/ldap.go index 8f9956ee33e8..5b8ec6d90d30 100644 --- a/test/extended/util/ldap.go +++ b/test/extended/util/ldap.go @@ -19,15 +19,14 @@ import ( "github.com/openshift/library-go/pkg/crypto" "github.com/openshift/library-go/pkg/operator/resource/resourceread" "github.com/openshift/origin/test/extended/testdata" + "github.com/openshift/origin/test/extended/util/image" ) const ( - // This image is used for both client and server pods. Temporary repo location. - OpenLDAPTestImage = "docker.io/mrogers950/origin-openldap-test:fedora29" - caCertFilename = "ca.crt" - caKeyFilename = "ca.key" - caName = "ldap CA" - saName = "ldap" + caCertFilename = "ca.crt" + caKeyFilename = "ca.key" + caName = "ldap CA" + saName = "ldap" // These names are in sync with those in ldapserver-deployment.yaml configMountName = "ldap-config" certMountName = "ldap-cert" @@ -181,7 +180,7 @@ func checkLDAPConn(oc *CLI, host string) error { // Run an ldapsearch in a pod against host. func runLDAPSearchInPod(oc *CLI, host string) (string, error) { mounts, volumes := LDAPClientMounts() - output, errs := RunOneShotCommandPod(oc, "runonce-ldapsearch-pod", OpenLDAPTestImage, fmt.Sprintf(ldapSearchCommandFormat, host), mounts, volumes, nil, 8*time.Minute) + output, errs := RunOneShotCommandPod(oc, "runonce-ldapsearch-pod", image.OpenLDAPTestImage(), fmt.Sprintf(ldapSearchCommandFormat, host), mounts, volumes, nil, 8*time.Minute) if len(errs) != 0 { return output, fmt.Errorf("errors encountered trying to run ldapsearch pod: %v", errs) } @@ -189,8 +188,8 @@ func runLDAPSearchInPod(oc *CLI, host string) (string, error) { } func ReadLDAPServerTestData() (*app.Deployment, *corev1.Service, *corev1.ConfigMap, *corev1.ConfigMap) { - return resourceread.ReadDeploymentV1OrDie(testdata.MustAsset( - "test/extended/testdata/ldap/ldapserver-deployment.yaml")), + return resourceread.ReadDeploymentV1OrDie(image.MustReplaceContents(testdata.MustAsset( + "test/extended/testdata/ldap/ldapserver-deployment.yaml"))), resourceread.ReadServiceV1OrDie(testdata.MustAsset( "test/extended/testdata/ldap/ldapserver-service.yaml")), resourceread.ReadConfigMapV1OrDie(testdata.MustAsset( diff --git a/test/extended/util/oauthserver/tokencmd/basicauth.go b/test/extended/util/oauthserver/tokencmd/basicauth.go index 53eb505d0e98..e0424e08c756 100644 --- a/test/extended/util/oauthserver/tokencmd/basicauth.go +++ b/test/extended/util/oauthserver/tokencmd/basicauth.go @@ -8,7 +8,7 @@ import ( "regexp" "strings" - "k8s.io/klog" + "k8s.io/klog/v2" ) type BasicChallengeHandler struct { diff --git a/test/extended/util/oauthserver/tokencmd/multi.go b/test/extended/util/oauthserver/tokencmd/multi.go index 8f2094a11fc4..bcdb3774e732 100644 --- a/test/extended/util/oauthserver/tokencmd/multi.go +++ b/test/extended/util/oauthserver/tokencmd/multi.go @@ -3,7 +3,7 @@ package tokencmd import ( "net/http" - "k8s.io/klog" + "k8s.io/klog/v2" apierrs "k8s.io/apimachinery/pkg/api/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors" diff --git a/test/extended/util/oauthserver/tokencmd/negotiate.go b/test/extended/util/oauthserver/tokencmd/negotiate.go index 5d595a48a7ba..64dc757954d0 100644 --- a/test/extended/util/oauthserver/tokencmd/negotiate.go +++ b/test/extended/util/oauthserver/tokencmd/negotiate.go @@ -6,7 +6,7 @@ import ( "net/http" "strings" - "k8s.io/klog" + "k8s.io/klog/v2" ) // Negotiator defines the minimal interface needed to interact with GSSAPI to perform a negotiate challenge/response diff --git a/test/extended/util/oauthserver/tokencmd/request_token.go b/test/extended/util/oauthserver/tokencmd/request_token.go index 0aac44e0c48a..0e94f5b43138 100644 --- a/test/extended/util/oauthserver/tokencmd/request_token.go +++ b/test/extended/util/oauthserver/tokencmd/request_token.go @@ -18,7 +18,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" restclient "k8s.io/client-go/rest" - "k8s.io/klog" + "k8s.io/klog/v2" "github.com/openshift/library-go/pkg/oauth/oauthdiscovery" ) diff --git a/test/extended/util/operator/settle.go b/test/extended/util/operator/settle.go new file mode 100644 index 000000000000..1ea6ae938dd8 --- /dev/null +++ b/test/extended/util/operator/settle.go @@ -0,0 +1,94 @@ +package operator + +import ( + "context" + "fmt" + "strings" + "time" + + configv1 "github.com/openshift/api/config/v1" + clientconfigv1 "github.com/openshift/client-go/config/clientset/versioned" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/kubernetes/test/e2e/framework" +) + +func WaitForOperatorsToSettleWithDefaultClient(ctx context.Context) error { + cfg := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(clientcmd.NewDefaultClientConfigLoadingRules(), &clientcmd.ConfigOverrides{}) + clusterConfig, err := cfg.ClientConfig() + if err != nil { + return fmt.Errorf("could not load client configuration: %v", err) + } + configClient, err := clientconfigv1.NewForConfig(clusterConfig) + if err != nil { + return err + } + return WaitForOperatorsToSettle(ctx, configClient) +} + +// can be overridden for tests +var nowFn = realNow + +func realNow() time.Time { + return time.Now() +} + +func WaitForOperatorsToSettle(ctx context.Context, configClient clientconfigv1.Interface) error { + framework.Logf("Waiting for operators to settle") + unsettledOperatorStatus := []string{} + if err := wait.PollImmediate(10*time.Second, 5*time.Minute, func() (bool, error) { + coList, err := configClient.ConfigV1().ClusterOperators().List(ctx, metav1.ListOptions{}) + if err != nil { + framework.Logf("error getting ClusterOperators %v", err) + return false, nil + } + unsettledOperatorStatus = unsettledOperators(coList.Items) + done := len(unsettledOperatorStatus) == 0 + return done, nil + + }); err != nil { + return fmt.Errorf("ClusterOperators did not settle: \n%v", strings.Join(unsettledOperatorStatus, "\n\t")) + } + return nil +} + +func unsettledOperators(operators []configv1.ClusterOperator) []string { + unsettledOperatorStatus := []string{} + for _, co := range operators { + available := findCondition(co.Status.Conditions, configv1.OperatorAvailable) + degraded := findCondition(co.Status.Conditions, configv1.OperatorDegraded) + progressing := findCondition(co.Status.Conditions, configv1.OperatorProgressing) + if available.Status == configv1.ConditionTrue && + degraded.Status == configv1.ConditionFalse && + progressing.Status == configv1.ConditionFalse { + continue + } + if available.Status != configv1.ConditionTrue { + unsettledOperatorStatus = append(unsettledOperatorStatus, fmt.Sprintf("clusteroperator/%v is not Available for %v because %q", co.Name, nowFn().Sub(available.LastTransitionTime.Time), available.Message)) + } + if degraded.Status != configv1.ConditionFalse { + unsettledOperatorStatus = append(unsettledOperatorStatus, fmt.Sprintf("clusteroperator/%v is Degraded for %v because %q", co.Name, nowFn().Sub(degraded.LastTransitionTime.Time), degraded.Message)) + } + if progressing.Status != configv1.ConditionFalse { + unsettledOperatorStatus = append(unsettledOperatorStatus, fmt.Sprintf("clusteroperator/%v is Progressing for %v because %q", co.Name, nowFn().Sub(progressing.LastTransitionTime.Time), progressing.Message)) + } + } + return unsettledOperatorStatus +} + +func findCondition(conditions []configv1.ClusterOperatorStatusCondition, name configv1.ClusterStatusConditionType) *configv1.ClusterOperatorStatusCondition { + for i := range conditions { + if name == conditions[i].Type { + return &conditions[i] + } + } + return nil +} + +func conditionHasStatus(c *configv1.ClusterOperatorStatusCondition, status configv1.ConditionStatus) bool { + if c == nil { + return false + } + return c.Status == status +} diff --git a/test/extended/util/operator/settle_test.go b/test/extended/util/operator/settle_test.go new file mode 100644 index 000000000000..f46a2a06c32d --- /dev/null +++ b/test/extended/util/operator/settle_test.go @@ -0,0 +1,153 @@ +package operator + +import ( + "reflect" + "testing" + "time" + + configv1 "github.com/openshift/api/config/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func fakeNow() time.Time { + fakeNow, err := time.Parse("Mon Jan 2 15:04:05 -0700 MST 2006", "Mon Jan 2 15:04:05 -0700 MST 2006") + if err != nil { + panic(err) + } + return fakeNow +} + +func newOperator(name string, + available, availableMessage string, availableDuration time.Duration, + degraded, degradedMessage string, degradedDuration time.Duration, + progressing, progressingMessage string, progressingDuration time.Duration, +) configv1.ClusterOperator { + return configv1.ClusterOperator{ + ObjectMeta: metav1.ObjectMeta{Name: name}, + Status: configv1.ClusterOperatorStatus{ + Conditions: []configv1.ClusterOperatorStatusCondition{ + { + Type: "Available", + Status: configv1.ConditionStatus(available), + LastTransitionTime: metav1.Time{Time: fakeNow().Add(-1 * availableDuration)}, + Message: availableMessage, + }, + { + Type: "Degraded", + Status: configv1.ConditionStatus(degraded), + LastTransitionTime: metav1.Time{Time: fakeNow().Add(-1 * degradedDuration)}, + Message: degradedMessage, + }, + { + Type: "Progressing", + Status: configv1.ConditionStatus(progressing), + LastTransitionTime: metav1.Time{Time: fakeNow().Add(-1 * progressingDuration)}, + Message: progressingMessage, + }, + }, + }, + } +} + +func TestWaitForOperatorsToSettle(t *testing.T) { + nowFn = fakeNow + tests := []struct { + name string + operators []configv1.ClusterOperator + expected []string + }{ + { + name: "all pass", + operators: []configv1.ClusterOperator{ + newOperator("foo", + "True", "as expected", time.Minute, + "False", "as expected", time.Minute, + "False", "as expected", time.Minute, + ), + }, + expected: []string{}, + }, + { + name: "one not available", + operators: []configv1.ClusterOperator{ + newOperator("foo", + "False", "OH NO", time.Minute, + "False", "as expected", time.Minute, + "False", "as expected", time.Minute, + ), + newOperator("bar", + "True", "as expected", time.Minute, + "False", "as expected", time.Minute, + "False", "as expected", time.Minute, + ), + }, + expected: []string{ + `clusteroperator/foo is not Available for 1m0s because "OH NO"`, + }, + }, + { + name: "one degraded, another unavailable", + operators: []configv1.ClusterOperator{ + newOperator("foo", + "False", "OH NO", time.Minute, + "False", "as expected", time.Minute, + "False", "as expected", time.Minute, + ), + newOperator("bar", + "True", "as expected", time.Minute, + "True", "Degraded", 2*time.Minute, + "False", "as expected", time.Minute, + ), + }, + expected: []string{ + `clusteroperator/foo is not Available for 1m0s because "OH NO"`, + `clusteroperator/bar is Degraded for 2m0s because "Degraded"`, + }, + }, + { + name: "one progressing", + operators: []configv1.ClusterOperator{ + newOperator("foo", + "True", "as expected", time.Minute, + "False", "as expected", time.Minute, + "False", "as expected", time.Minute, + ), + newOperator("bar", + "True", "as expected", time.Minute, + "False", "as expected", time.Minute, + "True", "rolling out", time.Minute, + ), + }, + expected: []string{ + `clusteroperator/bar is Progressing for 1m0s because "rolling out"`, + }, + }, + { + name: "one doing both", + operators: []configv1.ClusterOperator{ + newOperator("foo", + "True", "as expected", time.Minute, + "True", "Degraded", 2*time.Minute, + "True", "rolling out", time.Minute, + ), + newOperator("bar", + "True", "as expected", time.Minute, + "False", "as expected", time.Minute, + "False", "as expected", time.Minute, + ), + }, + expected: []string{ + `clusteroperator/foo is Degraded for 2m0s because "Degraded"`, + `clusteroperator/foo is Progressing for 1m0s because "rolling out"`, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual := unsettledOperators(tt.operators) + if !reflect.DeepEqual(actual, tt.expected) { + t.Error(actual) + } + }) + } +} diff --git a/test/extended/util/pods.go b/test/extended/util/pods.go index bd0fa08c8d09..ec5b45bbd20b 100644 --- a/test/extended/util/pods.go +++ b/test/extended/util/pods.go @@ -2,16 +2,28 @@ package util import ( "context" + "fmt" "strings" "time" + corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" kutilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/kubernetes" + clientset "k8s.io/client-go/kubernetes" e2e "k8s.io/kubernetes/test/e2e/framework" "k8s.io/kubernetes/test/e2e/framework/pod" + + "github.com/openshift/origin/test/extended/util/image" +) + +const ( + namespaceMachineConfigOperator = "openshift-machine-config-operator" + containerMachineConfigDaemon = "machine-config-daemon" ) // WaitForNoPodsAvailable waits until there are no pods in the @@ -52,16 +64,53 @@ func RemovePodsWithPrefixes(oc *CLI, prefixes ...string) error { return nil } -// CreateUbiExecPodOrFail creates a ubi8 pause pod used as a vessel for kubectl exec commands. +// CreateExecPodOrFail creates a pod used as a vessel for kubectl exec commands. // Pod name is uniquely generated. -func CreateUbiExecPodOrFail(client kubernetes.Interface, ns, generateName string, tweak func(*v1.Pod)) *v1.Pod { - return pod.CreateExecPodOrFail(client, ns, generateName, func(pod *v1.Pod) { - pod.Spec.Containers[0].Image = "ubi8/ubi" +func CreateExecPodOrFail(client kubernetes.Interface, ns, name string, tweak ...func(*v1.Pod)) *v1.Pod { + return pod.CreateExecPodOrFail(client, ns, name, func(pod *v1.Pod) { + pod.Name = name + pod.GenerateName = "" + pod.Spec.Containers[0].Image = image.ShellImage() pod.Spec.Containers[0].Command = []string{"sh", "-c", "trap exit TERM; while true; do sleep 5; done"} pod.Spec.Containers[0].Args = nil - if tweak != nil { - tweak(pod) + for _, fn := range tweak { + fn(pod) } }) } + +// GetMachineConfigDaemonByNode finds the privileged daemonset from the Machine Config Operator +func GetMachineConfigDaemonByNode(c clientset.Interface, node *corev1.Node) (*corev1.Pod, error) { + listOptions := metav1.ListOptions{ + FieldSelector: fields.SelectorFromSet(fields.Set{"spec.nodeName": node.Name}).String(), + LabelSelector: labels.SelectorFromSet(labels.Set{"k8s-app": "machine-config-daemon"}).String(), + } + + mcds, err := c.CoreV1().Pods(namespaceMachineConfigOperator).List(context.Background(), listOptions) + if err != nil { + return nil, err + } + + if len(mcds.Items) < 1 { + return nil, fmt.Errorf("failed to get machine-config-daemon pod for the node %q", node.Name) + } + return &mcds.Items[0], nil +} + +// ExecCommandOnMachineConfigDaemon returns the output of the command execution on the machine-config-daemon pod that runs on the specified node +func ExecCommandOnMachineConfigDaemon(c clientset.Interface, oc *CLI, node *corev1.Node, command []string) (string, error) { + mcd, err := GetMachineConfigDaemonByNode(c, node) + if err != nil { + return "", err + } + + initialArgs := []string{ + "-n", namespaceMachineConfigOperator, + "-c", containerMachineConfigDaemon, + "--request-timeout", "30", + mcd.Name, + } + args := append(initialArgs, command...) + return oc.AsAdmin().Run("rsh").Args(args...).Output() +} diff --git a/test/extended/util/prometheus/helpers.go b/test/extended/util/prometheus/helpers.go index 223aa94d738f..f47ed59aa8db 100644 --- a/test/extended/util/prometheus/helpers.go +++ b/test/extended/util/prometheus/helpers.go @@ -5,13 +5,13 @@ import ( "encoding/json" "fmt" "net/url" - "os" "strconv" "strings" "time" g "github.com/onsi/ginkgo" o "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/util/errors" exutil "github.com/openshift/origin/test/extended/util" "github.com/prometheus/common/model" @@ -41,14 +41,6 @@ type prometheusResponseData struct { Result model.Vector `json:"result"` } -// TestUnsupportedAllowVersionSkew returns whether TEST_UNSUPPORTED_ALLOW_VERSION_SKEW is set -func TestUnsupportedAllowVersionSkew() bool { - if len(os.Getenv("TEST_UNSUPPORTED_ALLOW_VERSION_SKEW")) > 0 { - return true - } - return false -} - // GetBearerTokenURLViaPod makes http request through given pod func GetBearerTokenURLViaPod(ns, execPodName, url, bearer string) (string, error) { cmd := fmt.Sprintf("curl --retry 15 --max-time 2 --retry-delay 1 -s -k -H 'Authorization: Bearer %s' %q", bearer, url) @@ -114,7 +106,7 @@ func ExpectPrometheus(f *framework.Framework) (url, bearerToken string, oc *exut } // RunQueries executes Prometheus queries and checks provided expected result. -func RunQueries(promQueries map[string]bool, oc *exutil.CLI, ns, execPodName, baseURL, bearerToken string) { +func RunQueries(promQueries map[string]bool, oc *exutil.CLI, ns, execPodName, baseURL, bearerToken string) error { // expect all correct metrics within a reasonable time period queryErrors := make(map[string]error) passed := make(map[string]struct{}) @@ -129,7 +121,9 @@ func RunQueries(promQueries map[string]bool, oc *exutil.CLI, ns, execPodName, ba g.By("perform prometheus metric query " + query) url := fmt.Sprintf("%s/api/v1/query?%s", baseURL, (url.Values{"query": []string{query}}).Encode()) contents, err := GetBearerTokenURLViaPod(ns, execPodName, url, bearerToken) - o.Expect(err).NotTo(o.HaveOccurred()) + if err != nil { + return err + } // check query result, if this is a new error log it, otherwise remain silent var result PrometheusResponse @@ -171,7 +165,11 @@ func RunQueries(promQueries map[string]bool, oc *exutil.CLI, ns, execPodName, ba if len(queryErrors) != 0 { exutil.DumpPodLogsStartingWith("prometheus-0", oc) } - o.Expect(queryErrors).To(o.BeEmpty()) + var errs []error + for query, err := range queryErrors { + errs = append(errs, fmt.Errorf("query failed: %s: %s", query, err)) + } + return errors.NewAggregate(errs) } // ExpectURLStatusCodeExec attempts connection to url returning an error diff --git a/test/extended/util/proxy.go b/test/extended/util/proxy.go new file mode 100644 index 000000000000..03771d3c6daa --- /dev/null +++ b/test/extended/util/proxy.go @@ -0,0 +1,20 @@ +package util + +import ( + "context" + + kerrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// IsClusterProxyEnabled returns true if the cluster has a global proxy enabled +func IsClusterProxyEnabled(oc *CLI) (bool, error) { + proxy, err := oc.AdminConfigClient().ConfigV1().Proxies().Get(context.Background(), "cluster", metav1.GetOptions{}) + if kerrors.IsNotFound(err) { + return false, nil + } + if err != nil { + return false, err + } + return len(proxy.Status.HTTPProxy) > 0 || len(proxy.Status.HTTPSProxy) > 0, nil +} diff --git a/test/extended/util/test.go b/test/extended/util/test.go index 69d23e711fdf..fe5369da6479 100644 --- a/test/extended/util/test.go +++ b/test/extended/util/test.go @@ -14,7 +14,7 @@ import ( "github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/reporters" "github.com/onsi/gomega" - "k8s.io/klog" + "k8s.io/klog/v2" kapiv1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" diff --git a/test/extended/util/url/url.go b/test/extended/util/url/url.go index 4e96700af0cb..5315ee4b70f8 100644 --- a/test/extended/util/url/url.go +++ b/test/extended/util/url/url.go @@ -15,13 +15,15 @@ import ( o "github.com/onsi/gomega" - exutil "github.com/openshift/origin/test/extended/util" v1 "k8s.io/api/core/v1" apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" kclientset "k8s.io/client-go/kubernetes" e2e "k8s.io/kubernetes/test/e2e/framework" + + exutil "github.com/openshift/origin/test/extended/util" + "github.com/openshift/origin/test/extended/util/image" ) type Tester struct { @@ -135,7 +137,7 @@ func (ut *Tester) Within(t time.Duration, tests ...*Test) { o.Expect(err).ToNot(o.HaveOccurred()) } -// createExecPod creates a simple pod in a sleep loop used as a +// createExecPod creates a simple bash pod in a sleep loop used as a // vessel for kubectl exec commands. // Returns the name of the created pod. func createExecPod(clientset kclientset.Interface, ns, name string) (string, error) { @@ -151,7 +153,7 @@ func createExecPod(clientset kclientset.Interface, ns, name string) (string, err { Command: []string{"/bin/bash", "-c", "exec sleep 10000"}, Name: "hostexec", - Image: "registry.redhat.io/rhel7:latest", + Image: image.ShellImage(), ImagePullPolicy: v1.PullIfNotPresent, }, }, @@ -181,7 +183,7 @@ func testsToScript(tests []*Test) string { testScripts := []string{ "set -euo pipefail", `function json_escape() {`, - ` python -c 'import json,sys; print json.dumps(sys.stdin.read())'`, + ` python -c 'import json,sys; print(json.dumps(sys.stdin.read()))'`, `}`, } for i, test := range tests { diff --git a/test/extended/util/wait.go b/test/extended/util/wait.go new file mode 100644 index 000000000000..17ced2e103be --- /dev/null +++ b/test/extended/util/wait.go @@ -0,0 +1,41 @@ +package util + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + "k8s.io/client-go/tools/cache" + watchtools "k8s.io/client-go/tools/watch" +) + +func WaitForCMState(ctx context.Context, client corev1client.CoreV1Interface, namespace string, name string, condition func(cm *corev1.ConfigMap) (bool, error)) (*corev1.ConfigMap, error) { + fieldSelector := fields.OneTermEqualSelector("metadata.name", name).String() + lw := &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + options.FieldSelector = fieldSelector + return client.ConfigMaps(namespace).List(ctx, options) + }, + WatchFunc: func(options metav1.ListOptions) (i watch.Interface, e error) { + options.FieldSelector = fieldSelector + return client.ConfigMaps(namespace).Watch(ctx, options) + }, + } + event, err := watchtools.UntilWithSync(ctx, lw, &corev1.ConfigMap{}, nil, func(event watch.Event) (bool, error) { + switch event.Type { + case watch.Added, watch.Modified: + return condition(event.Object.(*corev1.ConfigMap)) + default: + return true, fmt.Errorf("unexpected event: %#v", event) + } + }) + if err != nil { + return nil, err + } + return event.Object.(*corev1.ConfigMap), nil +} diff --git a/test/integration/testdata/project-request-template-with-quota.yaml b/test/integration/testdata/project-request-template-with-quota.yaml deleted file mode 100644 index f7cb62b7398b..000000000000 --- a/test/integration/testdata/project-request-template-with-quota.yaml +++ /dev/null @@ -1,115 +0,0 @@ -apiVersion: template.openshift.io/v1 -kind: Template -metadata: - creationTimestamp: 2015-10-24T18:25:22Z - name: default-project-request - namespace: default -objects: -- apiVersion: v1 - kind: Project - metadata: - annotations: - openshift.io/description: ${PROJECT_DESCRIPTION} - openshift.io/display-name: ${PROJECT_DISPLAYNAME} - extra: here - creationTimestamp: null - name: ${PROJECT_NAME} - spec: {} - status: {} -- apiVersion: v1 - kind: ResourceQuota - metadata: - name: ${PROJECT_NAME}-quota - spec: - hard: - cpu: 200m - memory: 512Mi - pods: 3 - replicationcontrollers: 3 - resourcequotas: 1 - services: 3 -- apiVersion: v1 - kind: LimitRange - metadata: - creationTimestamp: null - name: ${PROJECT_NAME}-limits - spec: - limits: - - max: - cpu: 500m - memory: 750Mi - min: - cpu: 10m - memory: 5Mi - type: Pod - - default: - cpu: 100m - memory: 100Mi - max: - cpu: 500m - memory: 750Mi - min: - cpu: 10m - memory: 5Mi - type: Container -- apiVersion: v1 - groupNames: [] - kind: RoleBinding - metadata: - creationTimestamp: null - name: admins - namespace: ${PROJECT_NAME} - roleRef: - name: admin - subjects: - - kind: User - name: ${PROJECT_ADMIN_USER} - userNames: - - ${PROJECT_ADMIN_USER} -- apiVersion: v1 - groupNames: - - system:serviceaccounts:${PROJECT_NAME} - kind: RoleBinding - metadata: - creationTimestamp: null - name: system:image-pullers - namespace: ${PROJECT_NAME} - roleRef: - name: system:image-puller - subjects: - - kind: SystemGroup - name: system:serviceaccounts:${PROJECT_NAME} - userNames: [] -- apiVersion: v1 - groupNames: [] - kind: RoleBinding - metadata: - creationTimestamp: null - name: system:image-builders - namespace: ${PROJECT_NAME} - roleRef: - name: system:image-builder - subjects: - - kind: ServiceAccount - name: builder - userNames: - - system:serviceaccount:${PROJECT_NAME}:builder -- apiVersion: v1 - groupNames: [] - kind: RoleBinding - metadata: - creationTimestamp: null - name: system:deployers - namespace: ${PROJECT_NAME} - roleRef: - name: system:deployer - subjects: - - kind: ServiceAccount - name: deployer - userNames: - - system:serviceaccount:${PROJECT_NAME}:deployer -parameters: -- name: PROJECT_NAME -- name: PROJECT_DISPLAYNAME -- name: PROJECT_DESCRIPTION -- name: PROJECT_ADMIN_USER diff --git a/test/integration/testdata/test-buildcli-beta2.json b/test/integration/testdata/test-buildcli-beta2.json deleted file mode 100644 index 2333a0939c3d..000000000000 --- a/test/integration/testdata/test-buildcli-beta2.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "kind": "List", - "apiVersion": "v1", - "metadata": {}, - "items": [ - { - "kind": "ImageStream", - "apiVersion": "v1", - "metadata": { - "name": "ruby-22-centos-buildcli", - "creationTimestamp": null - }, - "spec": { - "dockerImageRepository": "centos/ruby-22-centos", - "tags": [ - { - "name": "valid" - } - ] - }, - "status": { - "dockerImageRepository": "" - } - }, - { - "kind": "BuildConfig", - "apiVersion": "v1", - "metadata": { - "name": "ruby-sample-build-validtag", - "creationTimestamp": null - }, - "spec": { - "triggers": [ - { - "type": "imageChange", - "imageChange": {} - } - ], - "source": { - "type": "Git", - "git": { - "uri": "git://github.com/openshift/ruby-hello-world.git" - } - }, - "strategy": { - "type": "Source", - "sourceStrategy": { - "from": { - "kind": "ImageStreamTag", - "name": "ruby-22-centos-buildcli:valid" - }, - "incremental": true - } - }, - "output": { - "to": { - "kind": "ImageStreamTag", - "name": "origin-ruby-sample:latest" - } - }, - "resources": {} - }, - "status": { - "lastVersion": 0 - } - }, - { - "kind": "BuildConfig", - "apiVersion": "v1", - "metadata": { - "name": "ruby-sample-build-invalidtag", - "creationTimestamp": null - }, - "spec": { - "triggers": [ - { - "type": "imageChange", - "imageChange": {} - } - ], - "source": { - "type": "Git", - "git": { - "uri": "git://github.com/openshift/ruby-hello-world.git" - } - }, - "strategy": { - "type": "Source", - "sourceStrategy": { - "from": { - "kind": "ImageStreamTag", - "name": "ruby-22-centos-buildcli:invalid" - }, - "incremental": true - } - }, - "output": { - "to": { - "kind": "ImageStreamTag", - "name": "origin-ruby-sample:latest" - } - }, - "resources": {} - }, - "status": { - "lastVersion": 0 - } - } - ] -} diff --git a/test/integration/testdata/test-buildcli.json b/test/integration/testdata/test-buildcli.json index 5dfcbc09a395..34b77ed693c6 100644 --- a/test/integration/testdata/test-buildcli.json +++ b/test/integration/testdata/test-buildcli.json @@ -11,7 +11,7 @@ "creationTimestamp": null }, "spec": { - "dockerImageRepository": "centos/ruby-25-centos7", + "dockerImageRepository": "centos/ruby-27-centos7", "tags": [ { "name": "valid" @@ -47,7 +47,7 @@ "sourceStrategy": { "from": { "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/ruby-25-rhel7:latest" + "name": "registry.redhat.io/rhscl/ruby-27-rhel7:latest" }, "incremental": true } @@ -89,7 +89,7 @@ "sourceStrategy": { "from": { "kind": "DockerImage", - "name": "registry.redhat.io/rhscl/ruby-25-rhel7:latest" + "name": "registry.redhat.io/rhscl/ruby-27-rhel7:latest" }, "incremental": true } diff --git a/test/integration/testdata/test-image-stream-mapping.json b/test/integration/testdata/test-image-stream-mapping.json deleted file mode 100644 index 65c49688d576..000000000000 --- a/test/integration/testdata/test-image-stream-mapping.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "kind": "ImageStreamMapping", - "apiVersion": "v1", - "metadata": { - "name": "test", - "creationTimestamp": null - }, - "image": { - "metadata": { - "name": "sha256:4986bf8c15363d1c5d15512d5266f8777bfba4974ac56e3270e7760f6f0a8125", - "creationTimestamp": null - }, - "dockerImageReference": "openshift/ruby-19-centos:latest", - "dockerImageMetadata": { - "kind": "DockerImage", - "apiVersion": "1.0", - "Id": "", - "Created": null, - "ContainerConfig": {}, - "Config": {} - }, - "dockerImageMetadataVersion": "1.0", - "dockerImageManifest": "{\n \"name\": \"library/busybox\",\n \"tag\": \"latest\",\n \"architecture\": \"amd64\",\n \"fsLayers\": [\n {\n \"blobSum\": \"tarsum.dev+sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\"\n },\n {\n \"blobSum\": \"tarsum.dev+sha256:d43a7079c4dd020e9c65419c2eb6751ea49d6f7f9337edd895596cd5f7aa6369\"\n },\n {\n \"blobSum\": \"tarsum.dev+sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\"\n },\n {\n \"blobSum\": \"tarsum.dev+sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\"\n }\n ],\n \"history\": [\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"4986bf8c15363d1c5d15512d5266f8777bfba4974ac56e3270e7760f6f0a8125\\\",\\\"parent\\\":\\\"ea13149945cb6b1e746bf28032f02e9b5a793523481a0a18645fc77ad53c4ea2\\\",\\\"created\\\":\\\"2014-12-31T22:23:56.943403668Z\\\",\\\"container\\\":\\\"83dcf36ad1042b90f4ea8b2ebb60e61b2f1a451a883e04b388be299ad382b259\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"7f674915980d\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"Memory\\\":0,\\\"MemorySwap\\\":0,\\\"CpuShares\\\":0,\\\"Cpuset\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"PortSpecs\\\":null,\\\"ExposedPorts\\\":null,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) CMD [/bin/sh]\\\"],\\\"Image\\\":\\\"ea13149945cb6b1e746bf28032f02e9b5a793523481a0a18645fc77ad53c4ea2\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"NetworkDisabled\\\":false,\\\"MacAddress\\\":\\\"\\\",\\\"OnBuild\\\":[]},\\\"docker_version\\\":\\\"1.4.1\\\",\\\"author\\\":\\\"Jerome Petazzoni \\\\u003cjerome@docker.com\\\\u003e\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"7f674915980d\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"Memory\\\":0,\\\"MemorySwap\\\":0,\\\"CpuShares\\\":0,\\\"Cpuset\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"PortSpecs\\\":null,\\\"ExposedPorts\\\":null,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\"],\\\"Image\\\":\\\"ea13149945cb6b1e746bf28032f02e9b5a793523481a0a18645fc77ad53c4ea2\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"NetworkDisabled\\\":false,\\\"MacAddress\\\":\\\"\\\",\\\"OnBuild\\\":[]},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\",\\\"checksum\\\":\\\"tarsum.dev+sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\\\",\\\"Size\\\":0}\\n\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"ea13149945cb6b1e746bf28032f02e9b5a793523481a0a18645fc77ad53c4ea2\\\",\\\"parent\\\":\\\"df7546f9f060a2268024c8a230d8639878585defcc1bc6f79d2728a13957871b\\\",\\\"created\\\":\\\"2014-12-31T22:23:56.190797792Z\\\",\\\"container\\\":\\\"7f674915980dbcafb3096fa82369c2943194486dcb4e585e3490a2e66c530e44\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"7f674915980d\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"Memory\\\":0,\\\"MemorySwap\\\":0,\\\"CpuShares\\\":0,\\\"Cpuset\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"PortSpecs\\\":null,\\\"ExposedPorts\\\":null,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) ADD file:8cf517d90fe79547c474641cc1e6425850e04abbd8856718f7e4a184ea878538 in /\\\"],\\\"Image\\\":\\\"df7546f9f060a2268024c8a230d8639878585defcc1bc6f79d2728a13957871b\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"NetworkDisabled\\\":false,\\\"MacAddress\\\":\\\"\\\",\\\"OnBuild\\\":[]},\\\"docker_version\\\":\\\"1.4.1\\\",\\\"author\\\":\\\"Jerome Petazzoni \\\\u003cjerome@docker.com\\\\u003e\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"7f674915980d\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"Memory\\\":0,\\\"MemorySwap\\\":0,\\\"CpuShares\\\":0,\\\"Cpuset\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"PortSpecs\\\":null,\\\"ExposedPorts\\\":null,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":null,\\\"Image\\\":\\\"df7546f9f060a2268024c8a230d8639878585defcc1bc6f79d2728a13957871b\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"NetworkDisabled\\\":false,\\\"MacAddress\\\":\\\"\\\",\\\"OnBuild\\\":[]},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\",\\\"checksum\\\":\\\"tarsum.dev+sha256:d43a7079c4dd020e9c65419c2eb6751ea49d6f7f9337edd895596cd5f7aa6369\\\",\\\"Size\\\":2433303}\\n\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"df7546f9f060a2268024c8a230d8639878585defcc1bc6f79d2728a13957871b\\\",\\\"parent\\\":\\\"511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158\\\",\\\"created\\\":\\\"2014-10-01T20:46:07.263351912Z\\\",\\\"container\\\":\\\"2147a17cb1b2d6626ed78e5ef8ba4c71ce82c884bc3b57ab01e6114ff357cea4\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"2147a17cb1b2\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"Memory\\\":0,\\\"MemorySwap\\\":0,\\\"CpuShares\\\":0,\\\"Cpuset\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"PortSpecs\\\":null,\\\"ExposedPorts\\\":null,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) MAINTAINER Jerome Petazzoni \\\\u003cjerome@docker.com\\\\u003e\\\"],\\\"Image\\\":\\\"511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"NetworkDisabled\\\":false,\\\"MacAddress\\\":\\\"\\\",\\\"OnBuild\\\":[]},\\\"docker_version\\\":\\\"1.2.0\\\",\\\"author\\\":\\\"Jerome Petazzoni \\\\u003cjerome@docker.com\\\\u003e\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"2147a17cb1b2\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"Memory\\\":0,\\\"MemorySwap\\\":0,\\\"CpuShares\\\":0,\\\"Cpuset\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"PortSpecs\\\":null,\\\"ExposedPorts\\\":null,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":null,\\\"Image\\\":\\\"511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"NetworkDisabled\\\":false,\\\"MacAddress\\\":\\\"\\\",\\\"OnBuild\\\":[]},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\",\\\"checksum\\\":\\\"tarsum.dev+sha256:1b755912c77197c6a43539f2a708ef89d5849b8ce02642cb702e47afaa8195c3\\\",\\\"Size\\\":0}\\n\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158\\\",\\\"comment\\\":\\\"Imported from -\\\",\\\"created\\\":\\\"2013-06-13T14:03:50.821769-07:00\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"Memory\\\":0,\\\"MemorySwap\\\":0,\\\"CpuShares\\\":0,\\\"Cpuset\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"PortSpecs\\\":null,\\\"ExposedPorts\\\":null,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":null,\\\"Cmd\\\":null,\\\"Image\\\":\\\"\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"NetworkDisabled\\\":false,\\\"MacAddress\\\":\\\"\\\",\\\"OnBuild\\\":null},\\\"docker_version\\\":\\\"0.4.0\\\",\\\"architecture\\\":\\\"x86_64\\\",\\\"checksum\\\":\\\"tarsum.dev+sha256:324d4cf44ee7daa46266c1df830c61a7df615c0632176a339e7310e34723d67a\\\",\\\"Size\\\":0}\\n\"\n }\n ],\n \"schemaVersion\": 1,\n \"signatures\": [\n {\n \"header\": {\n \"jwk\": {\n \"crv\": \"P-256\",\n \"kid\": \"OIH7:HQFS:44FK:45VB:3B53:OIAG:TPL4:ATF5:6PNE:MGHN:NHQX:2GE4\",\n \"kty\": \"EC\",\n \"x\": \"Cu_UyxwLgHzE9rvlYSmvVdqYCXY42E9eNhBb0xNv0SQ\",\n \"y\": \"zUsjWJkeKQ5tv7S-hl1Tg71cd-CqnrtiiLxSi6N_yc8\"\n },\n \"alg\": \"ES256\"\n },\n \"signature\": \"bWiisabH8LgSXezUhjN8X3I7ESBo_fCXvFtqAwRmzozTfPHTr8edd13SU0KUJMq4X7_agEuLpSh1V8YGcBVpYg\",\n \"protected\": \"eyJmb3JtYXRMZW5ndGgiOjcwNjMsImZvcm1hdFRhaWwiOiJDbjAiLCJ0aW1lIjoiMjAxNS0wMy0zMVQxNjozMjoyOVoifQ\"\n }\n ]\n}" - }, - "tag": "sometag" -} \ No newline at end of file diff --git a/test/integration/testdata/test-image.json b/test/integration/testdata/test-image.json deleted file mode 100644 index e70d6e20d733..000000000000 --- a/test/integration/testdata/test-image.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "kind": "Image", - "apiVersion": "image.openshift.io/v1", - "metadata": { - "name": "test", - "creationTimestamp": null - }, - "dockerImageReference": "openshift/ruby-19-centos:latest", - "dockerImageMetadata": { - "kind": "DockerImage", - "apiVersion": "1.0", - "Id": "", - "ContainerConfig": {}, - "Config": {} - }, - "dockerImageMetadataVersion": "1.0" -} diff --git a/test/integration/testdata/test-route.json b/test/integration/testdata/test-route.json deleted file mode 100644 index 2c29049df9ca..000000000000 --- a/test/integration/testdata/test-route.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "kind": "Route", - "apiVersion": "v1", - "metadata": { - "name": "testroute", - "creationTimestamp": null, - "labels": { - "rtlabel1": "greatroute" - } - }, - "spec": { - "host": "test.example.com", - "to": { - "kind": "Service", - "name": "testservice" - } - }, - "status": {} -} diff --git a/test/integration/testdata/test-service-with-finalizer.json b/test/integration/testdata/test-service-with-finalizer.json deleted file mode 100644 index e055b7ca2ae3..000000000000 --- a/test/integration/testdata/test-service-with-finalizer.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "frontend", - "creationTimestamp": null, - "labels": { - "name": "frontend" - }, - "finalizers": ["fake/one"] - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 9998, - "targetPort": 9998, - "nodePort": 0 - } - ], - "selector": { - "name": "frontend" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } -} \ No newline at end of file diff --git a/test/integration/testdata/test-service.json b/test/integration/testdata/test-service.json deleted file mode 100644 index b2e6e8bfff62..000000000000 --- a/test/integration/testdata/test-service.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "kind": "Service", - "apiVersion": "v1", - "metadata": { - "name": "frontend", - "creationTimestamp": null, - "labels": { - "name": "frontend" - } - }, - "spec": { - "ports": [ - { - "protocol": "TCP", - "port": 9998, - "targetPort": 9998, - "nodePort": 0 - } - ], - "selector": { - "name": "frontend" - }, - "type": "ClusterIP", - "sessionAffinity": "None" - }, - "status": { - "loadBalancer": {} - } -} \ No newline at end of file diff --git a/vendor/github.com/openshift/library-go/pkg/config/client/client_config.go b/vendor/github.com/openshift/library-go/pkg/config/client/client_config.go index a247311057b9..e2b90ca53147 100644 --- a/vendor/github.com/openshift/library-go/pkg/config/client/client_config.go +++ b/vendor/github.com/openshift/library-go/pkg/config/client/client_config.go @@ -2,14 +2,12 @@ package client import ( "io/ioutil" - "net" - "net/http" - "time" - "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + "net/http" configv1 "github.com/openshift/api/config/v1" + "github.com/openshift/library-go/pkg/network" ) // GetKubeConfigOrInClusterConfig loads in-cluster config if kubeConfigFile is empty or the file if not, @@ -101,10 +99,7 @@ func (c ClientTransportOverrides) DefaultClientTransport(rt http.RoundTripper) h return rt } - transport.DialContext = (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - }).DialContext + transport.DialContext = network.DefaultClientDialContext() // Hold open more internal idle connections transport.MaxIdleConnsPerHost = 100 diff --git a/vendor/github.com/openshift/library-go/pkg/controller/factory/base_controller.go b/vendor/github.com/openshift/library-go/pkg/controller/factory/base_controller.go index 5a1b1177f917..70e6eda8bbcf 100644 --- a/vendor/github.com/openshift/library-go/pkg/controller/factory/base_controller.go +++ b/vendor/github.com/openshift/library-go/pkg/controller/factory/base_controller.go @@ -62,6 +62,18 @@ func (s *scheduledJob) Run() { s.queue.Add(DefaultQueueKey) } +func waitForNamedCacheSync(controllerName string, stopCh <-chan struct{}, cacheSyncs ...cache.InformerSynced) error { + klog.Infof("Waiting for caches to sync for %s", controllerName) + + if !cache.WaitForCacheSync(stopCh, cacheSyncs...) { + return fmt.Errorf("unable to sync caches for %s", controllerName) + } + + klog.Infof("Caches are synced for %s ", controllerName) + + return nil +} + func (c *baseController) Run(ctx context.Context, workers int) { // HandleCrash recovers panics defer utilruntime.HandleCrash() @@ -69,12 +81,19 @@ func (c *baseController) Run(ctx context.Context, workers int) { // give caches 10 minutes to sync cacheSyncCtx, cacheSyncCancel := context.WithTimeout(ctx, c.cacheSyncTimeout) defer cacheSyncCancel() - if !cache.WaitForNamedCacheSync(c.name, cacheSyncCtx.Done(), c.cachesToSync...) { - // the parent context is closed, it means we are shutting down, do not call panic() - if ctx.Err() != nil { + err := waitForNamedCacheSync(c.name, cacheSyncCtx.Done(), c.cachesToSync...) + if err != nil { + select { + case <-ctx.Done(): + // Exit gracefully because the controller was requested to stop. return + default: + // If caches did not sync after 10 minutes, it has taken oddly long and + // we should provide feedback. Since the control loops will never start, + // it is safer to exit with a good message than to continue with a dead loop. + // TODO: Consider making this behavior configurable. + klog.Exit(err) } - panic("failed to wait for cache to sync") } var workerWg sync.WaitGroup diff --git a/vendor/github.com/openshift/library-go/pkg/controller/factory/controller_context.go b/vendor/github.com/openshift/library-go/pkg/controller/factory/controller_context.go index 67a105184463..901fda133eb3 100644 --- a/vendor/github.com/openshift/library-go/pkg/controller/factory/controller_context.go +++ b/vendor/github.com/openshift/library-go/pkg/controller/factory/controller_context.go @@ -44,62 +44,66 @@ func (c syncContext) Recorder() events.Recorder { return c.eventRecorder } -func (c syncContext) isInterestingNamespace(obj interface{}, interestingNamespaces sets.String) (bool, bool) { - ns, ok := obj.(*corev1.Namespace) - if !ok { - tombstone, ok := obj.(cache.DeletedFinalStateUnknown) - if ok { - if ns, ok := tombstone.Obj.(*corev1.Namespace); ok { - return true, interestingNamespaces.Has(ns.Name) - } - } - return false, false - } - return true, interestingNamespaces.Has(ns.Name) -} - // eventHandler provides default event handler that is added to an informers passed to controller factory. -func (c syncContext) eventHandler(queueKeyFunc ObjectQueueKeyFunc, interestingNamespaces sets.String) cache.ResourceEventHandler { - return cache.ResourceEventHandlerFuncs{ +func (c syncContext) eventHandler(queueKeyFunc ObjectQueueKeyFunc, filter EventFilterFunc) cache.ResourceEventHandler { + resourceEventHandler := cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { - isNamespace, isInteresting := c.isInterestingNamespace(obj, interestingNamespaces) runtimeObj, ok := obj.(runtime.Object) if !ok { utilruntime.HandleError(fmt.Errorf("added object %+v is not runtime Object", obj)) return } - if !isNamespace || (isNamespace && isInteresting) { - c.Queue().Add(queueKeyFunc(runtimeObj)) - } + c.Queue().Add(queueKeyFunc(runtimeObj)) }, UpdateFunc: func(old, new interface{}) { - isNamespace, isInteresting := c.isInterestingNamespace(new, interestingNamespaces) runtimeObj, ok := new.(runtime.Object) if !ok { utilruntime.HandleError(fmt.Errorf("updated object %+v is not runtime Object", runtimeObj)) return } - if !isNamespace || (isNamespace && isInteresting) { - c.Queue().Add(queueKeyFunc(runtimeObj)) - } + c.Queue().Add(queueKeyFunc(runtimeObj)) }, DeleteFunc: func(obj interface{}) { - isNamespace, isInteresting := c.isInterestingNamespace(obj, interestingNamespaces) runtimeObj, ok := obj.(runtime.Object) if !ok { - tombstone, ok := obj.(cache.DeletedFinalStateUnknown) - if ok { - if !isNamespace || (isNamespace && isInteresting) { - c.Queue().Add(queueKeyFunc(tombstone.Obj.(runtime.Object))) - } + if tombstone, ok := obj.(cache.DeletedFinalStateUnknown); ok { + c.Queue().Add(queueKeyFunc(tombstone.Obj.(runtime.Object))) return } utilruntime.HandleError(fmt.Errorf("updated object %+v is not runtime Object", runtimeObj)) return } - if !isNamespace || (isNamespace && isInteresting) { - c.Queue().Add(queueKeyFunc(runtimeObj)) - } + c.Queue().Add(queueKeyFunc(runtimeObj)) }, } + if filter == nil { + return resourceEventHandler + } + return cache.FilteringResourceEventHandler{ + FilterFunc: filter, + Handler: resourceEventHandler, + } +} + +// namespaceChecker returns a function which returns true if an inpuut obj +// (or its tombstone) is a namespace and it matches a name of any namespaces +// that we are interested in +func namespaceChecker(interestingNamespaces []string) func(obj interface{}) bool { + interestingNamespacesSet := sets.NewString(interestingNamespaces...) + + return func(obj interface{}) bool { + ns, ok := obj.(*corev1.Namespace) + if ok { + return interestingNamespacesSet.Has(ns.Name) + } + + // the object might be getting deleted + tombstone, ok := obj.(cache.DeletedFinalStateUnknown) + if ok { + if ns, ok := tombstone.Obj.(*corev1.Namespace); ok { + return interestingNamespacesSet.Has(ns.Name) + } + } + return false + } } diff --git a/vendor/github.com/openshift/library-go/pkg/controller/factory/factory.go b/vendor/github.com/openshift/library-go/pkg/controller/factory/factory.go index 61c96b8a58a7..975687d5422a 100644 --- a/vendor/github.com/openshift/library-go/pkg/controller/factory/factory.go +++ b/vendor/github.com/openshift/library-go/pkg/controller/factory/factory.go @@ -26,7 +26,7 @@ type Factory struct { syncDegradedClient operatorv1helpers.OperatorClient resyncInterval time.Duration resyncSchedules []string - informers []Informer + informers []filteredInformers informerQueueKeys []informersWithQueueKey bareInformers []Informer postStartHooks []PostStartHook @@ -43,15 +43,21 @@ type Informer interface { } type namespaceInformer struct { - informer Informer - namespaces sets.String + informer Informer + nsFilter EventFilterFunc } type informersWithQueueKey struct { informers []Informer + filter EventFilterFunc queueKeyFn ObjectQueueKeyFunc } +type filteredInformers struct { + informers []Informer + filter EventFilterFunc +} + // PostStartHook specify a function that will run after controller is started. // The context is cancelled when the controller is asked to shutdown and the post start hook should terminate as well. // The syncContext allow access to controller queue and event recorder. @@ -62,6 +68,9 @@ type PostStartHook func(ctx context.Context, syncContext SyncContext) error // triggers. type ObjectQueueKeyFunc func(runtime.Object) string +// EventFilterFunc is used to filter informer events to prevent Sync() from being called +type EventFilterFunc func(obj interface{}) bool + // New return new factory instance. func New() *Factory { return &Factory{} @@ -78,7 +87,19 @@ func (f *Factory) WithSync(syncFn SyncFunc) *Factory { // Pass informers you want to use to react to changes on resources. If informer event is observed, then the Sync() function // is called. func (f *Factory) WithInformers(informers ...Informer) *Factory { - f.informers = append(f.informers, informers...) + f.WithFilteredEventsInformers(nil, informers...) + return f +} + +// WithFilteredEventsInformers is used to register event handlers and get the caches synchronized functions. +// Pass the informers you want to use to react to changes on resources. If informer event is observed, then the Sync() function +// is called. +// Pass filter to filter out events that should not trigger Sync() call. +func (f *Factory) WithFilteredEventsInformers(filter EventFilterFunc, informers ...Informer) *Factory { + f.informers = append(f.informers, filteredInformers{ + informers: informers, + filter: filter, + }) return f } @@ -104,6 +125,20 @@ func (f *Factory) WithInformersQueueKeyFunc(queueKeyFn ObjectQueueKeyFunc, infor return f } +// WithFilteredEventsInformersQueueKeyFunc is used to register event handlers and get the caches synchronized functions. +// Pass informers you want to use to react to changes on resources. If informer event is observed, then the Sync() function +// is called. +// Pass the queueKeyFn you want to use to transform the informer runtime.Object into string key used by work queue. +// Pass filter to filter out events that should not trigger Sync() call. +func (f *Factory) WithFilteredEventsInformersQueueKeyFunc(queueKeyFn ObjectQueueKeyFunc, filter EventFilterFunc, informers ...Informer) *Factory { + f.informerQueueKeys = append(f.informerQueueKeys, informersWithQueueKey{ + informers: informers, + filter: filter, + queueKeyFn: queueKeyFn, + }) + return f +} + // WithPostStartHooks allows to register functions that will run asynchronously after the controller is started via Run command. func (f *Factory) WithPostStartHooks(hooks ...PostStartHook) *Factory { f.postStartHooks = append(f.postStartHooks, hooks...) @@ -115,8 +150,8 @@ func (f *Factory) WithPostStartHooks(hooks ...PostStartHook) *Factory { // Do not use this to register non-namespace informers. func (f *Factory) WithNamespaceInformer(informer Informer, interestingNamespaces ...string) *Factory { f.namespaceInformers = append(f.namespaceInformers, &namespaceInformer{ - informer: informer, - namespaces: sets.NewString(interestingNamespaces...), + informer: informer, + nsFilter: namespaceChecker(interestingNamespaces), }) return f } @@ -205,16 +240,19 @@ func (f *Factory) ToController(name string, eventRecorder events.Recorder) Contr for d := range f.informerQueueKeys[i].informers { informer := f.informerQueueKeys[i].informers[d] queueKeyFn := f.informerQueueKeys[i].queueKeyFn - informer.AddEventHandler(c.syncContext.(syncContext).eventHandler(queueKeyFn, sets.NewString())) + informer.AddEventHandler(c.syncContext.(syncContext).eventHandler(queueKeyFn, f.informerQueueKeys[i].filter)) c.cachesToSync = append(c.cachesToSync, informer.HasSynced) } } for i := range f.informers { - f.informers[i].AddEventHandler(c.syncContext.(syncContext).eventHandler(func(runtime.Object) string { - return DefaultQueueKey - }, sets.NewString())) - c.cachesToSync = append(c.cachesToSync, f.informers[i].HasSynced) + for d := range f.informers[i].informers { + informer := f.informers[i].informers[d] + informer.AddEventHandler(c.syncContext.(syncContext).eventHandler(func(runtime.Object) string { + return DefaultQueueKey + }, f.informers[i].filter)) + c.cachesToSync = append(c.cachesToSync, informer.HasSynced) + } } for i := range f.bareInformers { @@ -224,7 +262,7 @@ func (f *Factory) ToController(name string, eventRecorder events.Recorder) Contr for i := range f.namespaceInformers { f.namespaceInformers[i].informer.AddEventHandler(c.syncContext.(syncContext).eventHandler(func(runtime.Object) string { return DefaultQueueKey - }, f.namespaceInformers[i].namespaces)) + }, f.namespaceInformers[i].nsFilter)) c.cachesToSync = append(c.cachesToSync, f.namespaceInformers[i].informer.HasSynced) } diff --git a/vendor/github.com/openshift/library-go/pkg/git/repository.go b/vendor/github.com/openshift/library-go/pkg/git/repository.go index e596ba3112db..6789fa3f1435 100644 --- a/vendor/github.com/openshift/library-go/pkg/git/repository.go +++ b/vendor/github.com/openshift/library-go/pkg/git/repository.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "net/url" "os" "os/exec" "path/filepath" @@ -37,6 +38,7 @@ type Repository interface { Commit(dir string, message string) error AddRemote(dir string, name, url string) error AddLocalConfig(dir, name, value string) error + AddGlobalConfig(name, value string) error ShowFormat(dir, commit, format string) (string, error) ListRemote(url string, args ...string) (string, string, error) TimedListRemote(timeout time.Duration, url string, args ...string) (string, string, error) @@ -260,6 +262,12 @@ func (r *repository) AddLocalConfig(location, name, value string) error { return err } +// AddGlobalConfig adds a value to the global git configuration +func (r *repository) AddGlobalConfig(name, value string) error { + _, _, err := r.git("", "config", "--global", "--add", name, value) + return err +} + // CloneWithOptions clones a remote git repository to a local directory func (r *repository) CloneWithOptions(location string, url string, args ...string) error { gitArgs := []string{"clone"} @@ -421,7 +429,9 @@ func command(name, dir string, env []string, args ...string) (stdout, stderr str func timedCommand(timeout time.Duration, name, dir string, env []string, args ...string) (stdout, stderr string, err error) { var stdoutBuffer, stderrBuffer bytes.Buffer - klog.V(4).Infof("Executing %s %s", name, strings.Join(args, " ")) + logArgs := safeForLoggingArgs(args...) + + klog.V(4).Infof("Executing %s %s", name, strings.Join(logArgs, " ")) cmd := exec.Command(name, args...) cmd.Dir = dir @@ -466,6 +476,29 @@ func timedCommand(timeout time.Duration, name, dir string, env []string, args .. return stdout, stderr, err } +// safeForLoggingArgs checks if a list of arguments contains a URL with embedded credentials. +// If credentials are found, the username and password are redacted. +func safeForLoggingArgs(args ...string) []string { + safeArgs := []string{} + for _, arg := range args { + u, err := url.Parse(arg) + if err != nil { + safeArgs = append(safeArgs, arg) + continue + } + if u.User == nil { + safeArgs = append(safeArgs, arg) + continue + } + if _, passwordSet := u.User.Password(); passwordSet { + // wipe out the user info from the url. + u.User = url.User("redacted") + } + safeArgs = append(safeArgs, u.String()) + } + return safeArgs +} + // runCommand runs the command with the given timeout, and returns any errors encountered and whether // the command timed out or not func runCommand(cmd *exec.Cmd, timeout time.Duration) (error, bool) { diff --git a/vendor/github.com/openshift/library-go/pkg/image/dockerv1client/client.go b/vendor/github.com/openshift/library-go/pkg/image/dockerv1client/client.go index fd8f0dbaab7e..cd15cd279498 100644 --- a/vendor/github.com/openshift/library-go/pkg/image/dockerv1client/client.go +++ b/vendor/github.com/openshift/library-go/pkg/image/dockerv1client/client.go @@ -35,10 +35,13 @@ var ( // convertImageToDockerImage converts an object of type *godockerclient.Image to *docker10.DockerImage func convertImageToDockerImage(in *godockerclient.Image, out *docker10.DockerImage, s conversion.Scope) error { - if err := s.Convert(&in.Config, &out.Config, conversion.AllowDifferentFieldTypeNames); err != nil { + if out.Config == nil { + out.Config = new(docker10.DockerConfig) + } + if err := convertConfigToDockerConfig(in.Config, out.Config); err != nil { return err } - if err := s.Convert(&in.ContainerConfig, &out.ContainerConfig, conversion.AllowDifferentFieldTypeNames); err != nil { + if err := convertConfigToDockerConfig(&in.ContainerConfig, &out.ContainerConfig); err != nil { return err } out.ID = in.ID @@ -53,12 +56,55 @@ func convertImageToDockerImage(in *godockerclient.Image, out *docker10.DockerIma return nil } +// convertConfigToDockerConfig converts an object of type *godockerclient.Config to *docker10.DockerConfig +func convertConfigToDockerConfig(in *godockerclient.Config, out *docker10.DockerConfig) error { + if in == nil { + return nil + } + out.Hostname = in.Hostname + out.Domainname = in.Domainname + out.User = in.User + out.Memory = in.Memory + out.MemorySwap = in.MemorySwap + out.CPUShares = in.CPUShares + out.CPUSet = in.CPUSet + out.AttachStdin = in.AttachStdin + out.AttachStdout = in.AttachStdout + out.AttachStderr = in.AttachStderr + out.PortSpecs = in.PortSpecs + if out.ExposedPorts == nil { + out.ExposedPorts = make(map[string]struct{}) + } + for k, v := range in.ExposedPorts { + out.ExposedPorts[string(k)] = v + } + out.Tty = in.Tty + out.OpenStdin = in.OpenStdin + out.StdinOnce = in.StdinOnce + out.Env = in.Env + out.Cmd = in.Cmd + out.DNS = in.DNS + out.Image = in.Image + out.Volumes = in.Volumes + out.VolumesFrom = in.VolumesFrom + out.WorkingDir = in.WorkingDir + out.Entrypoint = in.Entrypoint + out.NetworkDisabled = in.NetworkDisabled + out.SecurityOpts = in.SecurityOpts + out.OnBuild = in.OnBuild + out.Labels = in.Labels + return nil +} + // convertDockerImageToImage converts an object of type *docker10.DockerImage to *godockerclient.Image func convertDockerImageToImage(in *docker10.DockerImage, out *godockerclient.Image, s conversion.Scope) error { - if err := s.Convert(&in.Config, &out.Config, conversion.AllowDifferentFieldTypeNames); err != nil { + if out.Config == nil { + out.Config = new(godockerclient.Config) + } + if err := convertDockerConfigToConfig(in.Config, out.Config); err != nil { return err } - if err := s.Convert(&in.ContainerConfig, &out.ContainerConfig, conversion.AllowDifferentFieldTypeNames); err != nil { + if err := convertDockerConfigToConfig(&in.ContainerConfig, &out.ContainerConfig); err != nil { return err } out.ID = in.ID @@ -73,6 +119,46 @@ func convertDockerImageToImage(in *docker10.DockerImage, out *godockerclient.Ima return nil } +// convertDockerConfigToConfig converts an object of type *docker10.DockerConfig to *godockerclient.Config +func convertDockerConfigToConfig(in *docker10.DockerConfig, out *godockerclient.Config) error { + if in == nil { + return nil + } + out.Hostname = in.Hostname + out.Domainname = in.Domainname + out.User = in.User + out.Memory = in.Memory + out.MemorySwap = in.MemorySwap + out.CPUShares = in.CPUShares + out.CPUSet = in.CPUSet + out.AttachStdin = in.AttachStdin + out.AttachStdout = in.AttachStdout + out.AttachStderr = in.AttachStderr + out.PortSpecs = in.PortSpecs + if out.ExposedPorts == nil { + out.ExposedPorts = make(map[godockerclient.Port]struct{}) + } + for k, v := range in.ExposedPorts { + out.ExposedPorts[godockerclient.Port(k)] = v + } + out.Tty = in.Tty + out.OpenStdin = in.OpenStdin + out.StdinOnce = in.StdinOnce + out.Env = in.Env + out.Cmd = in.Cmd + out.DNS = in.DNS + out.Image = in.Image + out.Volumes = in.Volumes + out.VolumesFrom = in.VolumesFrom + out.WorkingDir = in.WorkingDir + out.Entrypoint = in.Entrypoint + out.NetworkDisabled = in.NetworkDisabled + out.SecurityOpts = in.SecurityOpts + out.OnBuild = in.OnBuild + out.Labels = in.Labels + return nil +} + func init() { ImageScheme.AddConversionFunc((*godockerclient.Image)(nil), (*docker10.DockerImage)(nil), func(a, b interface{}, scope conversion.Scope) error { return convertImageToDockerImage(a.(*godockerclient.Image), b.(*docker10.DockerImage), scope) diff --git a/vendor/github.com/openshift/library-go/pkg/network/dialer.go b/vendor/github.com/openshift/library-go/pkg/network/dialer.go new file mode 100644 index 000000000000..f19be44a3e99 --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/network/dialer.go @@ -0,0 +1,13 @@ +package network + +import ( + "context" + "net" +) + +type DialContext func(ctx context.Context, network, address string) (net.Conn, error) + +// DefaultDialContext returns a DialContext function from a network dialer with default options sets. +func DefaultClientDialContext() DialContext { + return dialerWithDefaultOptions() +} diff --git a/vendor/github.com/openshift/library-go/pkg/network/dialer_linux.go b/vendor/github.com/openshift/library-go/pkg/network/dialer_linux.go new file mode 100644 index 000000000000..b8ff8db85ee2 --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/network/dialer_linux.go @@ -0,0 +1,93 @@ +// +build linux + +package network + +import ( + "net" + "os" + "syscall" + "time" + + "golang.org/x/sys/unix" + + utilerrors "k8s.io/apimachinery/pkg/util/errors" +) + +func dialerWithDefaultOptions() DialContext { + nd := &net.Dialer{ + // TCP_USER_TIMEOUT does affect the behaviour of connect() which is controlled by this field so we set it to the same value + Timeout: 25 * time.Second, + // KeepAlive must to be set to a negative value to stop std library from applying the default values + // by doing so we ensure that the options we are interested in won't be overwritten + KeepAlive: time.Duration(-1), + Control: func(network, address string, con syscall.RawConn) error { + var errs []error + err := con.Control(func(fd uintptr) { + optionsErr := setDefaultSocketOptions(int(fd)) + if optionsErr != nil { + errs = append(errs, optionsErr) + } + }) + if err != nil { + errs = append(errs, err) + } + return utilerrors.NewAggregate(errs) + }, + } + return nd.DialContext +} + +// setDefaultSocketOptions sets custom socket options so that we can detect connections to an unhealthy (dead) peer quickly. +// In particular we set TCP_USER_TIMEOUT that specifies the maximum amount of time that transmitted data may remain +// unacknowledged before TCP will forcibly close the connection. +// +// Note +// TCP_USER_TIMEOUT can't be too low because a single dropped packet might drop the entire connection. +// Ideally it should be set to: TCP_KEEPIDLE + TCP_KEEPINTVL * TCP_KEEPCNT +func setDefaultSocketOptions(fd int) error { + // specifies the maximum amount of time in milliseconds that transmitted data may remain + // unacknowledged before TCP will forcibly close the corresponding connection and return ETIMEDOUT to the application + tcpUserTimeoutInMilliSeconds := int(25 * time.Second / time.Millisecond) + + // specifies the interval at which probes are sent in seconds + tcpKeepIntvl := int(roundDuration(5*time.Second, time.Second)) + + // specifies the threshold for sending the first KEEP ALIVE probe in seconds + tcpKeepIdle := int(roundDuration(2*time.Second, time.Second)) + + // enable keep-alive probes + if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil { + return wrapSyscallError("setsockopt", err) + } + + if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, tcpUserTimeoutInMilliSeconds); err != nil { + return wrapSyscallError("setsockopt", err) + } + + if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, tcpKeepIntvl); err != nil { + return wrapSyscallError("setsockopt", err) + } + + if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, tcpKeepIdle); err != nil { + return wrapSyscallError("setsockopt", err) + } + return nil +} + +// roundDurationUp rounds d to the next multiple of to. +// +// note that it was copied from the std library +func roundDuration(d time.Duration, to time.Duration) time.Duration { + return (d + to - 1) / to +} + +// wrapSyscallError takes an error and a syscall name. If the error is +// a syscall.Errno, it wraps it in a os.SyscallError using the syscall name. +// +// note that it was copied from the std library +func wrapSyscallError(name string, err error) error { + if _, ok := err.(syscall.Errno); ok { + err = os.NewSyscallError(name, err) + } + return err +} diff --git a/vendor/github.com/openshift/library-go/pkg/network/dialer_others.go b/vendor/github.com/openshift/library-go/pkg/network/dialer_others.go new file mode 100644 index 000000000000..6519b0986db2 --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/network/dialer_others.go @@ -0,0 +1,19 @@ +// +build !linux + +package network + +import ( + "net" + "time" + + "k8s.io/klog/v2" +) + +func dialerWithDefaultOptions() DialContext { + klog.V(2).Info("Creating the default network Dialer (unsupported platform). It may take up to 15 minutes to detect broken connections and establish a new one") + nd := &net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + } + return nd.DialContext +} diff --git a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/admissions.go b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/admissions.go new file mode 100644 index 000000000000..0edc4434918d --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/admissions.go @@ -0,0 +1,77 @@ +package resourceapply + +import ( + "context" + + admissionv1 "k8s.io/api/admissionregistration/v1" + "k8s.io/apimachinery/pkg/api/equality" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + admissionclientv1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1" + "k8s.io/klog/v2" + + "github.com/openshift/library-go/pkg/operator/events" + "github.com/openshift/library-go/pkg/operator/resource/resourcemerge" +) + +// ApplyValidatingWebhookConfiguration merges objectmeta, update webhooks. +func ApplyValidatingWebhookConfiguration(client admissionclientv1.ValidatingWebhookConfigurationsGetter, recorder events.Recorder, required *admissionv1.ValidatingWebhookConfiguration) (*admissionv1.ValidatingWebhookConfiguration, bool, error) { + existing, err := client.ValidatingWebhookConfigurations().Get(context.TODO(), required.Name, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + actual, err := client.ValidatingWebhookConfigurations(). + Create(context.TODO(), required, metav1.CreateOptions{}) + reportCreateEvent(recorder, required, err) + return actual, true, err + } + if err != nil { + return nil, false, err + } + + modified := resourcemerge.BoolPtr(false) + existingCopy := existing.DeepCopy() + + resourcemerge.EnsureObjectMeta(modified, &existingCopy.ObjectMeta, required.ObjectMeta) + contentSame := equality.Semantic.DeepEqual(existingCopy.Webhooks, required.Webhooks) + if contentSame && !*modified { + return existingCopy, false, nil + } + + if klog.V(4).Enabled() { + klog.Infof("ValidatingWebhookConfiguration %q changes: %v", required.Name, JSONPatchNoError(existing, required)) + } + + actual, err := client.ValidatingWebhookConfigurations().Update(context.TODO(), required, metav1.UpdateOptions{}) + reportUpdateEvent(recorder, required, err) + return actual, true, err +} + +// ApplyMutatingWebhookConfiguration merges objectmeta, update webhooks. +func ApplyMutatingWebhookConfiguration(client admissionclientv1.MutatingWebhookConfigurationsGetter, recorder events.Recorder, required *admissionv1.MutatingWebhookConfiguration) (*admissionv1.MutatingWebhookConfiguration, bool, error) { + existing, err := client.MutatingWebhookConfigurations().Get(context.TODO(), required.Name, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + actual, err := client.MutatingWebhookConfigurations(). + Create(context.TODO(), required, metav1.CreateOptions{}) + reportCreateEvent(recorder, required, err) + return actual, true, err + } + if err != nil { + return nil, false, err + } + + modified := resourcemerge.BoolPtr(false) + existingCopy := existing.DeepCopy() + + resourcemerge.EnsureObjectMeta(modified, &existingCopy.ObjectMeta, required.ObjectMeta) + contentSame := equality.Semantic.DeepEqual(existingCopy.Webhooks, required.Webhooks) + if contentSame && !*modified { + return existingCopy, false, nil + } + + if klog.V(4).Enabled() { + klog.Infof("ValidatingWebhookConfiguration %q changes: %v", required.Name, JSONPatchNoError(existing, required)) + } + + actual, err := client.MutatingWebhookConfigurations().Update(context.TODO(), required, metav1.UpdateOptions{}) + reportUpdateEvent(recorder, required, err) + return actual, true, err +} diff --git a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/generic.go b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/generic.go index 7f62f87abe25..43a4ce30f805 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/generic.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/generic.go @@ -9,6 +9,7 @@ import ( "github.com/openshift/api" "github.com/openshift/library-go/pkg/operator/events" + admissionv1 "k8s.io/api/admissionregistration/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" storagev1 "k8s.io/api/storage/v1" @@ -165,6 +166,16 @@ func ApplyDirectly(clients *ClientHolder, recorder events.Recorder, manifests As result.Error = fmt.Errorf("missing kubeClient") } result.Result, result.Changed, result.Error = ApplyCSIDriver(clients.kubeClient.StorageV1(), recorder, t) + case *admissionv1.ValidatingWebhookConfiguration: + if clients.kubeClient == nil { + result.Error = fmt.Errorf("missing kubeClient") + } + result.Result, result.Changed, result.Error = ApplyValidatingWebhookConfiguration(clients.kubeClient.AdmissionregistrationV1(), recorder, t) + case *admissionv1.MutatingWebhookConfiguration: + if clients.kubeClient == nil { + result.Error = fmt.Errorf("missing kubeClient") + } + result.Result, result.Changed, result.Error = ApplyMutatingWebhookConfiguration(clients.kubeClient.AdmissionregistrationV1(), recorder, t) default: result.Error = fmt.Errorf("unhandled type %T", requiredObj) } diff --git a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceread/apiextensions.go b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceread/apiextensions.go index 09428268d710..e21f774e1e3d 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceread/apiextensions.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceread/apiextensions.go @@ -27,7 +27,7 @@ func ReadCustomResourceDefinitionV1Beta1OrDie(objBytes []byte) *apiextensionsv1b } func ReadCustomResourceDefinitionV1OrDie(objBytes []byte) *apiextensionsv1.CustomResourceDefinition { - requiredObj, err := runtime.Decode(apiExtensionsCodecs.UniversalDecoder(apiextensionsv1beta1.SchemeGroupVersion), objBytes) + requiredObj, err := runtime.Decode(apiExtensionsCodecs.UniversalDecoder(apiextensionsv1.SchemeGroupVersion), objBytes) if err != nil { panic(err) } diff --git a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceread/core.go b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceread/core.go index ac2b477585bf..daa27c7b509b 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceread/core.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceread/core.go @@ -58,11 +58,19 @@ func ReadServiceV1OrDie(objBytes []byte) *corev1.Service { } func ReadPodV1OrDie(objBytes []byte) *corev1.Pod { - requiredObj, err := runtime.Decode(coreCodecs.UniversalDecoder(corev1.SchemeGroupVersion), objBytes) + requiredObj, err := ReadPodV1(objBytes) if err != nil { panic(err) } - return requiredObj.(*corev1.Pod) + return requiredObj +} + +func ReadPodV1(objBytes []byte) (*corev1.Pod, error) { + requiredObj, err := runtime.Decode(coreCodecs.UniversalDecoder(corev1.SchemeGroupVersion), objBytes) + if err != nil { + return nil, err + } + return requiredObj.(*corev1.Pod), nil } func WritePodV1OrDie(obj *corev1.Pod) string { diff --git a/vendor/github.com/openshift/library-go/pkg/operator/v1helpers/informers.go b/vendor/github.com/openshift/library-go/pkg/operator/v1helpers/informers.go index 8a3636b334bf..ba3769252d7d 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/v1helpers/informers.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/v1helpers/informers.go @@ -20,8 +20,13 @@ type KubeInformersForNamespaces interface { ConfigMapLister() corev1listers.ConfigMapLister SecretLister() corev1listers.SecretLister + + // Used in by workloads controller and controllers that report deployment pods status + PodLister() corev1listers.PodLister } +var _ KubeInformersForNamespaces = kubeInformersForNamespaces{} + func NewKubeInformersForNamespaces(kubeClient kubernetes.Interface, namespaces ...string) KubeInformersForNamespaces { ret := kubeInformersForNamespaces{} for _, namespace := range namespaces { @@ -103,3 +108,28 @@ func (l secretLister) Secrets(namespace string) corev1listers.SecretNamespaceLis return informer.Core().V1().Secrets().Lister().Secrets(namespace) } + +type podLister kubeInformersForNamespaces + +func (i kubeInformersForNamespaces) PodLister() corev1listers.PodLister { + return podLister(i) +} + +func (l podLister) List(selector labels.Selector) (ret []*corev1.Pod, err error) { + globalInformer, ok := l[""] + if !ok { + return nil, fmt.Errorf("combinedLister does not support cross namespace list") + } + + return globalInformer.Core().V1().Pods().Lister().List(selector) +} + +func (l podLister) Pods(namespace string) corev1listers.PodNamespaceLister { + informer, ok := l[namespace] + if !ok { + // coding error + panic(fmt.Sprintf("namespace %q is missing", namespace)) + } + + return informer.Core().V1().Pods().Lister().Pods(namespace) +} diff --git a/vendor/k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap/default.go b/vendor/k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap/default.go index 147128709cd8..3cde94ff19c5 100644 --- a/vendor/k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap/default.go +++ b/vendor/k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap/default.go @@ -210,7 +210,7 @@ var ( flowcontrol.PriorityLevelConfigurationSpec{ Type: flowcontrol.PriorityLevelEnablementLimited, Limited: &flowcontrol.LimitedPriorityLevelConfiguration{ - AssuredConcurrencyShares: 20, + AssuredConcurrencyShares: 100, LimitResponse: flowcontrol.LimitResponse{ Type: flowcontrol.LimitResponseTypeQueue, Queuing: &flowcontrol.QueuingConfiguration{ @@ -227,7 +227,7 @@ var ( flowcontrol.PriorityLevelConfigurationSpec{ Type: flowcontrol.PriorityLevelEnablementLimited, Limited: &flowcontrol.LimitedPriorityLevelConfiguration{ - AssuredConcurrencyShares: 100, + AssuredConcurrencyShares: 20, LimitResponse: flowcontrol.LimitResponse{ Type: flowcontrol.LimitResponseTypeQueue, Queuing: &flowcontrol.QueuingConfiguration{ diff --git a/vendor/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go b/vendor/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go index 5b9af2a04bec..d8b508eef8e0 100644 --- a/vendor/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go +++ b/vendor/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go @@ -185,6 +185,16 @@ var ( }, []string{"verb", "group", "version", "resource", "subresource", "scope", "component", "code"}, ) + // requestAbortsTotal is a number of aborted requests with http.ErrAbortHandler + requestAbortsTotal = compbasemetrics.NewCounterVec( + &compbasemetrics.CounterOpts{ + Name: "apiserver_request_aborts_total", + Help: "Number of requests which apiserver aborted possibly due to a timeout, for each group, version, verb, resource, subresource and scope", + StabilityLevel: compbasemetrics.ALPHA, + }, + []string{"verb", "group", "version", "resource", "subresource", "scope"}, + ) + kubectlExeRegexp = regexp.MustCompile(`^.*((?i:kubectl\.exe))`) metrics = []resettableCollector{ @@ -201,6 +211,7 @@ var ( currentInflightRequests, currentInqueueRequests, requestTerminationsTotal, + requestAbortsTotal, } // these are the known (e.g. whitelisted/known) content types which we will report for @@ -290,6 +301,22 @@ func UpdateInflightRequestMetrics(phase string, nonmutating, mutating int) { } } +// RecordRequestAbort records that the request was aborted possibly due to a timeout. +func RecordRequestAbort(req *http.Request, requestInfo *request.RequestInfo) { + if requestInfo == nil { + requestInfo = &request.RequestInfo{Verb: req.Method, Path: req.URL.Path} + } + + scope := CleanScope(requestInfo) + reportedVerb := cleanVerb(canonicalVerb(strings.ToUpper(req.Method), scope), req) + resource := requestInfo.Resource + subresource := requestInfo.Subresource + group := requestInfo.APIGroup + version := requestInfo.APIVersion + + requestAbortsTotal.WithLabelValues(reportedVerb, group, version, resource, subresource, scope).Inc() +} + // RecordRequestTermination records that the request was terminated early as part of a resource // preservation or apiserver self-defense mechanism (e.g. timeouts, maxinflight throttling, // proxyHandler errors). RecordRequestTermination should only be called zero or one times diff --git a/vendor/k8s.io/apiserver/pkg/server/config.go b/vendor/k8s.io/apiserver/pkg/server/config.go index e9a2aa38739e..50d098f1f00d 100644 --- a/vendor/k8s.io/apiserver/pkg/server/config.go +++ b/vendor/k8s.io/apiserver/pkg/server/config.go @@ -777,7 +777,7 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler { handler = genericapifilters.WithWarningRecorder(handler) handler = genericapifilters.WithCacheControl(handler) handler = genericapifilters.WithRequestReceivedTimestamp(handler) - handler = genericfilters.WithPanicRecovery(handler, c.IsTerminating) + handler = genericfilters.WithPanicRecovery(handler, c.IsTerminating, c.RequestInfoResolver) return handler } diff --git a/vendor/k8s.io/apiserver/pkg/server/filters/BUILD b/vendor/k8s.io/apiserver/pkg/server/filters/BUILD index a13e51bf319b..8b305b7363e1 100644 --- a/vendor/k8s.io/apiserver/pkg/server/filters/BUILD +++ b/vendor/k8s.io/apiserver/pkg/server/filters/BUILD @@ -19,14 +19,28 @@ go_test( deps = [ "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library", "//staging/src/k8s.io/apiserver/pkg/endpoints/filters:go_default_library", "//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/server/mux:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/flowcontrol:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/flowcontrol/metrics:go_default_library", + "//staging/src/k8s.io/client-go/informers:go_default_library", + "//staging/src/k8s.io/client-go/kubernetes:go_default_library", + "//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library", + "//staging/src/k8s.io/component-base/metrics/legacyregistry:go_default_library", + "//staging/src/k8s.io/component-base/metrics/testutil:go_default_library", "//vendor/golang.org/x/net/http2:go_default_library", + "//vendor/k8s.io/klog/v2:go_default_library", ], ) diff --git a/vendor/k8s.io/apiserver/pkg/server/filters/timeout.go b/vendor/k8s.io/apiserver/pkg/server/filters/timeout.go index 9b8d6d4b138d..2405bfd1ff92 100644 --- a/vendor/k8s.io/apiserver/pkg/server/filters/timeout.go +++ b/vendor/k8s.io/apiserver/pkg/server/filters/timeout.go @@ -33,8 +33,6 @@ import ( apirequest "k8s.io/apiserver/pkg/endpoints/request" ) -var errConnKilled = fmt.Errorf("killing connection/stream because serving request timed out and response had been started") - // WithTimeoutForNonLongRunningRequests times out non-long-running requests after the time given by timeout. func WithTimeoutForNonLongRunningRequests(handler http.Handler, longRunning apirequest.LongRunningRequestCheck, timeout time.Duration) http.Handler { if longRunning == nil { @@ -246,15 +244,17 @@ func (tw *baseTimeoutWriter) timeout(err *apierrors.StatusError) { // no way to timeout the HTTP request at the point. We have to shutdown // the connection for HTTP1 or reset stream for HTTP2. // - // Note from: Brad Fitzpatrick - // if the ServeHTTP goroutine panics, that will do the best possible thing for both - // HTTP/1 and HTTP/2. In HTTP/1, assuming you're replying with at least HTTP/1.1 and - // you've already flushed the headers so it's using HTTP chunking, it'll kill the TCP - // connection immediately without a proper 0-byte EOF chunk, so the peer will recognize - // the response as bogus. In HTTP/2 the server will just RST_STREAM the stream, leaving - // the TCP connection open, but resetting the stream to the peer so it'll have an error, - // like the HTTP/1 case. - panic(errConnKilled) + // Note from the golang's docs: + // If ServeHTTP panics, the server (the caller of ServeHTTP) assumes + // that the effect of the panic was isolated to the active request. + // It recovers the panic, logs a stack trace to the server error log, + // and either closes the network connection or sends an HTTP/2 + // RST_STREAM, depending on the HTTP protocol. To abort a handler so + // the client sees an interrupted response but the server doesn't log + // an error, panic with the value ErrAbortHandler. + // + // We are throwing http.ErrAbortHandler deliberately so that a client is notified and to suppress a not helpful stacktrace in the logs + panic(http.ErrAbortHandler) } } diff --git a/vendor/k8s.io/apiserver/pkg/server/filters/wrap.go b/vendor/k8s.io/apiserver/pkg/server/filters/wrap.go index 618bafb3caf4..f780c8b48ab1 100644 --- a/vendor/k8s.io/apiserver/pkg/server/filters/wrap.go +++ b/vendor/k8s.io/apiserver/pkg/server/filters/wrap.go @@ -17,22 +17,41 @@ limitations under the License. package filters import ( + "fmt" "net/http" - "k8s.io/klog/v2" - "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apiserver/pkg/endpoints/metrics" + "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/server/httplog" + "k8s.io/klog/v2" ) // WithPanicRecovery wraps an http Handler to recover and log panics (except in the special case of http.ErrAbortHandler panics, which suppress logging). -func WithPanicRecovery(handler http.Handler, isTerminating func() bool) http.Handler { +func WithPanicRecovery(handler http.Handler, isTerminating func() bool, resolver request.RequestInfoResolver) http.Handler { return withPanicRecovery(handler, func(w http.ResponseWriter, req *http.Request, err interface{}) { if err == http.ErrAbortHandler { - // honor the http.ErrAbortHandler sentinel panic value: - // ErrAbortHandler is a sentinel panic value to abort a handler. - // While any panic from ServeHTTP aborts the response to the client, - // panicking with ErrAbortHandler also suppresses logging of a stack trace to the server's error log. + // Honor the http.ErrAbortHandler sentinel panic value + // + // If ServeHTTP panics, the server (the caller of ServeHTTP) assumes + // that the effect of the panic was isolated to the active request. + // It recovers the panic, logs a stack trace to the server error log, + // and either closes the network connection or sends an HTTP/2 + // RST_STREAM, depending on the HTTP protocol. To abort a handler so + // the client sees an interrupted response but the server doesn't log + // an error, panic with the value ErrAbortHandler. + // + // Note that the ReallyCrash variable controls the behaviour of the HandleCrash function + // So it might actually crash, after calling the handlers + if info, err := resolver.NewRequestInfo(req); err != nil { + metrics.RecordRequestAbort(req, nil) + } else { + metrics.RecordRequestAbort(req, info) + } + // This call can have different handlers, but the default chain rate limits. Call it after the metrics are updated + // in case the rate limit delays it. If you outrun the rate for this one timed out requests, something has gone + // seriously wrong with your server, but generally having a logging signal for timeouts is useful. + runtime.HandleError(fmt.Errorf("timeout or abort while handling: %v %q", req.Method, req.URL.Path)) return } http.Error(w, "This request caused apiserver to panic. Look in the logs for details.", http.StatusInternalServerError) diff --git a/vendor/k8s.io/apiserver/pkg/server/options/authentication.go b/vendor/k8s.io/apiserver/pkg/server/options/authentication.go index 1929e975058d..c6b30bd187d9 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/authentication.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/authentication.go @@ -177,6 +177,10 @@ type DelegatingAuthenticationOptions struct { // TolerateInClusterLookupFailure indicates failures to look up authentication configuration from the cluster configmap should not be fatal. // Setting this can result in an authenticator that will reject all requests. TolerateInClusterLookupFailure bool + + // ClientTimeout specifies a time limit for requests made by the authorization webhook client. + // The default value is set to 10 seconds. + ClientTimeout time.Duration } func NewDelegatingAuthenticationOptions() *DelegatingAuthenticationOptions { @@ -189,9 +193,15 @@ func NewDelegatingAuthenticationOptions() *DelegatingAuthenticationOptions { GroupHeaders: []string{"x-remote-group"}, ExtraHeaderPrefixes: []string{"x-remote-extra-"}, }, + ClientTimeout: 10 * time.Second, } } +// WithClientTimeout sets the given timeout for the authentication webhook client. +func (s *DelegatingAuthenticationOptions) WithClientTimeout(timeout time.Duration) { + s.ClientTimeout = timeout +} + func (s *DelegatingAuthenticationOptions) Validate() []error { allErrors := []error{} allErrors = append(allErrors, s.RequestHeader.Validate()...) @@ -377,6 +387,7 @@ func (s *DelegatingAuthenticationOptions) getClient() (kubernetes.Interface, err // set high qps/burst limits since this will effectively limit API server responsiveness clientConfig.QPS = 200 clientConfig.Burst = 400 + clientConfig.Timeout = s.ClientTimeout return kubernetes.NewForConfig(clientConfig) } diff --git a/vendor/k8s.io/apiserver/pkg/server/options/authorization.go b/vendor/k8s.io/apiserver/pkg/server/options/authorization.go index dab4abcc9cfe..67cb2c66c6cf 100644 --- a/vendor/k8s.io/apiserver/pkg/server/options/authorization.go +++ b/vendor/k8s.io/apiserver/pkg/server/options/authorization.go @@ -59,6 +59,10 @@ type DelegatingAuthorizationOptions struct { // AlwaysAllowGroups are groups which are allowed to take any actions. In kube, this is system:masters. AlwaysAllowGroups []string + + // ClientTimeout specifies a time limit for requests made by SubjectAccessReviews client. + // The default value is set to 10 seconds. + ClientTimeout time.Duration } func NewDelegatingAuthorizationOptions() *DelegatingAuthorizationOptions { @@ -66,6 +70,7 @@ func NewDelegatingAuthorizationOptions() *DelegatingAuthorizationOptions { // very low for responsiveness, but high enough to handle storms AllowCacheTTL: 10 * time.Second, DenyCacheTTL: 10 * time.Second, + ClientTimeout: 10 * time.Second, } } @@ -81,6 +86,11 @@ func (s *DelegatingAuthorizationOptions) WithAlwaysAllowPaths(paths ...string) * return s } +// WithClientTimeout sets the given timeout for SAR client used by this authorizer +func (s *DelegatingAuthorizationOptions) WithClientTimeout(timeout time.Duration) { + s.ClientTimeout = timeout +} + func (s *DelegatingAuthorizationOptions) Validate() []error { allErrors := []error{} return allErrors @@ -186,6 +196,7 @@ func (s *DelegatingAuthorizationOptions) getClient() (kubernetes.Interface, erro // set high qps/burst limits since this will effectively limit API server responsiveness clientConfig.QPS = 200 clientConfig.Burst = 400 + clientConfig.Timeout = s.ClientTimeout // make the client use protobuf protoConfig := rest.CopyConfig(clientConfig) diff --git a/vendor/k8s.io/apiserver/pkg/util/flowcontrol/BUILD b/vendor/k8s.io/apiserver/pkg/util/flowcontrol/BUILD index 12a9c16e91c1..ca8032c49cb7 100644 --- a/vendor/k8s.io/apiserver/pkg/util/flowcontrol/BUILD +++ b/vendor/k8s.io/apiserver/pkg/util/flowcontrol/BUILD @@ -78,6 +78,7 @@ go_test( "//staging/src/k8s.io/api/flowcontrol/v1alpha1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap:go_default_library", "//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library", "//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library", diff --git a/vendor/k8s.io/apiserver/pkg/util/flowcontrol/apf_controller.go b/vendor/k8s.io/apiserver/pkg/util/flowcontrol/apf_controller.go index 50eb33272168..3e30221761e9 100644 --- a/vendor/k8s.io/apiserver/pkg/util/flowcontrol/apf_controller.go +++ b/vendor/k8s.io/apiserver/pkg/util/flowcontrol/apf_controller.go @@ -34,6 +34,7 @@ import ( "k8s.io/apimachinery/pkg/labels" apitypes "k8s.io/apimachinery/pkg/types" apierrors "k8s.io/apimachinery/pkg/util/errors" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" fcboot "k8s.io/apiserver/pkg/apis/flowcontrol/bootstrap" "k8s.io/apiserver/pkg/authentication/user" @@ -244,14 +245,28 @@ func (cfgCtlr *configController) updateObservations() { } } +// used from the unit tests only. +func (cfgCtlr *configController) getPriorityLevelState(plName string) *priorityLevelState { + cfgCtlr.lock.Lock() + defer cfgCtlr.lock.Unlock() + return cfgCtlr.priorityLevelStates[plName] +} + func (cfgCtlr *configController) Run(stopCh <-chan struct{}) error { + defer utilruntime.HandleCrash() + + // Let the config worker stop when we are done defer cfgCtlr.configQueue.ShutDown() + klog.Info("Starting API Priority and Fairness config controller") if ok := cache.WaitForCacheSync(stopCh, cfgCtlr.plInformerSynced, cfgCtlr.fsInformerSynced); !ok { return fmt.Errorf("Never achieved initial sync") } + klog.Info("Running API Priority and Fairness config worker") - wait.Until(cfgCtlr.runWorker, time.Second, stopCh) + go wait.Until(cfgCtlr.runWorker, time.Second, stopCh) + + <-stopCh klog.Info("Shutting down API Priority and Fairness config worker") return nil } diff --git a/vendor/k8s.io/apiserver/pkg/util/flowcontrol/apf_filter.go b/vendor/k8s.io/apiserver/pkg/util/flowcontrol/apf_filter.go index 5b8c0391684c..7a205d73d356 100644 --- a/vendor/k8s.io/apiserver/pkg/util/flowcontrol/apf_filter.go +++ b/vendor/k8s.io/apiserver/pkg/util/flowcontrol/apf_filter.go @@ -112,21 +112,28 @@ func (cfgCtlr *configController) Handle(ctx context.Context, requestDigest Reque } klog.V(7).Infof("Handle(%#+v) => fsName=%q, distMethod=%#+v, plName=%q, isExempt=%v, queued=%v", requestDigest, fs.Name, fs.Spec.DistinguisherMethod, pl.Name, isExempt, queued) var executed bool - idle := req.Finish(func() { + idle, panicking := true, true + defer func() { + klog.V(7).Infof("Handle(%#+v) => fsName=%q, distMethod=%#+v, plName=%q, isExempt=%v, queued=%v, Finish() => panicking=%v idle=%v", + requestDigest, fs.Name, fs.Spec.DistinguisherMethod, pl.Name, isExempt, queued, panicking, idle) + if idle { + cfgCtlr.maybeReap(pl.Name) + } + }() + idle = req.Finish(func() { if queued { metrics.ObserveWaitingDuration(pl.Name, fs.Name, strconv.FormatBool(req != nil), time.Since(startWaitingTime)) } metrics.AddDispatch(pl.Name, fs.Name) executed = true startExecutionTime := time.Now() + defer func() { + metrics.ObserveExecutionDuration(pl.Name, fs.Name, time.Since(startExecutionTime)) + }() execFn() - metrics.ObserveExecutionDuration(pl.Name, fs.Name, time.Since(startExecutionTime)) }) if queued && !executed { metrics.ObserveWaitingDuration(pl.Name, fs.Name, strconv.FormatBool(req != nil), time.Since(startWaitingTime)) } - klog.V(7).Infof("Handle(%#+v) => fsName=%q, distMethod=%#+v, plName=%q, isExempt=%v, queued=%v, Finish() => idle=%v", requestDigest, fs.Name, fs.Spec.DistinguisherMethod, pl.Name, isExempt, queued, idle) - if idle { - cfgCtlr.maybeReap(pl.Name) - } + panicking = false } diff --git a/vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/queueset/queueset.go b/vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/queueset/queueset.go index b469a4ac5752..0d4a443e963c 100644 --- a/vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/queueset/queueset.go +++ b/vendor/k8s.io/apiserver/pkg/util/flowcontrol/fairqueuing/queueset/queueset.go @@ -316,8 +316,15 @@ func (req *request) Finish(execFn func()) bool { if !exec { return idle } - execFn() - return req.qs.finishRequestAndDispatchAsMuchAsPossible(req) + func() { + defer func() { + idle = req.qs.finishRequestAndDispatchAsMuchAsPossible(req) + }() + + execFn() + }() + + return idle } func (req *request) wait() (bool, bool) { diff --git a/vendor/k8s.io/apiserver/pkg/util/flowcontrol/metrics/sample_and_watermark.go b/vendor/k8s.io/apiserver/pkg/util/flowcontrol/metrics/sample_and_watermark.go index f5df0e6492e4..43bd13adb06a 100644 --- a/vendor/k8s.io/apiserver/pkg/util/flowcontrol/metrics/sample_and_watermark.go +++ b/vendor/k8s.io/apiserver/pkg/util/flowcontrol/metrics/sample_and_watermark.go @@ -64,13 +64,16 @@ func (spg SampleAndWaterMarkPairGenerator) metrics() Registerables { // SampleAndWaterMarkObserverGenerator creates TimedObservers that // populate histograms of samples and low- and high-water-marks. The // generator has a samplePeriod, and the histograms get an observation -// every samplePeriod. +// every samplePeriod. The sampling windows are quantized based on +// the monotonic rather than wall-clock times. The `t0` field is +// there so to provide a baseline for monotonic clock differences. type SampleAndWaterMarkObserverGenerator struct { *sampleAndWaterMarkObserverGenerator } type sampleAndWaterMarkObserverGenerator struct { clock clock.PassiveClock + t0 time.Time samplePeriod time.Duration samples *compbasemetrics.HistogramVec waterMarks *compbasemetrics.HistogramVec @@ -83,6 +86,7 @@ func NewSampleAndWaterMarkHistogramsGenerator(clock clock.PassiveClock, samplePe return SampleAndWaterMarkObserverGenerator{ &sampleAndWaterMarkObserverGenerator{ clock: clock, + t0: clock.Now(), samplePeriod: samplePeriod, samples: compbasemetrics.NewHistogramVec(sampleOpts, labelNames), waterMarks: compbasemetrics.NewHistogramVec(waterMarkOpts, append([]string{labelNameMark}, labelNames...)), @@ -90,7 +94,7 @@ func NewSampleAndWaterMarkHistogramsGenerator(clock clock.PassiveClock, samplePe } func (swg *sampleAndWaterMarkObserverGenerator) quantize(when time.Time) int64 { - return when.UnixNano() / int64(swg.samplePeriod) + return int64(when.Sub(swg.t0) / swg.samplePeriod) } // Generate makes a new TimedObserver @@ -156,31 +160,44 @@ func (saw *sampleAndWaterMarkHistograms) SetX1(x1 float64) { } func (saw *sampleAndWaterMarkHistograms) innerSet(updateXOrX1 func()) { - saw.Lock() - when := saw.clock.Now() - whenInt := saw.quantize(when) - acc := saw.sampleAndWaterMarkAccumulator - wellOrdered := !when.Before(acc.lastSet) - if wellOrdered { + when, whenInt, acc, wellOrdered := func() (time.Time, int64, sampleAndWaterMarkAccumulator, bool) { + saw.Lock() + defer saw.Unlock() + // Moved these variables here to tiptoe around https://github.com/golang/go/issues/43570 for #97685 + when := saw.clock.Now() + whenInt := saw.quantize(when) + acc := saw.sampleAndWaterMarkAccumulator + wellOrdered := !when.Before(acc.lastSet) updateXOrX1() saw.relX = saw.x / saw.x1 - if acc.lastSetInt < whenInt { - saw.loRelX, saw.hiRelX = acc.relX, acc.relX - saw.lastSetInt = whenInt + if wellOrdered { + if acc.lastSetInt < whenInt { + saw.loRelX, saw.hiRelX = acc.relX, acc.relX + saw.lastSetInt = whenInt + } + saw.lastSet = when } + // `wellOrdered` should always be true because we are using + // monotonic clock readings and they never go backwards. Yet + // very small backwards steps (under 1 microsecond) have been + // observed + // (https://github.com/kubernetes/kubernetes/issues/96459). + // In the backwards case, treat the current reading as if it + // had occurred at time `saw.lastSet` and log an error. It + // would be wrong to update `saw.lastSet` in this case because + // that plants a time bomb for future updates to + // `saw.lastSetInt`. if saw.relX < saw.loRelX { saw.loRelX = saw.relX } else if saw.relX > saw.hiRelX { saw.hiRelX = saw.relX } - saw.lastSet = when - } - saw.Unlock() + return when, whenInt, acc, wellOrdered + }() if !wellOrdered { - lastSetS := acc.lastSet.Format(time.RFC3339Nano) - whenS := when.Format(time.RFC3339Nano) - klog.Fatalf("Time went backwards from %s to %s for labelValues=%#+v", lastSetS, whenS, saw.labelValues) - panic(append([]string{lastSetS, whenS}, saw.labelValues...)) + lastSetS := acc.lastSet.String() + whenS := when.String() + klog.Errorf("Time went backwards from %s to %s for labelValues=%#+v", lastSetS, whenS, saw.labelValues) } for acc.lastSetInt < whenInt { saw.samples.WithLabelValues(saw.labelValues...).Observe(acc.relX) diff --git a/vendor/k8s.io/client-go/tools/cache/controller.go b/vendor/k8s.io/client-go/tools/cache/controller.go index 916ca9cc118e..3ad9b53bbea3 100644 --- a/vendor/k8s.io/client-go/tools/cache/controller.go +++ b/vendor/k8s.io/client-go/tools/cache/controller.go @@ -144,11 +144,11 @@ func (c *controller) Run(stopCh <-chan struct{}) { c.reflectorMutex.Unlock() var wg wait.Group - defer wg.Wait() wg.StartWithChannel(stopCh, r.Run) wait.Until(c.processLoop, time.Second, stopCh) + wg.Wait() } // Returns true once this controller has completed an initial resource listing diff --git a/vendor/k8s.io/client-go/tools/cache/reflector.go b/vendor/k8s.io/client-go/tools/cache/reflector.go index a92b36f2c7bf..e995abe25316 100644 --- a/vendor/k8s.io/client-go/tools/cache/reflector.go +++ b/vendor/k8s.io/client-go/tools/cache/reflector.go @@ -570,5 +570,26 @@ func isExpiredError(err error) bool { } func isTooLargeResourceVersionError(err error) bool { - return apierrors.HasStatusCause(err, metav1.CauseTypeResourceVersionTooLarge) + if apierrors.HasStatusCause(err, metav1.CauseTypeResourceVersionTooLarge) { + return true + } + // In Kubernetes 1.17.0-1.18.5, the api server doesn't set the error status cause to + // metav1.CauseTypeResourceVersionTooLarge to indicate that the requested minimum resource + // version is larger than the largest currently available resource version. To ensure backward + // compatibility with these server versions we also need to detect the error based on the content + // of the error message field. + if !apierrors.IsTimeout(err) { + return false + } + apierr, ok := err.(apierrors.APIStatus) + if !ok || apierr == nil || apierr.Status().Details == nil { + return false + } + for _, cause := range apierr.Status().Details.Causes { + // Matches the message returned by api server 1.17.0-1.18.5 for this error condition + if cause.Message == "Too large resource version" { + return true + } + } + return false } diff --git a/vendor/k8s.io/client-go/tools/leaderelection/leaderelection.go b/vendor/k8s.io/client-go/tools/leaderelection/leaderelection.go index 4a5329681285..483f0cba40bd 100644 --- a/vendor/k8s.io/client-go/tools/leaderelection/leaderelection.go +++ b/vendor/k8s.io/client-go/tools/leaderelection/leaderelection.go @@ -290,8 +290,12 @@ func (le *LeaderElector) release() bool { if !le.IsLeader() { return true } + now := metav1.Now() leaderElectionRecord := rl.LeaderElectionRecord{ - LeaderTransitions: le.observedRecord.LeaderTransitions, + LeaderTransitions: le.observedRecord.LeaderTransitions, + LeaseDurationSeconds: 1, + RenewTime: now, + AcquireTime: now, } if err := le.config.Lock.Update(context.TODO(), leaderElectionRecord); err != nil { klog.Errorf("Failed to release lock: %v", err) diff --git a/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/configmaplock.go b/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/configmaplock.go index 6390b4ef5fde..8c28026bad1f 100644 --- a/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/configmaplock.go +++ b/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/configmaplock.go @@ -92,8 +92,12 @@ func (cml *ConfigMapLock) Update(ctx context.Context, ler LeaderElectionRecord) cml.cm.Annotations = make(map[string]string) } cml.cm.Annotations[LeaderElectionRecordAnnotationKey] = string(recordBytes) - cml.cm, err = cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Update(ctx, cml.cm, metav1.UpdateOptions{}) - return err + cm, err := cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Update(ctx, cml.cm, metav1.UpdateOptions{}) + if err != nil { + return err + } + cml.cm = cm + return nil } // RecordEvent in leader election while adding meta-data diff --git a/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/endpointslock.go b/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/endpointslock.go index 132c5a54890a..d11e43e338aa 100644 --- a/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/endpointslock.go +++ b/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/endpointslock.go @@ -87,8 +87,12 @@ func (el *EndpointsLock) Update(ctx context.Context, ler LeaderElectionRecord) e el.e.Annotations = make(map[string]string) } el.e.Annotations[LeaderElectionRecordAnnotationKey] = string(recordBytes) - el.e, err = el.Client.Endpoints(el.EndpointsMeta.Namespace).Update(ctx, el.e, metav1.UpdateOptions{}) - return err + e, err := el.Client.Endpoints(el.EndpointsMeta.Namespace).Update(ctx, el.e, metav1.UpdateOptions{}) + if err != nil { + return err + } + el.e = e + return nil } // RecordEvent in leader election while adding meta-data diff --git a/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/leaselock.go b/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/leaselock.go index 3d76d174ea3e..a403497279d5 100644 --- a/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/leaselock.go +++ b/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/leaselock.go @@ -71,9 +71,14 @@ func (ll *LeaseLock) Update(ctx context.Context, ler LeaderElectionRecord) error return errors.New("lease not initialized, call get or create first") } ll.lease.Spec = LeaderElectionRecordToLeaseSpec(&ler) - var err error - ll.lease, err = ll.Client.Leases(ll.LeaseMeta.Namespace).Update(ctx, ll.lease, metav1.UpdateOptions{}) - return err + + lease, err := ll.Client.Leases(ll.LeaseMeta.Namespace).Update(ctx, ll.lease, metav1.UpdateOptions{}) + if err != nil { + return err + } + + ll.lease = lease + return nil } // RecordEvent in leader election while adding meta-data diff --git a/vendor/k8s.io/client-go/transport/cache.go b/vendor/k8s.io/client-go/transport/cache.go index 3ec4e19357de..2ad7dfb3182e 100644 --- a/vendor/k8s.io/client-go/transport/cache.go +++ b/vendor/k8s.io/client-go/transport/cache.go @@ -18,12 +18,13 @@ package transport import ( "fmt" - "net" "net/http" "strings" "sync" "time" + libgonetwork "github.com/openshift/library-go/pkg/network" + utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apimachinery/pkg/util/wait" ) @@ -47,12 +48,9 @@ type tlsCacheKey struct { keyData string certFile string keyFile string - getCert string serverName string nextProtos string - dial string disableCompression bool - proxy string } func (t tlsCacheKey) String() string { @@ -60,22 +58,24 @@ func (t tlsCacheKey) String() string { if len(t.keyData) > 0 { keyText = "" } - return fmt.Sprintf("insecure:%v, caData:%#v, certData:%#v, keyData:%s, getCert: %s, serverName:%s, dial:%s disableCompression:%t, proxy: %s", t.insecure, t.caData, t.certData, keyText, t.getCert, t.serverName, t.dial, t.disableCompression, t.proxy) + return fmt.Sprintf("insecure:%v, caData:%#v, certData:%#v, keyData:%s, serverName:%s, disableCompression:%t", t.insecure, t.caData, t.certData, keyText, t.serverName, t.disableCompression) } func (c *tlsTransportCache) get(config *Config) (http.RoundTripper, error) { - key, err := tlsConfigKey(config) + key, canCache, err := tlsConfigKey(config) if err != nil { return nil, err } - // Ensure we only create a single transport for the given TLS options - c.mu.Lock() - defer c.mu.Unlock() + if canCache { + // Ensure we only create a single transport for the given TLS options + c.mu.Lock() + defer c.mu.Unlock() - // See if we already have a custom transport for this config - if t, ok := c.transports[key]; ok { - return t, nil + // See if we already have a custom transport for this config + if t, ok := c.transports[key]; ok { + return t, nil + } } // Get the TLS options for this client config @@ -90,10 +90,7 @@ func (c *tlsTransportCache) get(config *Config) (http.RoundTripper, error) { dial := config.Dial if dial == nil { - dial = (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - }).DialContext + dial = libgonetwork.DefaultClientDialContext() } // If we use are reloading files, we need to handle certificate rotation properly @@ -110,8 +107,7 @@ func (c *tlsTransportCache) get(config *Config) (http.RoundTripper, error) { proxy = config.Proxy } - // Cache a single transport for these options - c.transports[key] = utilnet.SetTransportDefaults(&http.Transport{ + transport := utilnet.SetTransportDefaults(&http.Transport{ Proxy: proxy, TLSHandshakeTimeout: 10 * time.Second, TLSClientConfig: tlsConfig, @@ -119,24 +115,33 @@ func (c *tlsTransportCache) get(config *Config) (http.RoundTripper, error) { DialContext: dial, DisableCompression: config.DisableCompression, }) - return c.transports[key], nil + + if canCache { + // Cache a single transport for these options + c.transports[key] = transport + } + + return transport, nil } // tlsConfigKey returns a unique key for tls.Config objects returned from TLSConfigFor -func tlsConfigKey(c *Config) (tlsCacheKey, error) { +func tlsConfigKey(c *Config) (tlsCacheKey, bool, error) { // Make sure ca/key/cert content is loaded if err := loadTLSFiles(c); err != nil { - return tlsCacheKey{}, err + return tlsCacheKey{}, false, err } + + if c.TLS.GetCert != nil || c.Dial != nil || c.Proxy != nil { + // cannot determine equality for functions + return tlsCacheKey{}, false, nil + } + k := tlsCacheKey{ insecure: c.TLS.Insecure, caData: string(c.TLS.CAData), - getCert: fmt.Sprintf("%p", c.TLS.GetCert), serverName: c.TLS.ServerName, nextProtos: strings.Join(c.TLS.NextProtos, ","), - dial: fmt.Sprintf("%p", c.Dial), disableCompression: c.DisableCompression, - proxy: fmt.Sprintf("%p", c.Proxy), } if c.TLS.ReloadTLSFiles { @@ -147,5 +152,5 @@ func tlsConfigKey(c *Config) (tlsCacheKey, error) { k.keyData = string(c.TLS.KeyData) } - return k, nil + return k, true, nil } diff --git a/vendor/k8s.io/cloud-provider/go.mod b/vendor/k8s.io/cloud-provider/go.mod index 4d9498c7c6f1..911d2d19b278 100644 --- a/vendor/k8s.io/cloud-provider/go.mod +++ b/vendor/k8s.io/cloud-provider/go.mod @@ -19,6 +19,7 @@ replace ( github.com/containerd/continuity => github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc github.com/go-bindata/go-bindata => github.com/go-bindata/go-bindata v3.1.1+incompatible github.com/imdario/mergo => github.com/imdario/mergo v0.3.5 + github.com/mattn/go-colorable => github.com/mattn/go-colorable v0.0.9 github.com/onsi/ginkgo => github.com/openshift/ginkgo v4.5.0-origin.1+incompatible github.com/robfig/cron => github.com/robfig/cron v1.1.0 go.uber.org/multierr => go.uber.org/multierr v1.1.0 diff --git a/vendor/k8s.io/cloud-provider/go.sum b/vendor/k8s.io/cloud-provider/go.sum index 9e91812126e0..481337a27395 100644 --- a/vendor/k8s.io/cloud-provider/go.sum +++ b/vendor/k8s.io/cloud-provider/go.sum @@ -105,6 +105,7 @@ github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ github.com/coredns/corefile-migration v1.0.10/go.mod h1:RMy/mXdeDlYwzt0vdMEJvT2hGJ2I86/eO0UdXmH9XNI= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -114,6 +115,7 @@ github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+ github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -171,6 +173,7 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= @@ -218,6 +221,7 @@ github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2K github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= @@ -276,6 +280,7 @@ github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= @@ -412,7 +417,8 @@ github.com/openshift/client-go v0.0.0-20200827190008-3062137373b5/go.mod h1:5rGm github.com/openshift/ginkgo v4.5.0-origin.1+incompatible h1:AGewrYJW8aXFkkf86sSoiO9L/a/QYKZvODVCaB/wk4o= github.com/openshift/ginkgo v4.5.0-origin.1+incompatible/go.mod h1:8METQ1gDhl0KW+pGH4c0DIJYEN/ksVCL6hOuHPmXGnk= github.com/openshift/library-go v0.0.0-20200831114015-2ab0c61c15de/go.mod h1:6vwp+YhYOIlj8MpkQKkebTTSn2TuYyvgiAFQ206jIEQ= -github.com/openshift/library-go v0.0.0-20200902112127-a4e32e339219/go.mod h1:6vwp+YhYOIlj8MpkQKkebTTSn2TuYyvgiAFQ206jIEQ= +github.com/openshift/library-go v0.0.0-20201123125610-83d6d67a1e98 h1:JYwa3H00larjMVZXmh7L4FHDhNlKdWSgYi0kLdav9BY= +github.com/openshift/library-go v0.0.0-20201123125610-83d6d67a1e98/go.mod h1:KNfLGf4dIRJ+QB2aGy67AOy1k+DV783cMCuJf0d4Zik= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= @@ -474,6 +480,7 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -482,6 +489,7 @@ github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -497,6 +505,7 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -526,6 +535,7 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -610,6 +620,7 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -680,6 +691,7 @@ golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -761,6 +773,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -771,6 +784,8 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/heapster v1.2.0-beta.1/go.mod h1:h1uhptVXMwC8xtZBYsPXKVi8fpdlYkTs6k949KozGrM= +k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.2.0 h1:XRvcwJozkgZ1UQJmfMGpvRthQHOvihEhYtDfAaxMz/A= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6 h1:+WnxoVtG8TMiudHBSEtrVL1egv36TkkJm+bA8AxicmQ= @@ -788,6 +803,8 @@ modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.9/go.mod h1:dzAXnQbTRyDlZPJX2SUPEqvnB+j7AJjtlox7PEwigU0= +sigs.k8s.io/controller-tools v0.2.8/go.mod h1:9VKHPszmf2DHz/QmHkcfZoewO6BL7pPs9uAiBVsaJSE= +sigs.k8s.io/kube-storage-version-migrator v0.0.3/go.mod h1:mXfSLkx9xbJHQsgNDDUZK/iQTs2tMbx/hsJlWe6Fthw= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= sigs.k8s.io/structured-merge-diff/v4 v4.0.1 h1:YXTMot5Qz/X1iBRJhAt+vI+HVttY0WkSqqhKxQ0xVbA= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= diff --git a/vendor/k8s.io/component-base/cli/flag/BUILD b/vendor/k8s.io/component-base/cli/flag/BUILD new file mode 100644 index 000000000000..9c52db989892 --- /dev/null +++ b/vendor/k8s.io/component-base/cli/flag/BUILD @@ -0,0 +1,63 @@ +package(default_visibility = ["//visibility:public"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", + "go_test", +) + +go_test( + name = "go_default_test", + srcs = [ + "ciphersuites_flag_test.go", + "colon_separated_multimap_string_string_test.go", + "langle_separated_map_string_string_test.go", + "map_string_bool_test.go", + "map_string_string_test.go", + "namedcertkey_flag_test.go", + "string_slice_flag_test.go", + ], + embed = [":go_default_library"], + deps = ["//vendor/github.com/spf13/pflag:go_default_library"], +) + +go_library( + name = "go_default_library", + srcs = [ + "ciphersuites_flag.go", + "ciphersuites_flag_114.go", + "colon_separated_multimap_string_string.go", + "configuration_map.go", + "flags.go", + "langle_separated_map_string_string.go", + "map_string_bool.go", + "map_string_string.go", + "namedcertkey_flag.go", + "noop.go", + "omitempty.go", + "sectioned.go", + "string_flag.go", + "string_slice_flag.go", + "tristate.go", + ], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/cli/flag", + importpath = "k8s.io/component-base/cli/flag", + deps = [ + "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", + "//vendor/github.com/spf13/pflag:go_default_library", + "//vendor/k8s.io/klog/v2:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/vendor/k8s.io/component-base/cli/flag/string_slice_flag.go b/vendor/k8s.io/component-base/cli/flag/string_slice_flag.go new file mode 100644 index 000000000000..7b2e0f616956 --- /dev/null +++ b/vendor/k8s.io/component-base/cli/flag/string_slice_flag.go @@ -0,0 +1,55 @@ +/* +Copyright 2021 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 flag + +import ( + goflag "flag" + "strings" + + "github.com/spf13/pflag" +) + +// StringSlice implements goflag.Value and plfag.Value, +// and allows set to be invoked repeatedly to accumulate values. +type StringSlice struct { + value *[]string + changed bool +} + +func NewStringSlice(s *[]string) *StringSlice { + return &StringSlice{value: s} +} + +var _ goflag.Value = &StringSlice{} +var _ pflag.Value = &StringSlice{} + +func (s *StringSlice) String() string { + return strings.Join(*s.value, " ") +} + +func (s *StringSlice) Set(val string) error { + if s.value == nil || !s.changed { + *s.value = make([]string, 0) + } + *s.value = append(*s.value, val) + s.changed = true + return nil +} + +func (StringSlice) Type() string { + return "sliceString" +} diff --git a/vendor/k8s.io/component-base/cli/globalflag/BUILD b/vendor/k8s.io/component-base/cli/globalflag/BUILD new file mode 100644 index 000000000000..0f1f1919b13e --- /dev/null +++ b/vendor/k8s.io/component-base/cli/globalflag/BUILD @@ -0,0 +1,38 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["globalflags.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/cli/globalflag", + importpath = "k8s.io/component-base/cli/globalflag", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/component-base/logs:go_default_library", + "//vendor/github.com/spf13/pflag:go_default_library", + "//vendor/k8s.io/klog/v2:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["globalflags_test.go"], + embed = [":go_default_library"], + deps = [ + "//staging/src/k8s.io/component-base/cli/flag:go_default_library", + "//vendor/github.com/spf13/pflag:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/k8s.io/component-base/codec/BUILD b/vendor/k8s.io/component-base/codec/BUILD new file mode 100644 index 000000000000..9e848249cb6e --- /dev/null +++ b/vendor/k8s.io/component-base/codec/BUILD @@ -0,0 +1,27 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["codec.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/codec", + importpath = "k8s.io/component-base/codec", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/k8s.io/component-base/config/BUILD b/vendor/k8s.io/component-base/config/BUILD new file mode 100644 index 000000000000..b92f4e0fd884 --- /dev/null +++ b/vendor/k8s.io/component-base/config/BUILD @@ -0,0 +1,34 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "types.go", + "zz_generated.deepcopy.go", + ], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/config", + importpath = "k8s.io/component-base/config", + visibility = ["//visibility:public"], + deps = ["//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//staging/src/k8s.io/component-base/config/options:all-srcs", + "//staging/src/k8s.io/component-base/config/testing:all-srcs", + "//staging/src/k8s.io/component-base/config/v1alpha1:all-srcs", + "//staging/src/k8s.io/component-base/config/validation:all-srcs", + ], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/k8s.io/component-base/config/v1alpha1/BUILD b/vendor/k8s.io/component-base/config/v1alpha1/BUILD new file mode 100644 index 000000000000..d6deae7a9b1e --- /dev/null +++ b/vendor/k8s.io/component-base/config/v1alpha1/BUILD @@ -0,0 +1,38 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "conversion.go", + "defaults.go", + "doc.go", + "register.go", + "types.go", + "zz_generated.conversion.go", + "zz_generated.deepcopy.go", + ], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/config/v1alpha1", + importpath = "k8s.io/component-base/config/v1alpha1", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/conversion:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//staging/src/k8s.io/component-base/config:go_default_library", + "//vendor/k8s.io/utils/pointer:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/k8s.io/component-base/config/validation/BUILD b/vendor/k8s.io/component-base/config/validation/BUILD new file mode 100644 index 000000000000..fe29ae9c5b9d --- /dev/null +++ b/vendor/k8s.io/component-base/config/validation/BUILD @@ -0,0 +1,38 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["validation.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/config/validation", + importpath = "k8s.io/component-base/config/validation", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", + "//staging/src/k8s.io/component-base/config:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["validation_test.go"], + embed = [":go_default_library"], + deps = [ + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", + "//staging/src/k8s.io/component-base/config:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/k8s.io/component-base/configz/BUILD b/vendor/k8s.io/component-base/configz/BUILD new file mode 100644 index 000000000000..9c41245c20de --- /dev/null +++ b/vendor/k8s.io/component-base/configz/BUILD @@ -0,0 +1,33 @@ +package(default_visibility = ["//visibility:public"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", + "go_test", +) + +go_library( + name = "go_default_library", + srcs = ["configz.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/configz", + importpath = "k8s.io/component-base/configz", +) + +go_test( + name = "go_default_test", + srcs = ["configz_test.go"], + embed = [":go_default_library"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/vendor/k8s.io/component-base/featuregate/BUILD b/vendor/k8s.io/component-base/featuregate/BUILD new file mode 100644 index 000000000000..c5513c01e612 --- /dev/null +++ b/vendor/k8s.io/component-base/featuregate/BUILD @@ -0,0 +1,41 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["feature_gate.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/featuregate", + importpath = "k8s.io/component-base/featuregate", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/apimachinery/pkg/util/naming:go_default_library", + "//vendor/github.com/spf13/pflag:go_default_library", + "//vendor/k8s.io/klog/v2:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["feature_gate_test.go"], + embed = [":go_default_library"], + deps = [ + "//vendor/github.com/spf13/pflag:go_default_library", + "//vendor/github.com/stretchr/testify/assert:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//staging/src/k8s.io/component-base/featuregate/testing:all-srcs", + ], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/k8s.io/component-base/featuregate/feature_gate.go b/vendor/k8s.io/component-base/featuregate/feature_gate.go index c805ffb01b57..a61276b9d488 100644 --- a/vendor/k8s.io/component-base/featuregate/feature_gate.go +++ b/vendor/k8s.io/component-base/featuregate/feature_gate.go @@ -218,7 +218,8 @@ func (f *featureGate) SetFromMap(m map[string]bool) error { k := Feature(k) featureSpec, ok := known[k] if !ok { - return fmt.Errorf("unrecognized feature gate: %s", k) + klog.Warningf("unrecognized feature gate: %s", k) + continue } if featureSpec.LockToDefault && featureSpec.Default != v { return fmt.Errorf("cannot set feature gate %v to %v, feature is locked to %v", k, v, featureSpec.Default) diff --git a/vendor/k8s.io/component-base/logs/BUILD b/vendor/k8s.io/component-base/logs/BUILD new file mode 100644 index 000000000000..51d95f3523fe --- /dev/null +++ b/vendor/k8s.io/component-base/logs/BUILD @@ -0,0 +1,41 @@ +package(default_visibility = ["//visibility:public"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", +) + +go_library( + name = "go_default_library", + srcs = [ + "logs.go", + "options.go", + "registry.go", + ], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/logs", + importpath = "k8s.io/component-base/logs", + deps = [ + "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", + "//staging/src/k8s.io/component-base/logs/json:go_default_library", + "//vendor/github.com/go-logr/logr:go_default_library", + "//vendor/github.com/spf13/pflag:go_default_library", + "//vendor/k8s.io/klog/v2:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//staging/src/k8s.io/component-base/logs/json:all-srcs", + "//staging/src/k8s.io/component-base/logs/logreduction:all-srcs", + ], + tags = ["automanaged"], +) diff --git a/vendor/k8s.io/component-base/logs/json/BUILD b/vendor/k8s.io/component-base/logs/json/BUILD new file mode 100644 index 000000000000..3fb7831c8779 --- /dev/null +++ b/vendor/k8s.io/component-base/logs/json/BUILD @@ -0,0 +1,43 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["json.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/logs/json", + importpath = "k8s.io/component-base/logs/json", + visibility = ["//visibility:public"], + deps = [ + "//vendor/github.com/go-logr/logr:go_default_library", + "//vendor/go.uber.org/zap:go_default_library", + "//vendor/go.uber.org/zap/zapcore:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = [ + "json_benchmark_test.go", + "json_test.go", + ], + embed = [":go_default_library"], + deps = [ + "//vendor/github.com/stretchr/testify/assert:go_default_library", + "//vendor/go.uber.org/zap:go_default_library", + "//vendor/go.uber.org/zap/zapcore:go_default_library", + "//vendor/k8s.io/klog/v2:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/k8s.io/component-base/logs/logreduction/BUILD b/vendor/k8s.io/component-base/logs/logreduction/BUILD new file mode 100644 index 000000000000..d0fa90d14f18 --- /dev/null +++ b/vendor/k8s.io/component-base/logs/logreduction/BUILD @@ -0,0 +1,29 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["logreduction.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/logs/logreduction", + importpath = "k8s.io/component-base/logs/logreduction", + visibility = ["//visibility:public"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) + +go_test( + name = "go_default_test", + srcs = ["logreduction_test.go"], + embed = [":go_default_library"], +) diff --git a/vendor/k8s.io/component-base/logs/registry.go b/vendor/k8s.io/component-base/logs/registry.go index 515bba280119..c71899db66d7 100644 --- a/vendor/k8s.io/component-base/logs/registry.go +++ b/vendor/k8s.io/component-base/logs/registry.go @@ -18,6 +18,7 @@ package logs import ( "fmt" + "sort" "github.com/go-logr/logr" json "k8s.io/component-base/logs/json" @@ -84,12 +85,13 @@ func (lfr *LogFormatRegistry) Delete(name string) error { return nil } -// List names of registered log formats +// List names of registered log formats (sorted) func (lfr *LogFormatRegistry) List() []string { formats := make([]string, 0, len(lfr.registry)) for f := range lfr.registry { formats = append(formats, f) } + sort.Strings(formats) return formats } diff --git a/vendor/k8s.io/component-base/metrics/BUILD b/vendor/k8s.io/component-base/metrics/BUILD new file mode 100644 index 000000000000..b75763c4c1bd --- /dev/null +++ b/vendor/k8s.io/component-base/metrics/BUILD @@ -0,0 +1,101 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "collector.go", + "counter.go", + "desc.go", + "gauge.go", + "histogram.go", + "http.go", + "labels.go", + "metric.go", + "options.go", + "opts.go", + "processstarttime.go", + "registry.go", + "summary.go", + "value.go", + "version.go", + "version_parser.go", + "wrappers.go", + ], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/metrics", + importpath = "k8s.io/component-base/metrics", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/apimachinery/pkg/version:go_default_library", + "//staging/src/k8s.io/component-base/version:go_default_library", + "//vendor/github.com/blang/semver:go_default_library", + "//vendor/github.com/prometheus/client_golang/prometheus:go_default_library", + "//vendor/github.com/prometheus/client_golang/prometheus/promhttp:go_default_library", + "//vendor/github.com/prometheus/client_model/go:go_default_library", + "//vendor/github.com/prometheus/procfs:go_default_library", + "//vendor/github.com/spf13/pflag:go_default_library", + "//vendor/k8s.io/klog/v2:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = [ + "collector_test.go", + "counter_test.go", + "desc_test.go", + "gauge_test.go", + "histogram_test.go", + "http_test.go", + "opts_test.go", + "registry_test.go", + "summary_test.go", + "version_parser_test.go", + ], + embed = [":go_default_library"], + deps = [ + "//staging/src/k8s.io/apimachinery/pkg/version:go_default_library", + "//vendor/github.com/blang/semver:go_default_library", + "//vendor/github.com/prometheus/client_golang/prometheus:go_default_library", + "//vendor/github.com/prometheus/client_golang/prometheus/testutil:go_default_library", + "//vendor/github.com/prometheus/common/expfmt:go_default_library", + "//vendor/github.com/stretchr/testify/assert:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//staging/src/k8s.io/component-base/metrics/legacyregistry:all-srcs", + "//staging/src/k8s.io/component-base/metrics/prometheus/clientgo:all-srcs", + "//staging/src/k8s.io/component-base/metrics/prometheus/ratelimiter:all-srcs", + "//staging/src/k8s.io/component-base/metrics/prometheus/restclient:all-srcs", + "//staging/src/k8s.io/component-base/metrics/prometheus/version:all-srcs", + "//staging/src/k8s.io/component-base/metrics/prometheus/workqueue:all-srcs", + "//staging/src/k8s.io/component-base/metrics/testutil:all-srcs", + ], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) + +# Packages allowed to import github.com/prometheus +package_group( + name = "prometheus_import_allow_list", + packages = [ + "//cluster/images/etcd-version-monitor", + "//pkg/scheduler/framework/v1alpha1", + "//pkg/volume/util/operationexecutor", + "//staging/src/k8s.io/apiserver/pkg/util/flowcontrol/metrics", + "//staging/src/k8s.io/component-base/metrics/...", + "//test/e2e_node", + "//test/integration/apiserver/flowcontrol", + "//vendor/...", + ], +) diff --git a/vendor/k8s.io/component-base/metrics/legacyregistry/BUILD b/vendor/k8s.io/component-base/metrics/legacyregistry/BUILD new file mode 100644 index 000000000000..f2e32beac574 --- /dev/null +++ b/vendor/k8s.io/component-base/metrics/legacyregistry/BUILD @@ -0,0 +1,28 @@ +package(default_visibility = ["//visibility:public"]) + +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["registry.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/metrics/legacyregistry", + importpath = "k8s.io/component-base/metrics/legacyregistry", + deps = [ + "//staging/src/k8s.io/component-base/metrics:go_default_library", + "//vendor/github.com/prometheus/client_golang/prometheus:go_default_library", + "//vendor/github.com/prometheus/client_golang/prometheus/promhttp:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/vendor/k8s.io/component-base/metrics/prometheus/ratelimiter/BUILD b/vendor/k8s.io/component-base/metrics/prometheus/ratelimiter/BUILD new file mode 100644 index 000000000000..c6b8c1647678 --- /dev/null +++ b/vendor/k8s.io/component-base/metrics/prometheus/ratelimiter/BUILD @@ -0,0 +1,35 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["rate_limiter.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/metrics/prometheus/ratelimiter", + importpath = "k8s.io/component-base/metrics/prometheus/ratelimiter", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library", + "//staging/src/k8s.io/component-base/metrics:go_default_library", + "//staging/src/k8s.io/component-base/metrics/legacyregistry:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["rate_limiter_test.go"], + embed = [":go_default_library"], + deps = ["//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/k8s.io/component-base/metrics/prometheus/workqueue/BUILD b/vendor/k8s.io/component-base/metrics/prometheus/workqueue/BUILD new file mode 100644 index 000000000000..3b46b1f8c577 --- /dev/null +++ b/vendor/k8s.io/component-base/metrics/prometheus/workqueue/BUILD @@ -0,0 +1,28 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["metrics.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/metrics/prometheus/workqueue", + importpath = "k8s.io/component-base/metrics/prometheus/workqueue", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/client-go/util/workqueue:go_default_library", + "//staging/src/k8s.io/component-base/metrics:go_default_library", + "//staging/src/k8s.io/component-base/metrics/legacyregistry:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/k8s.io/component-base/metrics/testutil/BUILD b/vendor/k8s.io/component-base/metrics/testutil/BUILD new file mode 100644 index 000000000000..9d7adc8cc48c --- /dev/null +++ b/vendor/k8s.io/component-base/metrics/testutil/BUILD @@ -0,0 +1,51 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "metrics.go", + "promlint.go", + "testutil.go", + ], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/metrics/testutil", + importpath = "k8s.io/component-base/metrics/testutil", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/apimachinery/pkg/version:go_default_library", + "//staging/src/k8s.io/component-base/metrics:go_default_library", + "//vendor/github.com/prometheus/client_golang/prometheus/testutil:go_default_library", + "//vendor/github.com/prometheus/client_golang/prometheus/testutil/promlint:go_default_library", + "//vendor/github.com/prometheus/client_model/go:go_default_library", + "//vendor/github.com/prometheus/common/expfmt:go_default_library", + "//vendor/github.com/prometheus/common/model:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) + +go_test( + name = "go_default_test", + srcs = [ + "metrics_test.go", + "promlint_test.go", + "testutil_test.go", + ], + embed = [":go_default_library"], + deps = [ + "//staging/src/k8s.io/component-base/metrics:go_default_library", + "//vendor/github.com/prometheus/client_model/go:go_default_library", + "//vendor/k8s.io/utils/pointer:go_default_library", + ], +) diff --git a/vendor/k8s.io/component-base/term/BUILD b/vendor/k8s.io/component-base/term/BUILD new file mode 100644 index 000000000000..f282ec811767 --- /dev/null +++ b/vendor/k8s.io/component-base/term/BUILD @@ -0,0 +1,24 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["term.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/term", + importpath = "k8s.io/component-base/term", + visibility = ["//visibility:public"], + deps = ["//vendor/github.com/moby/term:go_default_library"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/k8s.io/component-base/version/BUILD b/vendor/k8s.io/component-base/version/BUILD new file mode 100644 index 000000000000..a8a3fc75cd56 --- /dev/null +++ b/vendor/k8s.io/component-base/version/BUILD @@ -0,0 +1,30 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "base.go", + "version.go", + ], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/version", + importpath = "k8s.io/component-base/version", + visibility = ["//visibility:public"], + deps = ["//staging/src/k8s.io/apimachinery/pkg/version:go_default_library"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//staging/src/k8s.io/component-base/version/verflag:all-srcs", + ], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/k8s.io/component-base/version/verflag/BUILD b/vendor/k8s.io/component-base/version/verflag/BUILD new file mode 100644 index 000000000000..ca3c2b0f5ff8 --- /dev/null +++ b/vendor/k8s.io/component-base/version/verflag/BUILD @@ -0,0 +1,31 @@ +package(default_visibility = ["//visibility:public"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", +) +load("//staging/src/k8s.io/component-base/version:def.bzl", "version_x_defs") + +go_library( + name = "go_default_library", + srcs = ["verflag.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/component-base/version/verflag", + importpath = "k8s.io/component-base/version/verflag", + deps = [ + "//staging/src/k8s.io/component-base/version:go_default_library", + "//vendor/github.com/spf13/pflag:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/vendor/k8s.io/kube-aggregator/pkg/controllers/status/BUILD b/vendor/k8s.io/kube-aggregator/pkg/controllers/status/BUILD index 443aee80b157..6a3197382f09 100644 --- a/vendor/k8s.io/kube-aggregator/pkg/controllers/status/BUILD +++ b/vendor/k8s.io/kube-aggregator/pkg/controllers/status/BUILD @@ -41,7 +41,10 @@ go_library( go_test( name = "go_default_test", - srcs = ["available_controller_test.go"], + srcs = [ + "available_controller_test.go", + "metrics_test.go", + ], embed = [":go_default_library"], deps = [ "//staging/src/k8s.io/api/core/v1:go_default_library", @@ -50,6 +53,7 @@ go_test( "//staging/src/k8s.io/client-go/testing:go_default_library", "//staging/src/k8s.io/client-go/tools/cache:go_default_library", "//staging/src/k8s.io/client-go/util/workqueue:go_default_library", + "//staging/src/k8s.io/component-base/metrics/testutil:go_default_library", "//staging/src/k8s.io/kube-aggregator/pkg/apis/apiregistration/v1:go_default_library", "//staging/src/k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/fake:go_default_library", "//staging/src/k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/typed/apiregistration/v1:go_default_library", diff --git a/vendor/k8s.io/kube-aggregator/pkg/controllers/status/available_controller.go b/vendor/k8s.io/kube-aggregator/pkg/controllers/status/available_controller.go index 7cf38ced4c20..1af147ca46bf 100644 --- a/vendor/k8s.io/kube-aggregator/pkg/controllers/status/available_controller.go +++ b/vendor/k8s.io/kube-aggregator/pkg/controllers/status/available_controller.go @@ -43,6 +43,7 @@ import ( "k8s.io/client-go/tools/cache" "k8s.io/client-go/transport" "k8s.io/client-go/util/workqueue" + "k8s.io/component-base/metrics/legacyregistry" "k8s.io/klog/v2" apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" apiregistrationv1apihelper "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1/helper" @@ -52,6 +53,9 @@ import ( "k8s.io/kube-aggregator/pkg/controllers" ) +// making sure we only register metrics once into legacy registry +var registerIntoLegacyRegistryOnce sync.Once + type certKeyFunc func() ([]byte, []byte) // ServiceResolver knows how to convert a service reference into an actual location. @@ -86,6 +90,56 @@ type AvailableConditionController struct { cache map[string]map[string][]string // this lock protects operations on the above cache cacheLock sync.RWMutex + + // TLS config with customized dialer cannot be cached by the client-go + // tlsTransportCache. Use a local cache here to reduce the chance of + // the controller spamming idle connections with short-lived transports. + // NOTE: the cache works because we assume that the transports constructed + // by the controller only vary on the dynamic cert/key. + tlsCache *tlsTransportCache + + // metrics registered into legacy registry + metrics *availabilityMetrics +} + +type tlsTransportCache struct { + mu sync.Mutex + transports map[tlsCacheKey]http.RoundTripper +} + +func (c *tlsTransportCache) get(config *rest.Config) (http.RoundTripper, error) { + // If the available controller doesn't customzie the dialer (and we know from + // the code that the controller doesn't customzie other functions i.e. Proxy + // and GetCert (ExecProvider)), the config is cacheable by the client-go TLS + // transport cache. Let's skip the local cache and depend on the client-go cache. + if config.Dial == nil { + return rest.TransportFor(config) + } + c.mu.Lock() + defer c.mu.Unlock() + // See if we already have a custom transport for this config + key := tlsConfigKey(config) + if t, ok := c.transports[key]; ok { + return t, nil + } + restTransport, err := rest.TransportFor(config) + if err != nil { + return nil, err + } + c.transports[key] = restTransport + return restTransport, nil +} + +type tlsCacheKey struct { + certData string + keyData string +} + +func tlsConfigKey(c *rest.Config) tlsCacheKey { + return tlsCacheKey{ + certData: string(c.TLSClientConfig.CertData), + keyData: string(c.TLSClientConfig.KeyData), + } } // NewAvailableConditionController returns a new AvailableConditionController. @@ -115,6 +169,8 @@ func NewAvailableConditionController( workqueue.NewItemExponentialFailureRateLimiter(5*time.Millisecond, 30*time.Second), "AvailableConditionController"), proxyCurrentCertKeyContent: proxyCurrentCertKeyContent, + tlsCache: &tlsTransportCache{transports: make(map[tlsCacheKey]http.RoundTripper)}, + metrics: newAvailabilityMetrics(), } if egressSelector != nil { @@ -155,12 +211,22 @@ func NewAvailableConditionController( c.syncFn = c.sync + // TODO: decouple from legacyregistry + var err error + registerIntoLegacyRegistryOnce.Do(func() { + err = c.metrics.Register(legacyregistry.Register, legacyregistry.CustomRegister) + }) + if err != nil { + return nil, err + } + return c, nil } func (c *AvailableConditionController) sync(key string) error { originalAPIService, err := c.apiServiceLister.Get(key) if apierrors.IsNotFound(err) { + c.metrics.ForgetAPIService(key) return nil } if err != nil { @@ -185,7 +251,12 @@ func (c *AvailableConditionController) sync(key string) error { if c.dialContext != nil { restConfig.Dial = c.dialContext } - restTransport, err := rest.TransportFor(restConfig) + // TLS config with customized dialer cannot be cached by the client-go + // tlsTransportCache. Use a local cache here to reduce the chance of + // the controller spamming idle connections with short-lived transports. + // NOTE: the cache works because we assume that the transports constructed + // by the controller only vary on the dynamic cert/key. + restTransport, err := c.tlsCache.get(restConfig) if err != nil { return err } @@ -206,7 +277,7 @@ func (c *AvailableConditionController) sync(key string) error { // local API services are always considered available if apiService.Spec.Service == nil { apiregistrationv1apihelper.SetAPIServiceCondition(apiService, apiregistrationv1apihelper.NewLocalAvailableAPIServiceCondition()) - _, err := updateAPIServiceStatus(c.apiServiceClient, originalAPIService, apiService) + _, err := c.updateAPIServiceStatus(originalAPIService, apiService) return err } @@ -216,14 +287,14 @@ func (c *AvailableConditionController) sync(key string) error { availableCondition.Reason = "ServiceNotFound" availableCondition.Message = fmt.Sprintf("service/%s in %q is not present", apiService.Spec.Service.Name, apiService.Spec.Service.Namespace) apiregistrationv1apihelper.SetAPIServiceCondition(apiService, availableCondition) - _, err := updateAPIServiceStatus(c.apiServiceClient, originalAPIService, apiService) + _, err := c.updateAPIServiceStatus(originalAPIService, apiService) return err } else if err != nil { availableCondition.Status = apiregistrationv1.ConditionUnknown availableCondition.Reason = "ServiceAccessError" availableCondition.Message = fmt.Sprintf("service/%s in %q cannot be checked due to: %v", apiService.Spec.Service.Name, apiService.Spec.Service.Namespace, err) apiregistrationv1apihelper.SetAPIServiceCondition(apiService, availableCondition) - _, err := updateAPIServiceStatus(c.apiServiceClient, originalAPIService, apiService) + _, err := c.updateAPIServiceStatus(originalAPIService, apiService) return err } @@ -244,7 +315,7 @@ func (c *AvailableConditionController) sync(key string) error { availableCondition.Reason = "ServicePortError" availableCondition.Message = fmt.Sprintf("service/%s in %q is not listening on port %d", apiService.Spec.Service.Name, apiService.Spec.Service.Namespace, *apiService.Spec.Service.Port) apiregistrationv1apihelper.SetAPIServiceCondition(apiService, availableCondition) - _, err := updateAPIServiceStatus(c.apiServiceClient, originalAPIService, apiService) + _, err := c.updateAPIServiceStatus(originalAPIService, apiService) return err } @@ -254,14 +325,14 @@ func (c *AvailableConditionController) sync(key string) error { availableCondition.Reason = "EndpointsNotFound" availableCondition.Message = fmt.Sprintf("cannot find endpoints for service/%s in %q", apiService.Spec.Service.Name, apiService.Spec.Service.Namespace) apiregistrationv1apihelper.SetAPIServiceCondition(apiService, availableCondition) - _, err := updateAPIServiceStatus(c.apiServiceClient, originalAPIService, apiService) + _, err := c.updateAPIServiceStatus(originalAPIService, apiService) return err } else if err != nil { availableCondition.Status = apiregistrationv1.ConditionUnknown availableCondition.Reason = "EndpointsAccessError" availableCondition.Message = fmt.Sprintf("service/%s in %q cannot be checked due to: %v", apiService.Spec.Service.Name, apiService.Spec.Service.Namespace, err) apiregistrationv1apihelper.SetAPIServiceCondition(apiService, availableCondition) - _, err := updateAPIServiceStatus(c.apiServiceClient, originalAPIService, apiService) + _, err := c.updateAPIServiceStatus(originalAPIService, apiService) return err } hasActiveEndpoints := false @@ -282,7 +353,7 @@ func (c *AvailableConditionController) sync(key string) error { availableCondition.Reason = "MissingEndpoints" availableCondition.Message = fmt.Sprintf("endpoints for service/%s in %q have no addresses with port name %q", apiService.Spec.Service.Name, apiService.Spec.Service.Namespace, portName) apiregistrationv1apihelper.SetAPIServiceCondition(apiService, availableCondition) - _, err := updateAPIServiceStatus(c.apiServiceClient, originalAPIService, apiService) + _, err := c.updateAPIServiceStatus(originalAPIService, apiService) return err } } @@ -360,7 +431,7 @@ func (c *AvailableConditionController) sync(key string) error { availableCondition.Reason = "FailedDiscoveryCheck" availableCondition.Message = lastError.Error() apiregistrationv1apihelper.SetAPIServiceCondition(apiService, availableCondition) - _, updateErr := updateAPIServiceStatus(c.apiServiceClient, originalAPIService, apiService) + _, updateErr := c.updateAPIServiceStatus(originalAPIService, apiService) if updateErr != nil { return updateErr } @@ -373,26 +444,26 @@ func (c *AvailableConditionController) sync(key string) error { availableCondition.Reason = "Passed" availableCondition.Message = "all checks passed" apiregistrationv1apihelper.SetAPIServiceCondition(apiService, availableCondition) - _, err = updateAPIServiceStatus(c.apiServiceClient, originalAPIService, apiService) + _, err = c.updateAPIServiceStatus(originalAPIService, apiService) return err } // updateAPIServiceStatus only issues an update if a change is detected. We have a tight resync loop to quickly detect dead // apiservices. Doing that means we don't want to quickly issue no-op updates. -func updateAPIServiceStatus(client apiregistrationclient.APIServicesGetter, originalAPIService, newAPIService *apiregistrationv1.APIService) (*apiregistrationv1.APIService, error) { +func (c *AvailableConditionController) updateAPIServiceStatus(originalAPIService, newAPIService *apiregistrationv1.APIService) (*apiregistrationv1.APIService, error) { // update this metric on every sync operation to reflect the actual state - setUnavailableGauge(newAPIService) + c.setUnavailableGauge(newAPIService) if equality.Semantic.DeepEqual(originalAPIService.Status, newAPIService.Status) { return newAPIService, nil } - newAPIService, err := client.APIServices().UpdateStatus(context.TODO(), newAPIService, metav1.UpdateOptions{}) + newAPIService, err := c.apiServiceClient.APIServices().UpdateStatus(context.TODO(), newAPIService, metav1.UpdateOptions{}) if err != nil { return nil, err } - setUnavailableCounter(originalAPIService, newAPIService) + c.setUnavailableCounter(originalAPIService, newAPIService) return newAPIService, nil } @@ -577,17 +648,17 @@ func (c *AvailableConditionController) deleteEndpoints(obj interface{}) { } // setUnavailableGauge set the metrics so that it reflect the current state base on availability of the given service -func setUnavailableGauge(newAPIService *apiregistrationv1.APIService) { +func (c *AvailableConditionController) setUnavailableGauge(newAPIService *apiregistrationv1.APIService) { if apiregistrationv1apihelper.IsAPIServiceConditionTrue(newAPIService, apiregistrationv1.Available) { - unavailableGauge.WithLabelValues(newAPIService.Name).Set(0.0) + c.metrics.SetAPIServiceAvailable(newAPIService.Name) return } - unavailableGauge.WithLabelValues(newAPIService.Name).Set(1.0) + c.metrics.SetAPIServiceUnavailable(newAPIService.Name) } // setUnavailableCounter increases the metrics only if the given service is unavailable and its APIServiceCondition has changed -func setUnavailableCounter(originalAPIService, newAPIService *apiregistrationv1.APIService) { +func (c *AvailableConditionController) setUnavailableCounter(originalAPIService, newAPIService *apiregistrationv1.APIService) { wasAvailable := apiregistrationv1apihelper.IsAPIServiceConditionTrue(originalAPIService, apiregistrationv1.Available) isAvailable := apiregistrationv1apihelper.IsAPIServiceConditionTrue(newAPIService, apiregistrationv1.Available) statusChanged := isAvailable != wasAvailable @@ -597,6 +668,6 @@ func setUnavailableCounter(originalAPIService, newAPIService *apiregistrationv1. if newCondition := apiregistrationv1apihelper.GetAPIServiceConditionByType(newAPIService, apiregistrationv1.Available); newCondition != nil { reason = newCondition.Reason } - unavailableCounter.WithLabelValues(newAPIService.Name, reason).Inc() + c.metrics.UnavailableCounter(newAPIService.Name, reason).Inc() } } diff --git a/vendor/k8s.io/kube-aggregator/pkg/controllers/status/metrics.go b/vendor/k8s.io/kube-aggregator/pkg/controllers/status/metrics.go index 3a601a9ad9d0..524a8edb9aa9 100644 --- a/vendor/k8s.io/kube-aggregator/pkg/controllers/status/metrics.go +++ b/vendor/k8s.io/kube-aggregator/pkg/controllers/status/metrics.go @@ -17,8 +17,9 @@ limitations under the License. package apiserver import ( + "sync" + "k8s.io/component-base/metrics" - "k8s.io/component-base/metrics/legacyregistry" ) /* @@ -30,25 +31,120 @@ import ( * the metric stability policy. */ var ( - unavailableCounter = metrics.NewCounterVec( - &metrics.CounterOpts{ - Name: "aggregator_unavailable_apiservice_total", - Help: "Counter of APIServices which are marked as unavailable broken down by APIService name and reason.", - StabilityLevel: metrics.ALPHA, - }, - []string{"name", "reason"}, - ) - unavailableGauge = metrics.NewGaugeVec( - &metrics.GaugeOpts{ - Name: "aggregator_unavailable_apiservice", - Help: "Gauge of APIServices which are marked as unavailable broken down by APIService name.", - StabilityLevel: metrics.ALPHA, - }, + unavailableGaugeDesc = metrics.NewDesc( + "aggregator_unavailable_apiservice", + "Gauge of APIServices which are marked as unavailable broken down by APIService name.", []string{"name"}, + nil, + metrics.ALPHA, + "", ) ) -func init() { - legacyregistry.MustRegister(unavailableCounter) - legacyregistry.MustRegister(unavailableGauge) +type availabilityMetrics struct { + unavailableCounter *metrics.CounterVec + + *availabilityCollector +} + +func newAvailabilityMetrics() *availabilityMetrics { + return &availabilityMetrics{ + unavailableCounter: metrics.NewCounterVec( + &metrics.CounterOpts{ + Name: "aggregator_unavailable_apiservice_total", + Help: "Counter of APIServices which are marked as unavailable broken down by APIService name and reason.", + StabilityLevel: metrics.ALPHA, + }, + []string{"name", "reason"}, + ), + availabilityCollector: newAvailabilityCollector(), + } +} + +// Register registers apiservice availability metrics. +func (m *availabilityMetrics) Register( + registrationFunc func(metrics.Registerable) error, + customRegistrationFunc func(metrics.StableCollector) error, +) error { + err := registrationFunc(m.unavailableCounter) + if err != nil { + return err + } + + err = customRegistrationFunc(m.availabilityCollector) + if err != nil { + return err + } + + return nil +} + +// UnavailableCounter returns a counter to track apiservices marked as unavailable. +func (m *availabilityMetrics) UnavailableCounter(apiServiceName, reason string) metrics.CounterMetric { + return m.unavailableCounter.WithLabelValues(apiServiceName, reason) +} + +type availabilityCollector struct { + metrics.BaseStableCollector + + mtx sync.RWMutex + availabilities map[string]bool +} + +// Check if apiServiceStatusCollector implements necessary interface. +var _ metrics.StableCollector = &availabilityCollector{} + +func newAvailabilityCollector() *availabilityCollector { + return &availabilityCollector{ + availabilities: make(map[string]bool), + } +} + +// DescribeWithStability implements the metrics.StableCollector interface. +func (c *availabilityCollector) DescribeWithStability(ch chan<- *metrics.Desc) { + ch <- unavailableGaugeDesc +} + +// CollectWithStability implements the metrics.StableCollector interface. +func (c *availabilityCollector) CollectWithStability(ch chan<- metrics.Metric) { + c.mtx.RLock() + defer c.mtx.RUnlock() + + for apiServiceName, isAvailable := range c.availabilities { + gaugeValue := 1.0 + if isAvailable { + gaugeValue = 0.0 + } + ch <- metrics.NewLazyConstMetric( + unavailableGaugeDesc, + metrics.GaugeValue, + gaugeValue, + apiServiceName, + ) + } +} + +// SetAPIServiceAvailable sets the given apiservice availability gauge to available. +func (c *availabilityCollector) SetAPIServiceAvailable(apiServiceKey string) { + c.setAPIServiceAvailability(apiServiceKey, true) +} + +// SetAPIServiceUnavailable sets the given apiservice availability gauge to unavailable. +func (c *availabilityCollector) SetAPIServiceUnavailable(apiServiceKey string) { + c.setAPIServiceAvailability(apiServiceKey, false) +} + +func (c *availabilityCollector) setAPIServiceAvailability(apiServiceKey string, availability bool) { + c.mtx.Lock() + defer c.mtx.Unlock() + + c.availabilities[apiServiceKey] = availability +} + +// ForgetAPIService removes the availability gauge of the given apiservice. +func (c *availabilityCollector) ForgetAPIService(apiServiceKey string) { + c.mtx.Lock() + defer c.mtx.Unlock() + + delete(c.availabilities, apiServiceKey) } diff --git a/vendor/k8s.io/kubernetes/cmd/kube-apiserver/app/server.go b/vendor/k8s.io/kubernetes/cmd/kube-apiserver/app/server.go index caa93db294e6..b7589a75b9b0 100644 --- a/vendor/k8s.io/kubernetes/cmd/kube-apiserver/app/server.go +++ b/vendor/k8s.io/kubernetes/cmd/kube-apiserver/app/server.go @@ -738,8 +738,17 @@ func Complete(s *options.ServerRunOptions) (completedServerRunOptions, error) { } if s.Etcd.EnableWatchCache { + sizes := kubeapiserver.DefaultWatchCacheSizes() // Ensure that overrides parse correctly. - if _, err := serveroptions.ParseWatchCacheSizes(s.Etcd.WatchCacheSizes); err != nil { + userSpecified, err := serveroptions.ParseWatchCacheSizes(s.Etcd.WatchCacheSizes) + if err != nil { + return options, err + } + for resource, size := range userSpecified { + sizes[resource] = size + } + s.Etcd.WatchCacheSizes, err = serveroptions.WriteWatchCacheSizes(sizes) + if err != nil { return options, err } } @@ -831,7 +840,7 @@ type eventRegistrySink struct { var _ genericapiserver.EventSink = eventRegistrySink{} func (s eventRegistrySink) Create(v1event *corev1.Event) (*corev1.Event, error) { - ctx := request.WithNamespace(request.NewContext(), v1event.Namespace) + ctx := request.WithNamespace(request.WithRequestInfo(request.NewContext(), &request.RequestInfo{APIVersion: "v1"}), v1event.Namespace) var event core.Event if err := v1.Convert_v1_Event_To_core_Event(v1event, &event, nil); err != nil { diff --git a/vendor/k8s.io/kubernetes/openshift-hack/e2e/annotate/rules.go b/vendor/k8s.io/kubernetes/openshift-hack/e2e/annotate/rules.go index c5487ad59a36..0e14585c5f40 100644 --- a/vendor/k8s.io/kubernetes/openshift-hack/e2e/annotate/rules.go +++ b/vendor/k8s.io/kubernetes/openshift-hack/e2e/annotate/rules.go @@ -89,6 +89,10 @@ var ( // A fix is in progress: https://github.com/openshift/origin/pull/24709 `Multi-AZ Clusters should spread the pods of a replication controller across zones`, + + // NFS umount is broken in kernels 5.7+ + // https://bugzilla.redhat.com/show_bug.cgi?id=1854379 + `\[sig-storage\].*\[Driver: nfs\] \[Testpattern: Dynamic PV \(default fs\)\].*subPath should be able to unmount after the subpath directory is deleted`, }, // tests that may work, but we don't support them "[Disabled:Unsupported]": { diff --git a/vendor/k8s.io/kubernetes/pkg/credentialprovider/config.go b/vendor/k8s.io/kubernetes/pkg/credentialprovider/config.go index 42c184589ee7..b9edb4c39e83 100644 --- a/vendor/k8s.io/kubernetes/pkg/credentialprovider/config.go +++ b/vendor/k8s.io/kubernetes/pkg/credentialprovider/config.go @@ -117,10 +117,14 @@ func ReadDockercfgFile(searchPaths []string) (cfg DockerConfig, err error) { continue } cfg, err := readDockerConfigFileFromBytes(contents) - if err == nil { - klog.V(4).Infof("found .dockercfg at %s", absDockerConfigFileLocation) - return cfg, nil + if err != nil { + klog.V(4).Infof("couldn't get the config from %q contents: %v", absDockerConfigFileLocation, err) + continue } + + klog.V(4).Infof("found .dockercfg at %s", absDockerConfigFileLocation) + return cfg, nil + } return nil, fmt.Errorf("couldn't find valid .dockercfg after checking in %v", searchPaths) } @@ -230,8 +234,7 @@ func ReadDockerConfigFileFromURL(url string, client *http.Client, header *http.H func readDockerConfigFileFromBytes(contents []byte) (cfg DockerConfig, err error) { if err = json.Unmarshal(contents, &cfg); err != nil { - klog.Errorf("while trying to parse blob %q: %v", contents, err) - return nil, err + return nil, errors.New("error occurred while trying to unmarshal json") } return } @@ -239,8 +242,7 @@ func readDockerConfigFileFromBytes(contents []byte) (cfg DockerConfig, err error func readDockerConfigJSONFileFromBytes(contents []byte) (cfg DockerConfig, err error) { var cfgJSON DockerConfigJSON if err = json.Unmarshal(contents, &cfgJSON); err != nil { - klog.Errorf("while trying to parse blob %q: %v", contents, err) - return nil, err + return nil, errors.New("error occurred while trying to unmarshal json") } cfg = cfgJSON.Auths return diff --git a/vendor/k8s.io/kubernetes/pkg/kubeapiserver/default_storage_factory_builder.go b/vendor/k8s.io/kubernetes/pkg/kubeapiserver/default_storage_factory_builder.go index eaf38a5fe38d..03e7437474c6 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubeapiserver/default_storage_factory_builder.go +++ b/vendor/k8s.io/kubernetes/pkg/kubeapiserver/default_storage_factory_builder.go @@ -49,6 +49,15 @@ var SpecialDefaultResourcePrefixes = map[schema.GroupResource]string{ {Group: "policy", Resource: "podsecuritypolicies"}: "podsecuritypolicy", } +// DefaultWatchCacheSizes defines default resources for which watchcache +// should be disabled. +func DefaultWatchCacheSizes() map[schema.GroupResource]int { + return map[schema.GroupResource]int{ + {Resource: "events"}: 0, + {Group: "events.k8s.io", Resource: "events"}: 0, + } +} + // NewStorageFactoryConfig returns a new StorageFactoryConfig set up with necessary resource overrides. func NewStorageFactoryConfig() *StorageFactoryConfig { diff --git a/vendor/k8s.io/kubernetes/pkg/kubeapiserver/server/insecure_handler.go b/vendor/k8s.io/kubernetes/pkg/kubeapiserver/server/insecure_handler.go index 5b7ec2c45f49..b15744ae0dc9 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubeapiserver/server/insecure_handler.go +++ b/vendor/k8s.io/kubernetes/pkg/kubeapiserver/server/insecure_handler.go @@ -26,6 +26,7 @@ import ( // BuildInsecureHandlerChain sets up the server to listen to http. Should be removed. func BuildInsecureHandlerChain(apiHandler http.Handler, c *server.Config) http.Handler { + requestInfoResolver := server.NewRequestInfoResolver(c) handler := apiHandler // Temporarily disable APIPriorityAndFairness during development // so that /debug/pprof works even while this feature is totally @@ -40,10 +41,10 @@ func BuildInsecureHandlerChain(apiHandler http.Handler, c *server.Config) http.H handler = genericfilters.WithCORS(handler, c.CorsAllowedOriginList, nil, nil, nil, "true") handler = genericfilters.WithTimeoutForNonLongRunningRequests(handler, c.LongRunningFunc, c.RequestTimeout) handler = genericfilters.WithWaitGroup(handler, c.LongRunningFunc, c.HandlerChainWaitGroup) - handler = genericapifilters.WithRequestInfo(handler, server.NewRequestInfoResolver(c)) + handler = genericapifilters.WithRequestInfo(handler, requestInfoResolver) handler = genericapifilters.WithWarningRecorder(handler) handler = genericapifilters.WithCacheControl(handler) - handler = genericfilters.WithPanicRecovery(handler, nil) + handler = genericfilters.WithPanicRecovery(handler, nil, requestInfoResolver) return handler } diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/BUILD b/vendor/k8s.io/kubernetes/pkg/kubelet/BUILD index 7efbf4a69274..928a9707902b 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/BUILD +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/BUILD @@ -23,6 +23,10 @@ go_library( "kubelet_node_status_windows.go", "kubelet_pods.go", "kubelet_resources.go", + "kubelet_server_journal.go", + "kubelet_server_journal_linux.go", + "kubelet_server_journal_others.go", + "kubelet_server_journal_windows.go", "kubelet_volumes.go", "pod_container_deletor.go", "pod_workers.go", @@ -173,6 +177,7 @@ go_test( "kubelet_pods_test.go", "kubelet_pods_windows_test.go", "kubelet_resources_test.go", + "kubelet_server_journal_test.go", "kubelet_test.go", "kubelet_volumes_linux_test.go", "kubelet_volumes_test.go", diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/DOWNSTREAM_OWNERS b/vendor/k8s.io/kubernetes/pkg/kubelet/DOWNSTREAM_OWNERS new file mode 100644 index 000000000000..7497e0cba964 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/DOWNSTREAM_OWNERS @@ -0,0 +1,16 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +reviewers: + - rphillips + - sjenning + - mrunalp + +# adding mrunalp and sjenning from the upstream Kubelet OWNERS file: +# https://github.com/kubernetes/kubernetes/blob/17bb2fc050ec786b60db7d8d6d4d3ac8eeac205b/pkg/kubelet/OWNERS#L10-L11 +# sub-package approvers for "UPSTREAM: : ..." changes that merged upstream +# carry patches for "UPSTREAM: : ..." will be approved by the root level approvers +approvers: + - sjenning + - mrunalp + +component: node diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/docker_container.go b/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/docker_container.go index 01b865f9d2a3..3c61e13cf914 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/docker_container.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/docker_container.go @@ -83,6 +83,25 @@ func (ds *dockerService) ListContainers(_ context.Context, r *runtimeapi.ListCon return &runtimeapi.ListContainersResponse{Containers: result}, nil } +func (ds *dockerService) getContainerCleanupInfo(containerID string) (*containerCleanupInfo, bool) { + ds.cleanupInfosLock.RLock() + defer ds.cleanupInfosLock.RUnlock() + info, ok := ds.containerCleanupInfos[containerID] + return info, ok +} + +func (ds *dockerService) setContainerCleanupInfo(containerID string, info *containerCleanupInfo) { + ds.cleanupInfosLock.Lock() + defer ds.cleanupInfosLock.Unlock() + ds.containerCleanupInfos[containerID] = info +} + +func (ds *dockerService) clearContainerCleanupInfo(containerID string) { + ds.cleanupInfosLock.Lock() + defer ds.cleanupInfosLock.Unlock() + delete(ds.containerCleanupInfos, containerID) +} + // CreateContainer creates a new container in the given PodSandbox // Docker cannot store the log to an arbitrary location (yet), so we create an // symlink at LogPath, linking to the actual path of the log. @@ -185,7 +204,7 @@ func (ds *dockerService) CreateContainer(_ context.Context, r *runtimeapi.Create // we don't perform the clean up just yet at that could destroy information // needed for the container to start (e.g. Windows credentials stored in // registry keys); instead, we'll clean up when the container gets removed - ds.containerCleanupInfos[containerID] = cleanupInfo + ds.setContainerCleanupInfo(containerID, cleanupInfo) } return &runtimeapi.CreateContainerResponse{ContainerId: containerID}, nil } @@ -461,11 +480,11 @@ func (ds *dockerService) UpdateContainerResources(_ context.Context, r *runtimea } func (ds *dockerService) performPlatformSpecificContainerForContainer(containerID string) (errors []error) { - if cleanupInfo, present := ds.containerCleanupInfos[containerID]; present { + if cleanupInfo, present := ds.getContainerCleanupInfo(containerID); present { errors = ds.performPlatformSpecificContainerCleanupAndLogErrors(containerID, cleanupInfo) if len(errors) == 0 { - delete(ds.containerCleanupInfos, containerID) + ds.clearContainerCleanupInfo(containerID) } } diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/docker_service.go b/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/docker_service.go index d9665698cc3f..74a7b5d08127 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/docker_service.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/dockershim/docker_service.go @@ -31,7 +31,7 @@ import ( dockertypes "github.com/docker/docker/api/types" "k8s.io/klog/v2" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2" kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config" "k8s.io/kubernetes/pkg/kubelet/checkpointmanager" @@ -316,6 +316,7 @@ type dockerService struct { // (see `applyPlatformSpecificDockerConfig` and `performPlatformSpecificContainerCleanup` // methods for more info). containerCleanupInfos map[string]*containerCleanupInfo + cleanupInfosLock sync.RWMutex } // TODO: handle context. diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet.go b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet.go index 81f4d322ed8e..fb0023f9d609 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet.go @@ -1424,6 +1424,13 @@ func (kl *Kubelet) syncPod(o syncPodOptions) error { return nil } + // If the pod is a static pod and its mirror pod is still gracefully terminating, + // we do not want to start the new static pod until the old static pod is gracefully terminated. + podFullName := kubecontainer.GetPodFullName(pod) + if kl.podKiller.IsMirrorPodPendingTerminationByPodName(podFullName) { + return fmt.Errorf("pod %q is pending termination", podFullName) + } + // Latency measurements for the main workflow are relative to the // first time the pod was seen by the API server. var firstSeenTime time.Time @@ -1557,7 +1564,6 @@ func (kl *Kubelet) syncPod(o syncPodOptions) error { // Create Mirror Pod for Static Pod if it doesn't already exist if kubetypes.IsStaticPod(pod) { - podFullName := kubecontainer.GetPodFullName(pod) deleted := false if mirrorPod != nil { if mirrorPod.DeletionTimestamp != nil || !kl.podManager.IsMirrorPodOf(mirrorPod, pod) { @@ -1688,6 +1694,9 @@ func (kl *Kubelet) deletePod(pod *v1.Pod) error { } podPair := kubecontainer.PodPair{APIPod: pod, RunningPod: &runningPod} + if _, ok := kl.podManager.GetMirrorPodByPod(pod); ok { + kl.podKiller.MarkMirrorPodPendingTermination(pod) + } kl.podKiller.KillPod(&podPair) // TODO: delete the mirror pod here? @@ -2029,9 +2038,6 @@ func (kl *Kubelet) HandlePodRemoves(pods []*v1.Pod) { kl.handleMirrorPod(pod, start) continue } - if _, ok := kl.podManager.GetMirrorPodByPod(pod); ok { - kl.podKiller.MarkMirrorPodPendingTermination(pod) - } // Deletion is allowed to fail because the periodic cleanup routine // will trigger deletion again. if err := kl.deletePod(pod); err != nil { diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_pods.go b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_pods.go index 386f82d15919..40b709eb2412 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_pods.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_pods.go @@ -1605,7 +1605,7 @@ func (kl *Kubelet) convertStatusToAPIStatus(pod *v1.Pod, podStatus *kubecontaine // convertToAPIContainerStatuses converts the given internal container // statuses into API container statuses. func (kl *Kubelet) convertToAPIContainerStatuses(pod *v1.Pod, podStatus *kubecontainer.PodStatus, previousStatus []v1.ContainerStatus, containers []v1.Container, hasInitContainers, isInitContainer bool) []v1.ContainerStatus { - convertContainerStatus := func(cs *kubecontainer.Status) *v1.ContainerStatus { + convertContainerStatus := func(cs *kubecontainer.Status, oldStatus *v1.ContainerStatus) *v1.ContainerStatus { cid := cs.ID.String() status := &v1.ContainerStatus{ Name: cs.Name, @@ -1614,17 +1614,17 @@ func (kl *Kubelet) convertToAPIContainerStatuses(pod *v1.Pod, podStatus *kubecon ImageID: cs.ImageID, ContainerID: cid, } - switch cs.State { - case kubecontainer.ContainerStateRunning: + switch { + case cs.State == kubecontainer.ContainerStateRunning: status.State.Running = &v1.ContainerStateRunning{StartedAt: metav1.NewTime(cs.StartedAt)} - case kubecontainer.ContainerStateCreated: + case cs.State == kubecontainer.ContainerStateCreated: // Treat containers in the "created" state as if they are exited. // The pod workers are supposed start all containers it creates in // one sync (syncPod) iteration. There should not be any normal // "created" containers when the pod worker generates the status at // the beginning of a sync iteration. fallthrough - case kubecontainer.ContainerStateExited: + case cs.State == kubecontainer.ContainerStateExited: status.State.Terminated = &v1.ContainerStateTerminated{ ExitCode: int32(cs.ExitCode), Reason: cs.Reason, @@ -1633,7 +1633,31 @@ func (kl *Kubelet) convertToAPIContainerStatuses(pod *v1.Pod, podStatus *kubecon FinishedAt: metav1.NewTime(cs.FinishedAt), ContainerID: cid, } + + case cs.State == kubecontainer.ContainerStateUnknown && + oldStatus != nil && // we have an old status + oldStatus.State.Running != nil: // our previous status was running + // if this happens, then we know that this container was previously running and isn't anymore (assuming the CRI isn't failing to return running containers). + // you can imagine this happening in cases where a container failed and the kubelet didn't ask about it in time to see the result. + // in this case, the container should not to into waiting state immediately because that can make cases like runonce pods actually run + // twice. "container never ran" is different than "container ran and failed". This is handled differently in the kubelet + // and it is handled differently in higher order logic like crashloop detection and handling + status.State.Terminated = &v1.ContainerStateTerminated{ + Reason: "ContainerStatusUnknown", + Message: "The container could not be located when the pod was terminated", + ExitCode: 137, // this code indicates an error + } + // the restart count normally comes from the CRI (see near the top of this method), but since this is being added explicitly + // for the case where the CRI did not return a status, we need to manually increment the restart count to be accurate. + status.RestartCount = oldStatus.RestartCount + 1 + default: + // this collapses any unknown state to container waiting. If any container is waiting, then the pod status moves to pending even if it is running. + // if I'm reading this correctly, then any failure to read status on any container results in the entire pod going pending even if the containers + // are actually running. + // see https://github.com/kubernetes/kubernetes/blob/5d1b3e26af73dde33ecb6a3e69fb5876ceab192f/pkg/kubelet/kuberuntime/kuberuntime_container.go#L497 to + // https://github.com/kubernetes/kubernetes/blob/8976e3620f8963e72084971d9d4decbd026bf49f/pkg/kubelet/kuberuntime/helpers.go#L58-L71 + // and interpreted here https://github.com/kubernetes/kubernetes/blob/b27e78f590a0d43e4a23ca3b2bf1739ca4c6e109/pkg/kubelet/kubelet_pods.go#L1434-L1439 status.State.Waiting = &v1.ContainerStateWaiting{} } return status @@ -1673,6 +1697,70 @@ func (kl *Kubelet) convertToAPIContainerStatuses(pod *v1.Pod, podStatus *kubecon statuses[container.Name] = status } + for _, container := range containers { + found := false + for _, cStatus := range podStatus.ContainerStatuses { + if container.Name == cStatus.Name { + found = true + break + } + } + if found { + continue + } + // if no container is found, then assuming it should be waiting seems plausible, but the status code requires + // that a previous termination be present. If we're offline long enough (or something removed the container?), then + // the previous termination may not be present. This next code block ensures that if the container was previously running + // then when that container status disappears, we can infer that it terminated even if we don't know the status code. + // By setting the lasttermination state we are able to leave the container status waiting and present more accurate + // data via the API. + + oldStatus, ok := oldStatuses[container.Name] + if !ok { + continue + } + if oldStatus.State.Terminated != nil { + // if the old container status was terminated, the lasttermination status is correct + continue + } + if oldStatus.State.Running == nil { + // if the old container status isn't running, then waiting is an appropriate status and we have nothing to do + continue + } + + if pod.DeletionTimestamp == nil { + continue + } + + // and if the pod itself is being deleted, then the CRI may have removed the container already and for whatever reason the kubelet missed the exit code + // (this seems not awesome). We know at this point that we will not be restarting the container. + status := statuses[container.Name] + // if the status we're about to write indicates the default, the Waiting status will force this pod back into Pending. + // That isn't true, we know the pod is going away. + isDefaultWaitingStatus := status.State.Waiting != nil && status.State.Waiting.Reason == "ContainerCreating" + if hasInitContainers { + isDefaultWaitingStatus = status.State.Waiting != nil && status.State.Waiting.Reason == "PodInitializing" + } + if !isDefaultWaitingStatus { + // we the status was written, don't override + continue + } + if status.LastTerminationState.Terminated != nil { + // if we already have a termination state, nothing to do + continue + } + + // setting this value ensures that we show as stopped here, not as waiting: + // https://github.com/kubernetes/kubernetes/blob/90c9f7b3e198e82a756a68ffeac978a00d606e55/pkg/kubelet/kubelet_pods.go#L1440-L1445 + // This prevents the pod from becoming pending + status.LastTerminationState.Terminated = &v1.ContainerStateTerminated{ + Reason: "ContainerStatusUnknown", + Message: "The container could not be located when the pod was deleted. The container used to be Running", + ExitCode: 137, + } + statuses[container.Name] = status + } + // Make the latest container status comes first. sort.Sort(sort.Reverse(kubecontainer.SortContainerStatusesByCreationTime(podStatus.ContainerStatuses))) // Set container statuses according to the statuses seen in pod status @@ -1686,7 +1774,11 @@ func (kl *Kubelet) convertToAPIContainerStatuses(pod *v1.Pod, podStatus *kubecon if containerSeen[cName] >= 2 { continue } - status := convertContainerStatus(cStatus) + var oldStatusPtr *v1.ContainerStatus + if oldStatus, ok := oldStatuses[cName]; ok { + oldStatusPtr = &oldStatus + } + status := convertContainerStatus(cStatus, oldStatusPtr) if containerSeen[cName] == 0 { statuses[cName] = status } else { diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_server_journal.go b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_server_journal.go index 9c76041c3ac6..1d540c4a682b 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_server_journal.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_server_journal.go @@ -112,36 +112,6 @@ func newJournalArgsFromURL(query url.Values) (*journalArgs, error) { }, nil } -// Args returns the journalctl arguments for the given args. -func (a *journalArgs) Args() []string { - args := []string{ - "--utc", - "--no-pager", - } - if len(a.Since) > 0 { - args = append(args, "--since="+a.Since) - } - if len(a.Until) > 0 { - args = append(args, "--until="+a.Until) - } - if a.Tail > 0 { - args = append(args, "--pager-end", fmt.Sprintf("--lines=%d", a.Tail)) - } - if len(a.Format) > 0 { - args = append(args, "--output="+a.Format) - } - for _, unit := range a.Units { - if len(unit) > 0 { - args = append(args, "--unit="+unit) - } - } - if len(a.Pattern) > 0 { - args = append(args, "--grep="+a.Pattern) - args = append(args, fmt.Sprintf("--case-sensitive=%t", a.CaseSensitive)) - } - return args -} - // Copy streams the contents of the journalctl command executed with the current // args to the provided writer, timing out at a.Timeout. If an error occurs a line // is written to the output. @@ -166,9 +136,8 @@ func (a *journalArgs) copyForBoot(ctx context.Context, w io.Writer, previousBoot return } - args := a.Args() - args = append(args, "--boot", fmt.Sprintf("%d", previousBoot)) - cmd := exec.Command("journalctl", args...) + cmdStr, args := getLoggingCmd(a, previousBoot) + cmd := exec.Command(cmdStr, args...) cmd.Stdout = w cmd.Stderr = w diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_server_journal_linux.go b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_server_journal_linux.go new file mode 100644 index 000000000000..519ef209d3b7 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_server_journal_linux.go @@ -0,0 +1,40 @@ +// +build linux + +package kubelet + +import ( + "fmt" +) + +// getLoggingCmd returns the journalctl cmd and arguments for the given journalArgs and boot +func getLoggingCmd(a *journalArgs, boot int) (string, []string) { + args := []string{ + "--utc", + "--no-pager", + } + if len(a.Since) > 0 { + args = append(args, "--since="+a.Since) + } + if len(a.Until) > 0 { + args = append(args, "--until="+a.Until) + } + if a.Tail > 0 { + args = append(args, "--pager-end", fmt.Sprintf("--lines=%d", a.Tail)) + } + if len(a.Format) > 0 { + args = append(args, "--output="+a.Format) + } + for _, unit := range a.Units { + if len(unit) > 0 { + args = append(args, "--unit="+unit) + } + } + if len(a.Pattern) > 0 { + args = append(args, "--grep="+a.Pattern) + args = append(args, fmt.Sprintf("--case-sensitive=%t", a.CaseSensitive)) + } + + args = append(args, "--boot", fmt.Sprintf("%d", boot)) + + return "journalctl", args +} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_server_journal_others.go b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_server_journal_others.go new file mode 100644 index 000000000000..b92583b40b20 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_server_journal_others.go @@ -0,0 +1,8 @@ +// +build !linux,!windows + +package kubelet + +// getLoggingCmd on unsupported operating systems returns the echo command and a warning message (as strings) +func getLoggingCmd(a *journalArgs, boot int) (string, []string) { + return "echo", []string{"Operating System Not Supported"} +} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_server_journal_windows.go b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_server_journal_windows.go new file mode 100644 index 000000000000..695693f62015 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/kubelet_server_journal_windows.go @@ -0,0 +1,53 @@ +// +build windows + +package kubelet + +import ( + "fmt" + "strings" +) + +// getLoggingCmd returns the powershell cmd and arguments for the given journalArgs and boot +func getLoggingCmd(a *journalArgs, boot int) (string, []string) { + // The WinEvent log does not support querying by boot + // Set the cmd to return true on windows in case boot is not 0 + if boot != 0 { + return "cd.", []string{} + } + + args := []string{ + "-NonInteractive", + "-ExecutionPolicy", "Bypass", + "-Command", + } + + psCmd := "Get-WinEvent -FilterHashtable @{LogName='Application'" + if len(a.Since) > 0 { + psCmd += fmt.Sprintf("; StartTime='%s'", a.Since) + } + if len(a.Until) > 0 { + psCmd += fmt.Sprintf("; EndTime='%s'", a.Until) + } + var units []string + for _, unit := range a.Units { + if len(unit) > 0 { + units = append(units, "'"+unit+"'") + } + } + if len(units) > 0 { + psCmd += fmt.Sprintf("; ProviderName=%s", strings.Join(units, ",")) + } + psCmd += "}" + if a.Tail > 0 { + psCmd += fmt.Sprintf(" -MaxEvents %d", a.Tail) + } + psCmd += " | Sort-Object TimeCreated" + if len(a.Pattern) > 0 { + psCmd += fmt.Sprintf(" | Where-Object -Property Message -Match %s", a.Pattern) + } + psCmd += " | Format-Table -AutoSize -Wrap" + + args = append(args, psCmd) + + return "PowerShell.exe", args +} diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/kuberuntime/kuberuntime_container.go b/vendor/k8s.io/kubernetes/pkg/kubelet/kuberuntime/kuberuntime_container.go index af361122c35f..ef8c5a515fe3 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/kuberuntime/kuberuntime_container.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/kuberuntime/kuberuntime_container.go @@ -742,6 +742,18 @@ func findNextInitContainerToRun(pod *v1.Pod, podStatus *kubecontainer.PodStatus) return nil, nil, true } + // If any of the main containers have status and are Running, then all init containers must + // have been executed at some point in the past. However, they could have been removed + // from the container runtime now, and if we proceed, it would appear as if they + // never ran and will re-execute improperly. + for i := range pod.Spec.Containers { + container := &pod.Spec.Containers[i] + status := podStatus.FindContainerStatusByName(container.Name) + if status != nil && status.State == kubecontainer.ContainerStateRunning { + return nil, nil, true + } + } + // If there are failed containers, return the status of the last failed one. for i := len(pod.Spec.InitContainers) - 1; i >= 0; i-- { container := &pod.Spec.InitContainers[i] diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/kuberuntime/kuberuntime_manager.go b/vendor/k8s.io/kubernetes/pkg/kubelet/kuberuntime/kuberuntime_manager.go index 67d121d7321e..d0186ef96ee8 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/kuberuntime/kuberuntime_manager.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/kuberuntime/kuberuntime_manager.go @@ -505,19 +505,30 @@ func (m *kubeGenericRuntimeManager) computePodActions(pod *v1.Pod, podStatus *ku changes.CreateSandbox = false return changes } + + // Get the containers to start, excluding the ones that succeeded if RestartPolicy is OnFailure. + var containersToStart []int + for idx, c := range pod.Spec.Containers { + if pod.Spec.RestartPolicy == v1.RestartPolicyOnFailure && containerSucceeded(&c, podStatus) { + continue + } + containersToStart = append(containersToStart, idx) + } + // We should not create a sandbox for a Pod if initialization is done and there is no container to start. + if len(containersToStart) == 0 { + _, _, done := findNextInitContainerToRun(pod, podStatus) + if done { + changes.CreateSandbox = false + return changes + } + } + if len(pod.Spec.InitContainers) != 0 { // Pod has init containers, return the first one. changes.NextInitContainerToStart = &pod.Spec.InitContainers[0] return changes } - // Start all containers by default but exclude the ones that succeeded if - // RestartPolicy is OnFailure. - for idx, c := range pod.Spec.Containers { - if containerSucceeded(&c, podStatus) && pod.Spec.RestartPolicy == v1.RestartPolicyOnFailure { - continue - } - changes.ContainersToStart = append(changes.ContainersToStart, idx) - } + changes.ContainersToStart = containersToStart return changes } diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/time_cache.go b/vendor/k8s.io/kubernetes/pkg/kubelet/time_cache.go index 66528e25729c..d5929efbf107 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/time_cache.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/time_cache.go @@ -27,7 +27,7 @@ import ( // timeCache stores a time keyed by uid type timeCache struct { - lock sync.RWMutex + lock sync.Mutex cache *lru.Cache } @@ -53,8 +53,8 @@ func (c *timeCache) Remove(uid types.UID) { } func (c *timeCache) Get(uid types.UID) (time.Time, bool) { - c.lock.RLock() - defer c.lock.RUnlock() + c.lock.Lock() + defer c.lock.Unlock() value, ok := c.cache.Get(uid) if !ok { return time.Time{}, false diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/endpoints.go b/vendor/k8s.io/kubernetes/pkg/proxy/endpoints.go index b797a01e10d9..234cf4f2656c 100644 --- a/vendor/k8s.io/kubernetes/pkg/proxy/endpoints.go +++ b/vendor/k8s.io/kubernetes/pkg/proxy/endpoints.go @@ -167,7 +167,10 @@ func (ect *EndpointChangeTracker) Update(previous, current *v1.Endpoints) bool { ect.items[namespacedName] = change } - if t := getLastChangeTriggerTime(endpoints.Annotations); !t.IsZero() { + // In case of Endpoints deletion, the LastChangeTriggerTime annotation is + // by-definition coming from the time of last update, which is not what + // we want to measure. So we simply ignore it in this cases. + if t := getLastChangeTriggerTime(endpoints.Annotations); !t.IsZero() && current != nil { ect.lastChangeTriggerTimes[namespacedName] = append(ect.lastChangeTriggerTimes[namespacedName], t) } @@ -222,7 +225,12 @@ func (ect *EndpointChangeTracker) EndpointSliceUpdate(endpointSlice *discovery.E if changeNeeded { metrics.EndpointChangesPending.Inc() - if t := getLastChangeTriggerTime(endpointSlice.Annotations); !t.IsZero() { + // In case of Endpoints deletion, the LastChangeTriggerTime annotation is + // by-definition coming from the time of last update, which is not what + // we want to measure. So we simply ignore it in this cases. + // TODO(wojtek-t, robscott): Address the problem for EndpointSlice deletion + // when other EndpointSlice for that service still exist. + if t := getLastChangeTriggerTime(endpointSlice.Annotations); !t.IsZero() && !removeSlice { ect.lastChangeTriggerTimes[namespacedName] = append(ect.lastChangeTriggerTimes[namespacedName], t) } diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier.go b/vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier.go index 61161aecb5e0..ee3fb0d6d60a 100644 --- a/vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier.go +++ b/vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier.go @@ -1183,9 +1183,10 @@ func (proxier *Proxier) syncProxyRules() { allowFromNode := false for _, src := range svcInfo.LoadBalancerSourceRanges() { writeLine(proxier.natRules, append(args, "-s", src, "-j", string(chosenChain))...) - // ignore error because it has been validated - _, cidr, _ := net.ParseCIDR(src) - if cidr.Contains(proxier.nodeIP) { + _, cidr, err := net.ParseCIDR(src) + if err != nil { + klog.Errorf("Error parsing %s CIDR in LoadBalancerSourceRanges, dropping: %v", cidr, err) + } else if cidr.Contains(proxier.nodeIP) { allowFromNode = true } } diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/service.go b/vendor/k8s.io/kubernetes/pkg/proxy/service.go index 189feab64e17..48bd402f02c8 100644 --- a/vendor/k8s.io/kubernetes/pkg/proxy/service.go +++ b/vendor/k8s.io/kubernetes/pkg/proxy/service.go @@ -146,10 +146,14 @@ func (sct *ServiceChangeTracker) newBaseServiceInfo(port *v1.ServicePort, servic topologyKeys: service.Spec.TopologyKeys, } + loadBalancerSourceRanges := make([]string, len(service.Spec.LoadBalancerSourceRanges)) + for i, sourceRange := range service.Spec.LoadBalancerSourceRanges { + loadBalancerSourceRanges[i] = strings.TrimSpace(sourceRange) + } + if sct.isIPv6Mode == nil { info.externalIPs = make([]string, len(service.Spec.ExternalIPs)) - info.loadBalancerSourceRanges = make([]string, len(service.Spec.LoadBalancerSourceRanges)) - copy(info.loadBalancerSourceRanges, service.Spec.LoadBalancerSourceRanges) + info.loadBalancerSourceRanges = loadBalancerSourceRanges copy(info.externalIPs, service.Spec.ExternalIPs) // Deep-copy in case the service instance changes info.loadBalancerStatus = *service.Status.LoadBalancer.DeepCopy() @@ -162,7 +166,7 @@ func (sct *ServiceChangeTracker) newBaseServiceInfo(port *v1.ServicePort, servic if len(incorrectIPs) > 0 { utilproxy.LogAndEmitIncorrectIPVersionEvent(sct.recorder, "externalIPs", strings.Join(incorrectIPs, ","), service.Namespace, service.Name, service.UID) } - info.loadBalancerSourceRanges, incorrectIPs = utilproxy.FilterIncorrectCIDRVersion(service.Spec.LoadBalancerSourceRanges, *sct.isIPv6Mode) + info.loadBalancerSourceRanges, incorrectIPs = utilproxy.FilterIncorrectCIDRVersion(loadBalancerSourceRanges, *sct.isIPv6Mode) if len(incorrectIPs) > 0 { utilproxy.LogAndEmitIncorrectIPVersionEvent(sct.recorder, "loadBalancerSourceRanges", strings.Join(incorrectIPs, ","), service.Namespace, service.Name, service.UID) } diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/BUILD b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/BUILD index 4d09304432a5..b21f79b567cc 100644 --- a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/BUILD +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/plugins/noderesources/BUILD @@ -67,6 +67,7 @@ go_test( "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", + "//staging/src/k8s.io/component-base/featuregate:go_default_library", "//staging/src/k8s.io/component-base/featuregate/testing:go_default_library", "//vendor/github.com/stretchr/testify/assert:go_default_library", ], diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1/listers.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1/listers.go index e6bc9b43db17..91167edc0a0a 100644 --- a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1/listers.go +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1/listers.go @@ -22,6 +22,8 @@ type NodeInfoLister interface { List() ([]*NodeInfo, error) // Returns the list of NodeInfos of nodes with pods with affinity terms. HavePodsWithAffinityList() ([]*NodeInfo, error) + // Returns the list of NodeInfos of nodes with pods with required anti-affinity terms. + HavePodsWithRequiredAntiAffinityList() ([]*NodeInfo, error) // Returns the NodeInfo of the given node name. Get(nodeName string) (*NodeInfo, error) } diff --git a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1/types.go b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1/types.go index c878a7c9ffad..1bf116b6b767 100644 --- a/vendor/k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1/types.go +++ b/vendor/k8s.io/kubernetes/pkg/scheduler/framework/v1alpha1/types.go @@ -196,6 +196,9 @@ type NodeInfo struct { // The subset of pods with affinity. PodsWithAffinity []*PodInfo + // The subset of pods with required anti-affinity. + PodsWithRequiredAntiAffinity []*PodInfo + // Ports allocated on the node. UsedPorts HostPortInfo @@ -388,8 +391,10 @@ func (r *Resource) SetMaxResource(rl v1.ResourceList) { r.MilliCPU = cpu } case v1.ResourceEphemeralStorage: - if ephemeralStorage := rQuantity.Value(); ephemeralStorage > r.EphemeralStorage { - r.EphemeralStorage = ephemeralStorage + if utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolation) { + if ephemeralStorage := rQuantity.Value(); ephemeralStorage > r.EphemeralStorage { + r.EphemeralStorage = ephemeralStorage + } } default: if v1helper.IsScalarResourceName(rName) { @@ -457,6 +462,9 @@ func (n *NodeInfo) Clone() *NodeInfo { if len(n.PodsWithAffinity) > 0 { clone.PodsWithAffinity = append([]*PodInfo(nil), n.PodsWithAffinity...) } + if len(n.PodsWithRequiredAntiAffinity) > 0 { + clone.PodsWithRequiredAntiAffinity = append([]*PodInfo(nil), n.PodsWithRequiredAntiAffinity...) + } return clone } @@ -486,10 +494,12 @@ func (n *NodeInfo) AddPod(pod *v1.Pod) { n.NonZeroRequested.MilliCPU += non0CPU n.NonZeroRequested.Memory += non0Mem n.Pods = append(n.Pods, podInfo) - affinity := pod.Spec.Affinity - if affinity != nil && (affinity.PodAffinity != nil || affinity.PodAntiAffinity != nil) { + if podWithAffinity(pod) { n.PodsWithAffinity = append(n.PodsWithAffinity, podInfo) } + if podWithRequiredAntiAffinity(pod) { + n.PodsWithRequiredAntiAffinity = append(n.PodsWithRequiredAntiAffinity, podInfo) + } // Consume ports when pods added. n.updateUsedPorts(podInfo.Pod, true) @@ -497,33 +507,54 @@ func (n *NodeInfo) AddPod(pod *v1.Pod) { n.Generation = nextGeneration() } -// RemovePod subtracts pod information from this NodeInfo. -func (n *NodeInfo) RemovePod(pod *v1.Pod) error { - k1, err := GetPodKey(pod) - if err != nil { - return err - } +func podWithAffinity(p *v1.Pod) bool { + affinity := p.Spec.Affinity + return affinity != nil && (affinity.PodAffinity != nil || affinity.PodAntiAffinity != nil) +} + +func podWithRequiredAntiAffinity(p *v1.Pod) bool { + affinity := p.Spec.Affinity + return affinity != nil && affinity.PodAntiAffinity != nil && + len(affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution) != 0 +} - for i := range n.PodsWithAffinity { - k2, err := GetPodKey(n.PodsWithAffinity[i].Pod) +func removeFromSlice(s []*PodInfo, k string) []*PodInfo { + for i := range s { + k2, err := GetPodKey(s[i].Pod) if err != nil { klog.Errorf("Cannot get pod key, err: %v", err) continue } - if k1 == k2 { + if k == k2 { // delete the element - n.PodsWithAffinity[i] = n.PodsWithAffinity[len(n.PodsWithAffinity)-1] - n.PodsWithAffinity = n.PodsWithAffinity[:len(n.PodsWithAffinity)-1] + s[i] = s[len(s)-1] + s = s[:len(s)-1] break } } + return s +} + +// RemovePod subtracts pod information from this NodeInfo. +func (n *NodeInfo) RemovePod(pod *v1.Pod) error { + k, err := GetPodKey(pod) + if err != nil { + return err + } + if podWithAffinity(pod) { + n.PodsWithAffinity = removeFromSlice(n.PodsWithAffinity, k) + } + if podWithRequiredAntiAffinity(pod) { + n.PodsWithRequiredAntiAffinity = removeFromSlice(n.PodsWithRequiredAntiAffinity, k) + } + for i := range n.Pods { k2, err := GetPodKey(n.Pods[i].Pod) if err != nil { klog.Errorf("Cannot get pod key, err: %v", err) continue } - if k1 == k2 { + if k == k2 { // delete the element n.Pods[i] = n.Pods[len(n.Pods)-1] n.Pods = n.Pods[:len(n.Pods)-1] @@ -558,6 +589,9 @@ func (n *NodeInfo) resetSlicesIfEmpty() { if len(n.PodsWithAffinity) == 0 { n.PodsWithAffinity = nil } + if len(n.PodsWithRequiredAntiAffinity) == 0 { + n.PodsWithRequiredAntiAffinity = nil + } if len(n.Pods) == 0 { n.Pods = nil } diff --git a/vendor/k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp/BUILD b/vendor/k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp/BUILD index bce686a3621a..a3b99b53ff3a 100644 --- a/vendor/k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp/BUILD +++ b/vendor/k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp/BUILD @@ -13,6 +13,7 @@ go_library( deps = [ "//pkg/api/pod:go_default_library", "//pkg/apis/core:go_default_library", + "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", ], ) diff --git a/vendor/k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp/strategy.go b/vendor/k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp/strategy.go index 5fee30cb1f41..a9cfa4216115 100644 --- a/vendor/k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp/strategy.go +++ b/vendor/k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp/strategy.go @@ -20,6 +20,7 @@ import ( "fmt" "strings" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/validation/field" podutil "k8s.io/kubernetes/pkg/api/pod" api "k8s.io/kubernetes/pkg/apis/core" @@ -67,6 +68,15 @@ func NewStrategy(pspAnnotations map[string]string) Strategy { allowAnyProfile = true continue } + // With the graduation of seccomp to GA we automatically convert + // the deprecated seccomp profile annotation `docker/default` to + // `runtime/default`. This means that we now have to automatically + // allow `runtime/default` if a user specifies `docker/default` and + // vice versa in a PSP. + if p == v1.DeprecatedSeccompProfileDockerDefault || p == v1.SeccompProfileRuntimeDefault { + allowedProfiles[v1.SeccompProfileRuntimeDefault] = true + allowedProfiles[v1.DeprecatedSeccompProfileDockerDefault] = true + } allowedProfiles[p] = true } } diff --git a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/attacher.go b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/attacher.go index 60bb9a661103..d1e2c2a1991f 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/attacher.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/azure_dd/attacher.go @@ -285,6 +285,15 @@ func (d *azureDiskDetacher) Detach(diskURI string, nodeName types.NodeName) erro // UnmountDevice unmounts the volume on the node func (d *azureDiskDetacher) UnmountDevice(deviceMountPath string) error { + if runtime.GOOS == "windows" { + // Flush data cache for windows because it does not do so automatically during unmount device + exec := d.plugin.host.GetExec(d.plugin.GetPluginName()) + err := util.WriteVolumeCache(deviceMountPath, exec) + if err != nil { + return err + } + } + err := mount.CleanupMountPoint(deviceMountPath, d.plugin.host.GetMounter(d.plugin.GetPluginName()), false) if err == nil { klog.V(2).Infof("azureDisk - Device %s was unmounted", deviceMountPath) diff --git a/vendor/k8s.io/kubernetes/pkg/volume/fc/attacher.go b/vendor/k8s.io/kubernetes/pkg/volume/fc/attacher.go index a9252286412f..fe4ac941ba42 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/fc/attacher.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/fc/attacher.go @@ -165,6 +165,11 @@ func (detacher *fcDetacher) UnmountDevice(deviceMountPath string) error { if err != nil { return fmt.Errorf("fc: failed to unmount: %s\nError: %v", deviceMountPath, err) } + // GetDeviceNameFromMount from above returns an empty string if deviceMountPath is not a mount point + // There is no need to DetachDisk if this is the case (and DetachDisk will throw an error if we attempt) + if devName == "" { + return nil + } unMounter := volumeSpecToUnmounter(detacher.mounter) err = detacher.manager.DetachDisk(*unMounter, devName) if err != nil { diff --git a/vendor/k8s.io/kubernetes/pkg/volume/fc/fc_util.go b/vendor/k8s.io/kubernetes/pkg/volume/fc/fc_util.go index a2bc31e3b3aa..c8da529c9c79 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/fc/fc_util.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/fc/fc_util.go @@ -21,6 +21,7 @@ import ( "io/ioutil" "os" "path/filepath" + "regexp" "strconv" "strings" @@ -60,12 +61,13 @@ func (handler *osIOHandler) WriteFile(filename string, data []byte, perm os.File // given a wwn and lun, find the device and associated devicemapper parent func findDisk(wwn, lun string, io ioHandler, deviceUtil volumeutil.DeviceUtil) (string, string) { - fcPath := "-fc-0x" + wwn + "-lun-" + lun + fcPathExp := "^(pci-.*-fc|fc)-0x" + wwn + "-lun-" + lun + r := regexp.MustCompile(fcPathExp) devPath := byPath if dirs, err := io.ReadDir(devPath); err == nil { for _, f := range dirs { name := f.Name() - if strings.Contains(name, fcPath) { + if r.MatchString(name) { if disk, err1 := io.EvalSymlinks(devPath + name); err1 == nil { dm := deviceUtil.FindMultipathDeviceForDevice(disk) klog.Infof("fc: find disk: %v, dm: %v", disk, dm) diff --git a/vendor/k8s.io/kubernetes/pkg/volume/rbd/rbd_util.go b/vendor/k8s.io/kubernetes/pkg/volume/rbd/rbd_util.go index 4c001cb704b1..a0f5922437a6 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/rbd/rbd_util.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/rbd/rbd_util.go @@ -594,9 +594,9 @@ func (util *rbdUtil) CreateImage(p *rbdVolumeProvisioner) (r *v1.RBDPersistentVo volSz := fmt.Sprintf("%d", sz) mon := util.kernelRBDMonitorsOpt(p.Mon) if p.rbdMounter.imageFormat == rbdImageFormat2 { - klog.V(4).Infof("rbd: create %s size %s format %s (features: %s) using mon %s, pool %s id %s key %s", p.rbdMounter.Image, volSz, p.rbdMounter.imageFormat, p.rbdMounter.imageFeatures, mon, p.rbdMounter.Pool, p.rbdMounter.adminID, p.rbdMounter.adminSecret) + klog.V(4).Infof("rbd: create %s size %s format %s (features: %s) using mon %s, pool %s id %s key ", p.rbdMounter.Image, volSz, p.rbdMounter.imageFormat, p.rbdMounter.imageFeatures, mon, p.rbdMounter.Pool, p.rbdMounter.adminID) } else { - klog.V(4).Infof("rbd: create %s size %s format %s using mon %s, pool %s id %s key %s", p.rbdMounter.Image, volSz, p.rbdMounter.imageFormat, mon, p.rbdMounter.Pool, p.rbdMounter.adminID, p.rbdMounter.adminSecret) + klog.V(4).Infof("rbd: create %s size %s format %s using mon %s, pool %s id %s key ", p.rbdMounter.Image, volSz, p.rbdMounter.imageFormat, mon, p.rbdMounter.Pool, p.rbdMounter.adminID) } args := []string{"create", p.rbdMounter.Image, "--size", volSz, "--pool", p.rbdMounter.Pool, "--id", p.rbdMounter.adminID, "-m", mon, "--key=" + p.rbdMounter.adminSecret, "--image-format", p.rbdMounter.imageFormat} if p.rbdMounter.imageFormat == rbdImageFormat2 { @@ -632,7 +632,7 @@ func (util *rbdUtil) DeleteImage(p *rbdVolumeDeleter) error { } // rbd rm. mon := util.kernelRBDMonitorsOpt(p.rbdMounter.Mon) - klog.V(4).Infof("rbd: rm %s using mon %s, pool %s id %s key %s", p.rbdMounter.Image, mon, p.rbdMounter.Pool, p.rbdMounter.adminID, p.rbdMounter.adminSecret) + klog.V(4).Infof("rbd: rm %s using mon %s, pool %s id %s key ", p.rbdMounter.Image, mon, p.rbdMounter.Pool, p.rbdMounter.adminID) output, err = p.exec.Command("rbd", "rm", p.rbdMounter.Image, "--pool", p.rbdMounter.Pool, "--id", p.rbdMounter.adminID, "-m", mon, "--key="+p.rbdMounter.adminSecret).CombinedOutput() if err == nil { @@ -668,7 +668,7 @@ func (util *rbdUtil) ExpandImage(rbdExpander *rbdVolumeExpander, oldSize resourc // rbd resize. mon := util.kernelRBDMonitorsOpt(rbdExpander.rbdMounter.Mon) - klog.V(4).Infof("rbd: resize %s using mon %s, pool %s id %s key %s", rbdExpander.rbdMounter.Image, mon, rbdExpander.rbdMounter.Pool, rbdExpander.rbdMounter.adminID, rbdExpander.rbdMounter.adminSecret) + klog.V(4).Infof("rbd: resize %s using mon %s, pool %s id %s key ", rbdExpander.rbdMounter.Image, mon, rbdExpander.rbdMounter.Pool, rbdExpander.rbdMounter.adminID) output, err = rbdExpander.exec.Command("rbd", "resize", rbdExpander.rbdMounter.Image, "--size", newVolSz, "--pool", rbdExpander.rbdMounter.Pool, "--id", rbdExpander.rbdMounter.adminID, "-m", mon, "--key="+rbdExpander.rbdMounter.adminSecret).CombinedOutput() if err == nil { @@ -710,7 +710,7 @@ func (util *rbdUtil) rbdInfo(b *rbdMounter) (int, error) { // # image does not exist (exit=2) // rbd: error opening image 1234: (2) No such file or directory // - klog.V(4).Infof("rbd: info %s using mon %s, pool %s id %s key %s", b.Image, mon, b.Pool, id, secret) + klog.V(4).Infof("rbd: info %s using mon %s, pool %s id %s key ", b.Image, mon, b.Pool, id) output, err = b.exec.Command("rbd", "info", b.Image, "--pool", b.Pool, "-m", mon, "--id", id, "--key="+secret, "-k=/dev/null", "--format=json").CombinedOutput() @@ -773,7 +773,7 @@ func (util *rbdUtil) rbdStatus(b *rbdMounter) (bool, string, error) { // # image does not exist (exit=2) // rbd: error opening image kubernetes-dynamic-pvc-: (2) No such file or directory // - klog.V(4).Infof("rbd: status %s using mon %s, pool %s id %s key %s", b.Image, mon, b.Pool, id, secret) + klog.V(4).Infof("rbd: status %s using mon %s, pool %s id %s key ", b.Image, mon, b.Pool, id) cmd, err = b.exec.Command("rbd", "status", b.Image, "--pool", b.Pool, "-m", mon, "--id", id, "--key="+secret).CombinedOutput() output = string(cmd) diff --git a/vendor/k8s.io/kubernetes/test/e2e/auth/service_accounts.go b/vendor/k8s.io/kubernetes/test/e2e/auth/service_accounts.go index 1fc9e7d0e1bc..cef99fa6234b 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/auth/service_accounts.go +++ b/vendor/k8s.io/kubernetes/test/e2e/auth/service_accounts.go @@ -631,7 +631,7 @@ var _ = SIGDescribe("ServiceAccounts", func() { framework.Logf("Error pulling logs: %v", err) return false, nil } - tokenCount, err := parseInClusterClientLogs(logs) + tokenCount, err := ParseInClusterClientLogs(logs) if err != nil { return false, fmt.Errorf("inclusterclient reported an error: %v", err) } @@ -832,7 +832,8 @@ var _ = SIGDescribe("ServiceAccounts", func() { var reportLogsParser = regexp.MustCompile("([a-zA-Z0-9-_]*)=([a-zA-Z0-9-_]*)$") -func parseInClusterClientLogs(logs string) (int, error) { +// ParseInClusterClientLogs parses logs of pods using inclusterclient. +func ParseInClusterClientLogs(logs string) (int, error) { seenTokens := map[string]struct{}{} lines := strings.Split(logs, "\n") diff --git a/vendor/k8s.io/kubernetes/test/e2e/e2e.go b/vendor/k8s.io/kubernetes/test/e2e/e2e.go index d1e23325d698..6d503a7d7a03 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/e2e.go +++ b/vendor/k8s.io/kubernetes/test/e2e/e2e.go @@ -184,7 +184,13 @@ func getDefaultClusterIPFamily(c clientset.Interface) string { // waitForDaemonSets for all daemonsets in the given namespace to be ready // (defined as all but 'allowedNotReadyNodes' pods associated with that // daemonset are ready). +// +// If allowedNotReadyNodes is -1, this method returns immediately without waiting. func waitForDaemonSets(c clientset.Interface, ns string, allowedNotReadyNodes int32, timeout time.Duration) error { + if allowedNotReadyNodes == -1 { + return nil + } + start := time.Now() framework.Logf("Waiting up to %v for all daemonsets in namespace '%s' to start", timeout, ns) diff --git a/vendor/k8s.io/kubernetes/test/e2e/framework/node/wait.go b/vendor/k8s.io/kubernetes/test/e2e/framework/node/wait.go index 9cad4dc71208..a3aa06681971 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/framework/node/wait.go +++ b/vendor/k8s.io/kubernetes/test/e2e/framework/node/wait.go @@ -213,6 +213,9 @@ func CheckReadyForTests(c clientset.Interface, nonblockingTaints string, allowed attempt := 0 var notSchedulable []*v1.Node return func() (bool, error) { + if allowedNotReadyNodes == -1 { + return true, nil + } attempt++ notSchedulable = nil opts := metav1.ListOptions{ diff --git a/vendor/k8s.io/kubernetes/test/e2e/framework/nodes_util.go b/vendor/k8s.io/kubernetes/test/e2e/framework/nodes_util.go index 2dc622cd1005..b589771a89ef 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/framework/nodes_util.go +++ b/vendor/k8s.io/kubernetes/test/e2e/framework/nodes_util.go @@ -34,7 +34,7 @@ import ( e2essh "k8s.io/kubernetes/test/e2e/framework/ssh" ) -const etcdImage = "3.4.9-1" +const etcdImage = "3.4.13-0" // EtcdUpgrade upgrades etcd on GCE. func EtcdUpgrade(targetStorage, targetVersion string) error { @@ -47,10 +47,10 @@ func EtcdUpgrade(targetStorage, targetVersion string) error { } // MasterUpgrade upgrades master node on GCE/GKE. -func MasterUpgrade(f *Framework, v string) error { +func MasterUpgrade(f *Framework, v string, extraEnvs []string) error { switch TestContext.Provider { case "gce": - return masterUpgradeGCE(v, false) + return masterUpgradeGCE(v, extraEnvs) case "gke": return MasterUpgradeGKE(f.Namespace.Name, v) default: @@ -72,12 +72,12 @@ func etcdUpgradeGCE(targetStorage, targetVersion string) error { // MasterUpgradeGCEWithKubeProxyDaemonSet upgrades master node on GCE with enabling/disabling the daemon set of kube-proxy. // TODO(mrhohn): Remove this function when kube-proxy is run as a DaemonSet by default. func MasterUpgradeGCEWithKubeProxyDaemonSet(v string, enableKubeProxyDaemonSet bool) error { - return masterUpgradeGCE(v, enableKubeProxyDaemonSet) + return masterUpgradeGCE(v, []string{fmt.Sprintf("KUBE_PROXY_DAEMONSET=%v", enableKubeProxyDaemonSet)}) } // TODO(mrhohn): Remove 'enableKubeProxyDaemonSet' when kube-proxy is run as a DaemonSet by default. -func masterUpgradeGCE(rawV string, enableKubeProxyDaemonSet bool) error { - env := append(os.Environ(), fmt.Sprintf("KUBE_PROXY_DAEMONSET=%v", enableKubeProxyDaemonSet)) +func masterUpgradeGCE(rawV string, extraEnvs []string) error { + env := append(os.Environ(), extraEnvs...) // TODO: Remove these variables when they're no longer needed for downgrades. if TestContext.EtcdUpgradeVersion != "" && TestContext.EtcdUpgradeStorage != "" { env = append(env, diff --git a/vendor/k8s.io/kubernetes/test/e2e/framework/pod/create.go b/vendor/k8s.io/kubernetes/test/e2e/framework/pod/create.go index beb31fdfb4df..353fb8cb9f2f 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/framework/pod/create.go +++ b/vendor/k8s.io/kubernetes/test/e2e/framework/pod/create.go @@ -48,6 +48,7 @@ type Config struct { SeLinuxLabel *v1.SELinuxOptions FsGroup *int64 NodeSelection NodeSelection + ImageID int } // CreateUnschedulablePod with given claims based on node selector @@ -185,6 +186,10 @@ func MakeSecPod(podConfig *Config) (*v1.Pod, error) { return &i }(1000) } + image := imageutils.BusyBox + if podConfig.ImageID != imageutils.None { + image = podConfig.ImageID + } podSpec := &v1.Pod{ TypeMeta: metav1.TypeMeta{ Kind: "Pod", @@ -203,7 +208,7 @@ func MakeSecPod(podConfig *Config) (*v1.Pod, error) { Containers: []v1.Container{ { Name: "write-pod", - Image: imageutils.GetE2EImage(imageutils.BusyBox), + Image: imageutils.GetE2EImage(image), Command: []string{"/bin/sh"}, Args: []string{"-c", podConfig.Command}, SecurityContext: &v1.SecurityContext{ diff --git a/vendor/k8s.io/kubernetes/test/e2e/framework/pod/resource.go b/vendor/k8s.io/kubernetes/test/e2e/framework/pod/resource.go index 155a4e74984e..6feabb2a8316 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/framework/pod/resource.go +++ b/vendor/k8s.io/kubernetes/test/e2e/framework/pod/resource.go @@ -502,25 +502,33 @@ func checkPodsCondition(c clientset.Interface, ns string, podNames []string, tim // GetPodLogs returns the logs of the specified container (namespace/pod/container). func GetPodLogs(c clientset.Interface, namespace, podName, containerName string) (string, error) { - return getPodLogsInternal(c, namespace, podName, containerName, false) + return getPodLogsInternal(c, namespace, podName, containerName, false, nil) +} + +// GetPodLogsSince returns the logs of the specified container (namespace/pod/container) since a timestamp. +func GetPodLogsSince(c clientset.Interface, namespace, podName, containerName string, since time.Time) (string, error) { + sinceTime := metav1.NewTime(since) + return getPodLogsInternal(c, namespace, podName, containerName, false, &sinceTime) } // GetPreviousPodLogs returns the logs of the previous instance of the // specified container (namespace/pod/container). func GetPreviousPodLogs(c clientset.Interface, namespace, podName, containerName string) (string, error) { - return getPodLogsInternal(c, namespace, podName, containerName, true) + return getPodLogsInternal(c, namespace, podName, containerName, true, nil) } // utility function for gomega Eventually -func getPodLogsInternal(c clientset.Interface, namespace, podName, containerName string, previous bool) (string, error) { - logs, err := c.CoreV1().RESTClient().Get(). +func getPodLogsInternal(c clientset.Interface, namespace, podName, containerName string, previous bool, sinceTime *metav1.Time) (string, error) { + request := c.CoreV1().RESTClient().Get(). Resource("pods"). Namespace(namespace). Name(podName).SubResource("log"). Param("container", containerName). - Param("previous", strconv.FormatBool(previous)). - Do(context.TODO()). - Raw() + Param("previous", strconv.FormatBool(previous)) + if sinceTime != nil { + request.Param("sinceTime", sinceTime.Format(time.RFC3339)) + } + logs, err := request.Do(context.TODO()).Raw() if err != nil { return "", err } diff --git a/vendor/k8s.io/kubernetes/test/e2e/framework/pod/wait.go b/vendor/k8s.io/kubernetes/test/e2e/framework/pod/wait.go index 8f1e8be6f8ca..7ea437c2849d 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/framework/pod/wait.go +++ b/vendor/k8s.io/kubernetes/test/e2e/framework/pod/wait.go @@ -99,7 +99,14 @@ func errorBadPodsStates(badPods []v1.Pod, desiredPods int, ns, desiredState stri // waiting. All pods that are in SUCCESS state are not counted. // // If ignoreLabels is not empty, pods matching this selector are ignored. +// +// If minPods or allowedNotReadyPods are -1, this method returns immediately +// without waiting. func WaitForPodsRunningReady(c clientset.Interface, ns string, minPods, allowedNotReadyPods int32, timeout time.Duration, ignoreLabels map[string]string) error { + if minPods == -1 || allowedNotReadyPods == -1 { + return nil + } + ignoreSelector := labels.SelectorFromSet(map[string]string{}) start := time.Now() e2elog.Logf("Waiting up to %v for all pods (need at least %d) in namespace '%s' to be running and ready", diff --git a/vendor/k8s.io/kubernetes/test/e2e/framework/providers/gce/gce.go b/vendor/k8s.io/kubernetes/test/e2e/framework/providers/gce/gce.go index 271a70760a9a..05b0b003c831 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/framework/providers/gce/gce.go +++ b/vendor/k8s.io/kubernetes/test/e2e/framework/providers/gce/gce.go @@ -19,6 +19,7 @@ package gce import ( "context" "fmt" + "math/rand" "net/http" "os/exec" "regexp" @@ -47,6 +48,21 @@ func factory() (framework.ProviderInterface, error) { framework.Logf("Fetching cloud provider for %q\r", framework.TestContext.Provider) zone := framework.TestContext.CloudConfig.Zone region := framework.TestContext.CloudConfig.Region + allowedZones := framework.TestContext.CloudConfig.Zones + + // ensure users don't specify a zone outside of the requested zones + if len(zone) > 0 && len(allowedZones) > 0 { + var found bool + for _, allowedZone := range allowedZones { + if zone == allowedZone { + found = true + break + } + } + if !found { + return nil, fmt.Errorf("the provided zone %q must be included in the list of allowed zones %v", zone, allowedZones) + } + } var err error if region == "" { @@ -59,6 +75,9 @@ func factory() (framework.ProviderInterface, error) { if !framework.TestContext.CloudConfig.MultiZone { managedZones = []string{zone} } + if len(allowedZones) > 0 { + managedZones = allowedZones + } gceCloud, err := gcecloud.CreateGCECloud(&gcecloud.CloudConfig{ APIEndpoint: framework.TestContext.CloudConfig.APIEndpoint, @@ -79,7 +98,10 @@ func factory() (framework.ProviderInterface, error) { return nil, fmt.Errorf("Error building GCE/GKE provider: %v", err) } - // Arbitrarily pick one of the zones we have nodes in + // Arbitrarily pick one of the zones we have nodes in, looking at prepopulated zones first. + if framework.TestContext.CloudConfig.Zone == "" && len(managedZones) > 0 { + framework.TestContext.CloudConfig.Zone = managedZones[rand.Intn(len(managedZones))] + } if framework.TestContext.CloudConfig.Zone == "" && framework.TestContext.CloudConfig.MultiZone { zones, err := gceCloud.GetAllZonesFromCloudProvider() if err != nil { diff --git a/vendor/k8s.io/kubernetes/test/e2e/framework/test_context.go b/vendor/k8s.io/kubernetes/test/e2e/framework/test_context.go index b0a8a9f97ab7..0d3c907dcf44 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/framework/test_context.go +++ b/vendor/k8s.io/kubernetes/test/e2e/framework/test_context.go @@ -224,7 +224,8 @@ type NodeTestContextType struct { type CloudConfig struct { APIEndpoint string ProjectID string - Zone string // for multizone tests, arbitrarily chosen zone + Zone string // for multizone tests, arbitrarily chosen zone + Zones []string // for multizone tests, use this set of zones instead of querying the cloud provider. Must include Zone. Region string MultiZone bool MultiMaster bool @@ -284,7 +285,7 @@ func RegisterCommonFlags(flags *flag.FlagSet) { flags.StringVar(&TestContext.LogexporterGCSPath, "logexporter-gcs-path", "", "Path to the GCS artifacts directory to dump logs from nodes. Logexporter gets enabled if this is non-empty.") flags.BoolVar(&TestContext.DeleteNamespace, "delete-namespace", true, "If true tests will delete namespace after completion. It is only designed to make debugging easier, DO NOT turn it off by default.") flags.BoolVar(&TestContext.DeleteNamespaceOnFailure, "delete-namespace-on-failure", true, "If true, framework will delete test namespace on failure. Used only during test debugging.") - flags.IntVar(&TestContext.AllowedNotReadyNodes, "allowed-not-ready-nodes", 0, "If non-zero, framework will allow for that many non-ready nodes when checking for all ready nodes.") + flags.IntVar(&TestContext.AllowedNotReadyNodes, "allowed-not-ready-nodes", 0, "If greater than zero, framework will allow for that many non-ready nodes when checking for all ready nodes. If -1, no waiting will be performed for ready nodes or daemonset pods.") flags.StringVar(&TestContext.Host, "host", "", fmt.Sprintf("The host, or apiserver, to connect to. Will default to %s if this argument and --kubeconfig are not set", defaultHost)) flags.StringVar(&TestContext.ReportPrefix, "report-prefix", "", "Optional prefix for JUnit XML reports. Default is empty, which doesn't prepend anything to the default name.") @@ -334,6 +335,7 @@ func RegisterClusterFlags(flags *flag.FlagSet) { flags.StringVar(&cloudConfig.APIEndpoint, "gce-api-endpoint", "", "The GCE APIEndpoint being used, if applicable") flags.StringVar(&cloudConfig.ProjectID, "gce-project", "", "The GCE project being used, if applicable") flags.StringVar(&cloudConfig.Zone, "gce-zone", "", "GCE zone being used, if applicable") + flags.Var(cliflag.NewStringSlice(&cloudConfig.Zones), "gce-zones", "The set of zones to use in a multi-zone test instead of querying the cloud provider.") flags.StringVar(&cloudConfig.Region, "gce-region", "", "GCE region being used, if applicable") flags.BoolVar(&cloudConfig.MultiZone, "gce-multizone", false, "If true, start GCE cloud provider with multizone support.") flags.BoolVar(&cloudConfig.MultiMaster, "gce-multimaster", false, "If true, the underlying GCE/GKE cluster is assumed to be multi-master.") @@ -347,7 +349,7 @@ func RegisterClusterFlags(flags *flag.FlagSet) { flags.StringVar(&cloudConfig.ClusterTag, "cluster-tag", "", "Tag used to identify resources. Only required if provider is aws.") flags.StringVar(&cloudConfig.ConfigFile, "cloud-config-file", "", "Cloud config file. Only required if provider is azure or vsphere.") - flags.IntVar(&TestContext.MinStartupPods, "minStartupPods", 0, "The number of pods which we need to see in 'Running' state with a 'Ready' condition of true, before we try running tests. This is useful in any cluster which needs some base pod-based services running before it can be used.") + flags.IntVar(&TestContext.MinStartupPods, "minStartupPods", 0, "The number of pods which we need to see in 'Running' state with a 'Ready' condition of true, before we try running tests. This is useful in any cluster which needs some base pod-based services running before it can be used. If set to -1, no pods are checked and tests run straight away.") flags.DurationVar(&TestContext.SystemPodsStartupTimeout, "system-pods-startup-timeout", 10*time.Minute, "Timeout for waiting for all system pods to be running before starting tests.") flags.DurationVar(&TestContext.NodeSchedulableTimeout, "node-schedulable-timeout", 30*time.Minute, "Timeout for waiting for all nodes to be schedulable.") flags.DurationVar(&TestContext.SystemDaemonsetStartupTimeout, "system-daemonsets-startup-timeout", 5*time.Minute, "Timeout for waiting for all system daemonsets to be ready.") diff --git a/vendor/k8s.io/kubernetes/test/e2e/framework/util.go b/vendor/k8s.io/kubernetes/test/e2e/framework/util.go index c5831027faa7..fec1d3933aa9 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/framework/util.go +++ b/vendor/k8s.io/kubernetes/test/e2e/framework/util.go @@ -1007,8 +1007,11 @@ func getNodeEvents(c clientset.Interface, nodeName string) []v1.Event { // WaitForAllNodesSchedulable waits up to timeout for all // (but TestContext.AllowedNotReadyNodes) to become scheduable. func WaitForAllNodesSchedulable(c clientset.Interface, timeout time.Duration) error { - Logf("Waiting up to %v for all (but %d) nodes to be schedulable", timeout, TestContext.AllowedNotReadyNodes) + if TestContext.AllowedNotReadyNodes == -1 { + return nil + } + Logf("Waiting up to %v for all (but %d) nodes to be schedulable", timeout, TestContext.AllowedNotReadyNodes) return wait.PollImmediate( 30*time.Second, timeout, @@ -1101,11 +1104,16 @@ func RunHostCmdWithRetries(ns, name, cmd string, interval, timeout time.Duration } } -// AllNodesReady checks whether all registered nodes are ready. +// AllNodesReady checks whether all registered nodes are ready. Setting -1 on +// TestContext.AllowedNotReadyNodes will bypass the post test node readiness check. // TODO: we should change the AllNodesReady call in AfterEach to WaitForAllNodesHealthy, // and figure out how to do it in a configurable way, as we can't expect all setups to run // default test add-ons. func AllNodesReady(c clientset.Interface, timeout time.Duration) error { + if TestContext.AllowedNotReadyNodes == -1 { + return nil + } + Logf("Waiting up to %v for all (but %d) nodes to be ready", timeout, TestContext.AllowedNotReadyNodes) var notReady []*v1.Node diff --git a/vendor/k8s.io/kubernetes/test/e2e/generated/bindata.go b/vendor/k8s.io/kubernetes/test/e2e/generated/bindata.go index bd99634bfe77..c202e090a034 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/generated/bindata.go +++ b/vendor/k8s.io/kubernetes/test/e2e/generated/bindata.go @@ -2765,7 +2765,7 @@ func testE2e_nodeTestingManifestsSriovdpSaYaml() (*asset, error) { return a, nil } -var _testImagesMakefile = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x74\x53\xd1\x6e\xe3\x36\x10\x7c\x2e\xbf\x62\x10\xdd\x43\x02\xd8\x72\x62\xa0\x38\xd4\x45\x70\x50\x1c\x35\x11\x92\x93\xae\x92\x72\x41\x9e\x0c\x5a\x5a\x4b\xc4\xd1\xa4\x4a\x52\xb1\x8d\xa2\xff\x5e\x50\x8a\xdb\x3a\x41\xf5\x46\xee\xcc\xec\x68\x76\x19\x60\xa9\xbb\x83\x11\x4d\xeb\x30\xbf\xbc\xfa\x8c\xb2\x25\x3c\xf4\x6b\x32\x8a\x1c\x59\x44\xbd\x6b\xb5\xb1\x21\x0b\x58\x80\x47\x51\x91\xb2\x54\xa3\x57\x35\x19\xb8\x96\x10\x75\xbc\x6a\xe9\x58\x99\xe0\x3b\x19\x2b\xb4\xc2\x3c\xbc\xc4\xb9\x07\x9c\xbd\x95\xce\x2e\x7e\x65\x01\x0e\xba\xc7\x96\x1f\xa0\xb4\x43\x6f\x09\xae\x15\x16\x1b\x21\x09\xb4\xaf\xa8\x73\x10\x0a\x95\xde\x76\x52\x70\x55\x11\x76\xc2\xb5\x43\x9b\x37\x91\x90\x05\x78\x79\x93\xd0\x6b\xc7\x85\x02\x47\xa5\xbb\x03\xf4\xe6\xbf\x38\x70\x37\x18\xf6\x5f\xeb\x5c\xb7\x98\xcd\x76\xbb\x5d\xc8\x07\xb3\xa1\x36\xcd\x4c\x8e\x40\x3b\x7b\x4c\x96\x71\x5a\xc4\xd3\x79\x78\x39\x50\x9e\x94\x24\x6b\x61\xe8\x8f\x5e\x18\xaa\xb1\x3e\x80\x77\x9d\x14\x15\x5f\x4b\x82\xe4\x3b\x68\x03\xde\x18\xa2\x1a\x4e\x7b\xbf\x3b\x23\x9c\x50\xcd\x04\x56\x6f\xdc\x8e\x1b\x62\x01\x6a\x61\x9d\x11\xeb\xde\x9d\x84\x75\x74\x27\xec\x09\x40\x2b\x70\x85\xb3\xa8\x40\x52\x9c\xe1\x26\x2a\x92\x62\xc2\x02\x3c\x27\xe5\x7d\xf6\x54\xe2\x39\xca\xf3\x28\x2d\x93\xb8\x40\x96\x63\x99\xa5\xb7\x49\x99\x64\x69\x81\xec\x37\x44\xe9\x0b\x1e\x92\xf4\x76\x02\x12\xae\x25\x03\xda\x77\xc6\xfb\xd7\x06\xc2\xc7\x48\xb5\xcf\xac\x20\x3a\x31\xb0\xd1\xa3\x21\xdb\x51\x25\x36\xa2\x82\xe4\xaa\xe9\x79\x43\x68\xf4\x2b\x19\x25\x54\x83\x8e\xcc\x56\x58\x3f\x4c\x0b\xae\x6a\x16\x40\x8a\xad\x70\xdc\x0d\x37\x1f\x7e\x2a\x64\x2c\x8f\xef\x92\xa2\xcc\x5f\xf0\xe5\x1a\x4d\x65\x42\xa1\x67\x3f\xfe\xd9\xa4\x29\xcd\x69\xea\xc8\xba\xa9\xd8\xf2\x86\x2c\xbb\xcb\xa2\xfc\xab\x87\x7e\x66\xb7\xd9\xf2\x21\xce\x57\xcb\x38\x2f\x57\x37\x51\x11\xaf\xbe\x45\xe5\x3d\xbe\x5c\xb3\xdf\xe3\xaf\x4f\xdf\xe3\xbc\x48\xb2\xf4\xfa\x75\x1e\xfe\x12\x5e\xb1\xbb\xec\x31\x4a\xef\x56\xc7\xdb\xab\xf0\xea\xe7\xf0\x92\xd1\xbe\xd3\xc6\x31\x26\x36\xaa\xa6\x0d\x9e\xef\xa3\x92\x7d\x3a\x27\x63\xb4\x19\x0e\x3e\x72\xfe\xef\x50\x5f\xb9\x11\x7e\x9e\x13\xd0\x7e\x81\x2d\xff\x41\xe0\x52\x0e\xc8\x6b\x45\xee\x82\x91\xaa\xc5\x86\xb1\x00\x37\xbd\x90\x35\x2a\x5d\xd3\xf8\x04\x22\xd3\xd8\xc5\xb0\x59\x1e\xbc\xc0\xad\x30\x54\x39\x6d\x0e\x50\x7c\x4b\xd6\xaf\xc4\xda\x53\x46\x74\xbc\xe7\xdb\x4e\xd2\x48\x38\x6d\x53\xc9\xde\x3a\x32\xbc\x13\x43\x2a\x64\x18\x97\x72\xe1\xeb\xd3\x4a\x2b\xbf\xda\x64\x18\x3b\x39\x2e\xd8\x4f\xe1\x6c\x48\x6f\xda\x3b\x21\x43\xdb\x8e\xbd\xf0\xe9\xdc\x4b\x5e\x8c\xf0\xae\xb7\xed\x7b\x9d\x0f\x3c\x0f\x3a\xa5\x0d\x4a\x53\xae\xea\x51\xe0\x7f\x5a\xad\xb8\xaa\x57\x23\xf9\x4f\x4f\xfe\x8b\xb1\xf0\xdb\x7d\x96\xbe\x0c\x1d\xf1\x51\x08\x47\x4b\xef\x1c\xfd\x1d\x00\x00\xff\xff\x3b\x8d\xfd\x02\x78\x04\x00\x00") +var _testImagesMakefile = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x74\x53\xd1\x6e\xe3\x36\x10\x7c\x2e\xbf\x62\x10\xdd\x43\x02\xd8\x72\x62\xa0\x38\xd4\x45\x70\x50\x1c\x35\x11\x92\x93\xae\x92\x72\x41\x9e\x0c\x5a\x5a\x4b\xc4\xd1\xa4\x4a\x52\xb1\x8d\xa2\xff\x5e\x50\x8a\xdb\x3a\x41\xf5\x46\xee\xcc\xec\x68\x76\x19\x60\xa9\xbb\x83\x11\x4d\xeb\x30\xbf\xbc\xfa\x8c\xb2\x25\x3c\xf4\x6b\x32\x8a\x1c\x59\x44\xbd\x6b\xb5\xb1\x21\x0b\x58\x80\x47\x51\x91\xb2\x54\xa3\x57\x35\x19\xb8\x96\x10\x75\xbc\x6a\xe9\x58\x99\xe0\x3b\x19\x2b\xb4\xc2\x3c\xbc\xc4\xb9\x07\x9c\xbd\x95\xce\x2e\x7e\x65\x01\x0e\xba\xc7\x96\x1f\xa0\xb4\x43\x6f\x09\xae\x15\x16\x1b\x21\x09\xb4\xaf\xa8\x73\x10\x0a\x95\xde\x76\x52\x70\x55\x11\x76\xc2\xb5\x43\x9b\x37\x91\x90\x05\x78\x79\x93\xd0\x6b\xc7\x85\x02\x47\xa5\xbb\x03\xf4\xe6\xbf\x38\x70\x37\x18\xf6\x5f\xeb\x5c\xb7\x98\xcd\x76\xbb\x5d\xc8\x07\xb3\xa1\x36\xcd\x4c\x8e\x40\x3b\x7b\x4c\x96\x71\x5a\xc4\xd3\x79\x78\x39\x50\x9e\x94\x24\x6b\x61\xe8\x8f\x5e\x18\xaa\xb1\x3e\x80\x77\x9d\x14\x15\x5f\x4b\x82\xe4\x3b\x68\x03\xde\x18\xa2\x1a\x4e\x7b\xbf\x3b\x23\x9c\x50\xcd\x04\x56\x6f\xdc\x8e\x1b\x62\x01\x6a\x61\x9d\x11\xeb\xde\x9d\x84\x75\x74\x27\xec\x09\x40\x2b\x70\x85\xb3\xa8\x40\x52\x9c\xe1\x26\x2a\x92\x62\xc2\x02\x3c\x27\xe5\x7d\xf6\x54\xe2\x39\xca\xf3\x28\x2d\x93\xb8\x40\x96\x63\x99\xa5\xb7\x49\x99\x64\x69\x81\xec\x37\x44\xe9\x0b\x1e\x92\xf4\x76\x02\x12\xae\x25\x03\xda\x77\xc6\xfb\xd7\x06\xc2\xc7\x48\xb5\xcf\xac\x20\x3a\x31\xb0\xd1\xa3\x21\xdb\x51\x25\x36\xa2\x82\xe4\xaa\xe9\x79\x43\x68\xf4\x2b\x19\x25\x54\x83\x8e\xcc\x56\x58\x3f\x4c\x0b\xae\x6a\x16\x40\x8a\xad\x70\xdc\x0d\x37\x1f\x7e\x2a\x64\x2c\x8f\xef\x92\xa2\xcc\x5f\xf0\xe5\x1a\x4d\x65\x42\xa1\x67\x3f\xfe\xd9\xa4\x29\xcd\x69\xea\xc8\xba\xa9\xd8\xf2\x86\x2c\xbb\xcb\xa2\xfc\xab\x87\x7e\x66\xb7\xd9\xf2\x21\xce\x57\xcb\x38\x2f\x57\x37\x51\x11\xaf\xbe\x45\xe5\x3d\xbe\x5c\xb3\xdf\xe3\xaf\x4f\xdf\xe3\xbc\x48\xb2\xf4\xfa\x75\x1e\xfe\x12\x5e\xb1\xbb\xec\x31\x4a\xef\x56\xc7\xdb\xab\xf0\xea\xe7\x70\xce\x68\xdf\x69\xe3\x18\x13\x1b\x55\xd3\x06\xcf\xf7\x51\xc9\x3e\x9d\x93\x31\xda\x0c\x07\x1f\x39\xff\x77\xa8\xaf\xdc\x08\x3f\xcf\x09\x68\xbf\xc0\x96\xff\x20\x70\x29\x07\xe4\xb5\x22\x77\xc1\x48\xd5\x62\xc3\x58\x80\x9b\x5e\xc8\x1a\x95\xae\x69\x7c\x02\x91\x69\xec\x62\xd8\x2c\x0f\x5e\xe0\x56\x18\xaa\x9c\x36\x07\x28\xbe\x25\xeb\x57\x62\xed\x29\x23\x3a\xde\xf3\x6d\x27\x69\x24\x9c\xb6\xa9\x64\x6f\x1d\x19\xde\x89\x21\x15\x32\x8c\x4b\xb9\xf0\xf5\x69\xa5\x95\x5f\x6d\x32\x8c\x9d\x1c\x17\xec\xa7\x70\x36\xa4\x37\xed\x9d\x90\xa1\x6d\xc7\x5e\xf8\x74\xee\x25\x2f\x46\x78\xd7\xdb\xf6\xbd\xce\x07\x9e\x07\x9d\xd2\x06\xa5\x29\x57\xf5\x28\xf0\x3f\xad\x56\x5c\xd5\xab\x91\xfc\xa7\x27\xff\xc5\x58\xf8\xed\x3e\x4b\x5f\x86\x8e\xf8\x28\x84\xa3\xa5\x77\x8e\xfe\x0e\x00\x00\xff\xff\x8e\x41\xcc\xb6\x78\x04\x00\x00") func testImagesMakefileBytes() ([]byte, error) { return bindataRead( @@ -6225,7 +6225,7 @@ func testImagesSampleApiserverBaseimage() (*asset, error) { return a, nil } -var _testImagesSampleApiserverDockerfile = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x54\xef\x4f\xe3\x46\x10\xfd\xee\xbf\xe2\x29\xe6\x43\x2b\x61\x3b\x41\xaa\x0e\x71\x42\xaa\x09\xb9\x60\x1d\xc4\x28\x0e\x77\x42\x6d\x15\x6d\xec\x89\xbd\xc5\xde\x75\xf7\x47\x42\x74\xba\xff\xbd\xda\x35\x70\x50\x2a\x5d\x3e\xc5\xb3\xb3\xf3\xde\xbe\x99\x37\x21\xa6\xb2\x3f\x28\x5e\x37\x06\x27\xe3\xc9\x29\x56\x0d\xe1\xb3\xdd\x90\x12\x64\x48\x23\xb5\xa6\x91\x4a\xc7\x41\x18\x84\xb8\xe6\x25\x09\x4d\x15\xac\xa8\x48\xc1\x34\x84\xb4\x67\x65\x43\xcf\x27\xc7\xf8\x42\x4a\x73\x29\x70\x12\x8f\xf1\x8b\x4b\x18\x3d\x1d\x8d\x7e\xfd\x18\x84\x38\x48\x8b\x8e\x1d\x20\xa4\x81\xd5\x04\xd3\x70\x8d\x2d\x6f\x09\xf4\x58\x52\x6f\xc0\x05\x4a\xd9\xf5\x2d\x67\xa2\x24\xec\xb9\x69\x3c\xcc\x53\x91\x38\x08\x71\xff\x54\x42\x6e\x0c\xe3\x02\x0c\xa5\xec\x0f\x90\xdb\xd7\x79\x60\xc6\x13\x76\xbf\xc6\x98\xfe\x2c\x49\xf6\xfb\x7d\xcc\x3c\xd9\x58\xaa\x3a\x69\x87\x44\x9d\x5c\x67\xd3\xd9\xa2\x98\x45\x27\xf1\xd8\x5f\xb9\x13\x2d\x69\x0d\x45\xff\x58\xae\xa8\xc2\xe6\x00\xd6\xf7\x2d\x2f\xd9\xa6\x25\xb4\x6c\x0f\xa9\xc0\x6a\x45\x54\xc1\x48\xc7\x77\xaf\xb8\xe1\xa2\x3e\x86\x96\x5b\xb3\x67\x8a\x82\x10\x15\xd7\x46\xf1\x8d\x35\x6f\xc4\x7a\x66\xc7\xf5\x9b\x04\x29\xc0\x04\x46\x69\x81\xac\x18\xe1\x22\x2d\xb2\xe2\x38\x08\xf1\x35\x5b\x5d\xe5\x77\x2b\x7c\x4d\x97\xcb\x74\xb1\xca\x66\x05\xf2\x25\xa6\xf9\xe2\x32\x5b\x65\xf9\xa2\x40\xfe\x09\xe9\xe2\x1e\x9f\xb3\xc5\xe5\x31\x88\x9b\x86\x14\xe8\xb1\x57\x8e\xbf\x54\xe0\x4e\x46\xaa\x9c\x66\x05\xd1\x1b\x02\x5b\x39\x10\xd2\x3d\x95\x7c\xcb\x4b\xb4\x4c\xd4\x96\xd5\x84\x5a\xee\x48\x09\x2e\x6a\xf4\xa4\x3a\xae\x5d\x33\x35\x98\xa8\x82\x10\x2d\xef\xb8\x61\xc6\x47\xde\x3d\x2a\x0e\x82\x74\x39\x77\xec\x67\xd9\x4d\x3a\x9f\x05\x9f\x96\xf9\x0d\x1e\x4e\x75\x5c\x97\x2a\xe6\x32\xd9\x58\xde\x56\x11\xef\x58\x4d\xc9\x83\xdd\x50\x54\x2a\xa9\xf5\xd9\x6e\x12\x4f\x7e\x8b\xc7\xd1\x04\x4c\xc3\xe7\xac\x1f\x4e\xf5\x7a\xb2\x9e\x7c\x58\x6b\xd6\xf5\x2d\xad\x59\xcf\x35\xa9\x1d\xa9\x20\x98\x2d\xbe\x60\x9e\xdf\xa6\xab\x2b\x24\xb5\x0c\x96\x77\x0b\x74\x0f\x15\x57\x88\x7a\x1c\x7d\x1b\x4e\xbe\x27\x5a\x95\xaf\xbe\x36\x5c\xf8\x7b\xfe\xd6\xd1\x10\x75\xc1\xb3\x23\xf7\x2f\x08\x82\xd0\x0f\x3d\x9d\x10\x58\x5d\x2b\xaa\x99\x71\xf2\x90\x36\xbe\x51\xa4\x79\x2d\x86\x66\xfb\x18\xdb\xf0\x96\x9b\x83\xfb\x56\x56\x60\xe0\x18\xbd\x70\x74\xcf\x60\xe2\xa5\x12\x55\x18\xe2\xae\x0d\x9a\x06\x18\x5f\x47\xb0\x8e\x2a\x8c\x8a\x46\xda\xb6\xc2\x86\xe0\x07\xcc\x48\x68\xdb\xf7\x52\x19\x2f\xee\x24\x9e\x7c\x40\xe1\x21\x90\xde\x66\x28\x06\x0c\xab\x5d\x87\x5c\x42\x69\x95\x22\x61\x90\xbe\x30\x1f\xb9\x07\x5d\x38\x21\xe1\xb4\xfd\x10\x8f\x5d\x51\x12\xda\x2a\x7a\x73\x45\x51\x4b\x4c\xd3\x33\x9e\x06\x43\xaf\xb8\x54\xd8\x3d\x79\xf8\xc9\x53\xc3\x0b\xf1\xa3\x0b\x21\xe6\x64\xbc\x37\xa5\x35\x43\xcf\x3c\x1d\x89\x5e\xf6\xb6\x65\x86\xd0\xc9\xca\xb6\x84\xd2\xf9\xcd\x77\x69\x9e\x4f\x26\x93\x9b\xfc\xf2\xee\x7a\x76\x2e\x05\x6a\x89\x9a\x0c\xa2\xca\x4f\x08\x97\xc9\x7f\x65\xfc\x7d\x37\xf6\xdc\x5f\x81\x21\x2f\x92\x74\x39\xbd\x8a\x5e\xa6\x96\xc4\xce\xa1\x7a\x06\xff\x87\x32\x9d\xe7\xeb\xd9\x22\xbd\xb8\x9e\x5d\x9e\x8f\x31\xcf\xf3\xe2\xbc\xe5\xc2\x3e\x62\x9e\xbb\x42\xe7\x6e\x58\xdd\x9f\x67\x3a\x3f\xe3\x12\x84\xde\x39\x4c\x75\xc7\xee\x0a\x17\xda\xb0\xb6\x75\x8b\x4c\xa3\x96\x6e\xa6\x12\x5f\x7f\xed\x33\xb4\xc4\xdf\x56\x1b\x6c\xb9\xa8\xbc\x90\x7e\xcf\x31\x51\x0d\x1b\x8b\x1b\x3f\x52\x0d\x41\x49\x69\xa0\x65\x10\x62\xef\x24\x13\x2f\xe7\x4e\xde\xad\x92\xdd\xb0\x26\x4d\xa3\xe4\x1e\x6c\xcf\x0e\x28\xa5\x70\xcb\x8f\x9c\xc9\x9d\x6b\x7d\x12\x83\x36\x4c\x54\x4c\x55\x68\x65\xe9\x7d\xea\x45\xf1\xf8\xc9\xc0\x0f\x91\x1b\xbb\xf7\x43\x1b\xd1\x23\x95\x28\x7b\x7c\xfb\x8e\x04\x7f\x7e\x0c\x06\xfb\x1e\xfd\xb0\xf3\x34\xbf\xbd\x47\x14\x39\xa4\xf3\x9f\xd8\x14\xef\x14\x7c\x1f\x71\x56\x5e\x2d\xef\x6f\xf3\x6c\xb1\xc2\x1f\xa3\x77\xe7\xa3\xbf\x82\x7f\x03\x00\x00\xff\xff\x2b\x22\x73\x84\x9b\x06\x00\x00") +var _testImagesSampleApiserverDockerfile = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x84\x54\xef\x4f\xe3\x46\x10\xfd\xee\xbf\xe2\x29\xe6\x43\x2b\x61\x3b\x41\xaa\x0e\x71\x42\xaa\x09\xb9\x60\x1d\xc4\x28\x0e\x77\x42\x6d\x15\x6d\xec\x89\xbd\xc5\xde\x75\xf7\x47\x42\x74\xba\xff\xbd\xda\x35\x70\x50\x2a\x5d\x3e\xc5\xb3\xb3\xf3\xde\xbe\x99\x37\x21\xa6\xb2\x3f\x28\x5e\x37\x06\x27\xe3\xc9\x29\x56\x0d\xe1\xb3\xdd\x90\x12\x64\x48\x23\xb5\xa6\x91\x4a\xc7\x41\x18\x84\xb8\xe6\x25\x09\x4d\x15\xac\xa8\x48\xc1\x34\x84\xb4\x67\x65\x43\xcf\x27\xc7\xf8\x42\x4a\x73\x29\x70\x12\x8f\xf1\x8b\x4b\x18\x3d\x1d\x8d\x7e\xfd\x18\x84\x38\x48\x8b\x8e\x1d\x20\xa4\x81\xd5\x04\xd3\x70\x8d\x2d\x6f\x09\xf4\x58\x52\x6f\xc0\x05\x4a\xd9\xf5\x2d\x67\xa2\x24\xec\xb9\x69\x3c\xcc\x53\x91\x38\x08\x71\xff\x54\x42\x6e\x0c\xe3\x02\x0c\xa5\xec\x0f\x90\xdb\xd7\x79\x60\xc6\x13\x76\xbf\xc6\x98\xfe\x2c\x49\xf6\xfb\x7d\xcc\x3c\xd9\x58\xaa\x3a\x69\x87\x44\x9d\x5c\x67\xd3\xd9\xa2\x98\x45\x27\xf1\xd8\x5f\xb9\x13\x2d\x69\x0d\x45\xff\x58\xae\xa8\xc2\xe6\x00\xd6\xf7\x2d\x2f\xd9\xa6\x25\xb4\x6c\x0f\xa9\xc0\x6a\x45\x54\xc1\x48\xc7\x77\xaf\xb8\xe1\xa2\x3e\x86\x96\x5b\xb3\x67\x8a\x82\x10\x15\xd7\x46\xf1\x8d\x35\x6f\xc4\x7a\x66\xc7\xf5\x9b\x04\x29\xc0\x04\x46\x69\x81\xac\x18\xe1\x22\x2d\xb2\xe2\x38\x08\xf1\x35\x5b\x5d\xe5\x77\x2b\x7c\x4d\x97\xcb\x74\xb1\xca\x66\x05\xf2\x25\xa6\xf9\xe2\x32\x5b\x65\xf9\xa2\x40\xfe\x09\xe9\xe2\x1e\x9f\xb3\xc5\xe5\x31\x88\x9b\x86\x14\xe8\xb1\x57\x8e\xbf\x54\xe0\x4e\x46\xaa\x9c\x66\x05\xd1\x1b\x02\x5b\x39\x10\xd2\x3d\x95\x7c\xcb\x4b\xb4\x4c\xd4\x96\xd5\x84\x5a\xee\x48\x09\x2e\x6a\xf4\xa4\x3a\xae\x5d\x33\x35\x98\xa8\x82\x10\x2d\xef\xb8\x61\xc6\x47\xde\x3d\x2a\x0e\x82\x74\x39\x77\xec\x67\xd9\x4d\x3a\x9f\x05\x9f\x96\xf9\x0d\x1e\x4e\x75\x5c\x97\x2a\xe6\x32\xd9\x58\xde\x56\x11\xef\x58\x4d\xc9\x83\xdd\x50\x54\x2a\xa9\xf5\xd9\x6e\x12\x4f\x7e\x8b\x4f\xa2\x09\x98\x86\xcf\x59\x3f\x9c\xea\xf5\x64\x3d\xf9\xb0\xd6\xac\xeb\x5b\x5a\xb3\x9e\x6b\x52\x3b\x52\x41\x30\x5b\x7c\xc1\x3c\xbf\x4d\x57\x57\x48\x6a\x19\x2c\xef\x16\xe8\x1e\x2a\xae\x10\xf5\x38\xfa\x36\x9c\x7c\x4f\xb4\x2a\x5f\x7d\x6d\xb8\xf0\xf7\xfc\xad\xa3\x21\xea\x82\x67\x47\xee\x5f\x10\x04\xa1\x1f\x7a\x3a\x21\xb0\xba\x56\x54\x33\xe3\xe4\x21\x6d\x7c\xa3\x48\xf3\x5a\x0c\xcd\xf6\x31\xb6\xe1\x2d\x37\x07\xf7\xad\xac\xc0\xc0\x31\x7a\xe1\xe8\x9e\xc1\xc4\x4b\x25\xaa\x30\xc4\x5d\x1b\x34\x0d\x30\xbe\x8e\x60\x1d\x55\x18\x15\x8d\xb4\x6d\x85\x0d\xc1\x0f\x98\x91\xd0\xb6\xef\xa5\x32\x5e\xdc\x49\x3c\xf9\x80\xc2\x43\x20\xbd\xcd\x50\x0c\x18\x56\xbb\x0e\xb9\x84\xd2\x2a\x45\xc2\x20\x7d\x61\x3e\x72\x0f\xba\x70\x42\xc2\x69\xfb\x21\x1e\xbb\xa2\x24\xb4\x55\xf4\xe6\x8a\xa2\x96\x98\xa6\x67\x3c\x0d\x86\x5e\x71\xa9\xb0\x7b\xf2\xf0\x93\xa7\x86\x17\xe2\x47\x17\x42\xcc\xc9\x78\x6f\x4a\x6b\x86\x9e\x79\x3a\x12\xbd\xec\x6d\xcb\x0c\xa1\x93\x95\x6d\x09\xa5\xf3\x9b\xef\xd2\x3c\x9f\x4c\x26\x37\xf9\xe5\xdd\xf5\xec\x5c\x0a\xd4\x12\x35\x19\x44\x95\x9f\x10\x2e\x93\xff\xca\xf8\xfb\x6e\xec\xb9\xbf\x02\x43\x5e\x24\xe9\x72\x7a\x15\xbd\x4c\x2d\x89\x9d\x43\xf5\x0c\xfe\x0f\x65\x3a\xcf\xd7\xb3\x45\x7a\x71\x3d\xbb\x3c\x1f\x63\x9e\xe7\xc5\x79\xcb\x85\x7d\xc4\x3c\x77\x85\xce\xdd\xb0\xba\x3f\xcf\x74\x7e\xc6\x25\x08\xbd\x73\x98\xea\x8e\xdd\x15\x2e\xb4\x61\x6d\xeb\x16\x99\x46\x2d\xdd\x4c\x25\xbe\xfe\xda\x67\x68\x89\xbf\xad\x36\xd8\x72\x51\x79\x21\xfd\x9e\x63\xa2\x1a\x36\x16\x37\x7e\xa4\x1a\x82\x92\xd2\x40\xcb\x20\xc4\xde\x49\x26\x5e\xce\x9d\xbc\x5b\x25\xbb\x61\x4d\x9a\x46\xc9\x3d\xd8\x9e\x1d\x50\x4a\xe1\x96\x1f\x39\x93\x3b\xd7\xfa\x24\x06\x6d\x98\xa8\x98\xaa\xd0\xca\xd2\xfb\xd4\x8b\xe2\xf1\x93\x81\x1f\x22\x37\x76\xef\x87\x36\xa2\x47\x2a\x51\xf6\xf8\xf6\x1d\x09\xfe\xfc\x18\x0c\xf6\x3d\xfa\x61\xe7\x69\x7e\x7b\x8f\x28\x72\x48\xe7\x3f\xb1\x29\xde\x29\xf8\x3e\xe2\xac\xbc\x5a\xde\xdf\xe6\xd9\x62\x85\x3f\x46\xef\xce\x47\x7f\x05\xff\x06\x00\x00\xff\xff\xd5\x5c\x5b\xe6\x9b\x06\x00\x00") func testImagesSampleApiserverDockerfileBytes() ([]byte, error) { return bindataRead( diff --git a/vendor/k8s.io/kubernetes/test/e2e/network/network_policy.go b/vendor/k8s.io/kubernetes/test/e2e/network/network_policy.go index 29a9895ad53d..2835b289f983 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/network/network_policy.go +++ b/vendor/k8s.io/kubernetes/test/e2e/network/network_policy.go @@ -19,6 +19,8 @@ package network import ( "context" "encoding/json" + "fmt" + "net" v1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" @@ -31,8 +33,7 @@ import ( e2epod "k8s.io/kubernetes/test/e2e/framework/pod" e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper" imageutils "k8s.io/kubernetes/test/utils/image" - - "fmt" + utilnet "k8s.io/utils/net" "github.com/onsi/ginkgo" ) @@ -1373,8 +1374,11 @@ var _ = SIGDescribe("NetworkPolicy [LinuxOnly]", func() { if err != nil { framework.ExpectNoError(err, "Error occurred while getting pod status.") } - - podServerCIDR := fmt.Sprintf("%s/32", podServerStatus.Status.PodIP) + hostMask := 32 + if utilnet.IsIPv6String(podServerStatus.Status.PodIP) { + hostMask = 128 + } + podServerCIDR := fmt.Sprintf("%s/%d", podServerStatus.Status.PodIP, hostMask) // Creating pod-b and service-b podServerB, serviceB = createServerPodAndService(f, f.Namespace, "pod-b", []int{80}) @@ -1450,9 +1454,18 @@ var _ = SIGDescribe("NetworkPolicy [LinuxOnly]", func() { framework.ExpectNoError(err, "Error occurred while getting pod status.") } - podServerAllowCIDR := fmt.Sprintf("%s/24", podServerStatus.Status.PodIP) + allowMask := 24 + hostMask := 32 + if utilnet.IsIPv6String(podServerStatus.Status.PodIP) { + allowMask = 64 + hostMask = 128 + } + _, podServerAllowSubnet, err := net.ParseCIDR(fmt.Sprintf("%s/%d", podServerStatus.Status.PodIP, allowMask)) + framework.ExpectNoError(err, "could not parse allow subnet") + podServerAllowCIDR := podServerAllowSubnet.String() + // Exclude podServer's IP with an Except clause - podServerExceptList := []string{fmt.Sprintf("%s/32", podServerStatus.Status.PodIP)} + podServerExceptList := []string{fmt.Sprintf("%s/%d", podServerStatus.Status.PodIP, hostMask)} // client-a can connect to server prior to applying the NetworkPolicy ginkgo.By("Creating client-a which should be able to contact the server.", func() { @@ -1515,10 +1528,19 @@ var _ = SIGDescribe("NetworkPolicy [LinuxOnly]", func() { framework.ExpectNoError(err, "Error occurred while getting pod status.") } - podServerAllowCIDR := fmt.Sprintf("%s/24", podServerStatus.Status.PodIP) - podServerIP := fmt.Sprintf("%s/32", podServerStatus.Status.PodIP) + allowMask := 24 + hostMask := 32 + if utilnet.IsIPv6String(podServerStatus.Status.PodIP) { + allowMask = 64 + hostMask = 128 + } + _, podServerAllowSubnet, err := net.ParseCIDR(fmt.Sprintf("%s/%d", podServerStatus.Status.PodIP, allowMask)) + framework.ExpectNoError(err, "could not parse allow subnet") + podServerAllowCIDR := podServerAllowSubnet.String() + // Exclude podServer's IP with an Except clause - podServerExceptList := []string{podServerIP} + podServerCIDR := fmt.Sprintf("%s/%d", podServerStatus.Status.PodIP, hostMask) + podServerExceptList := []string{podServerCIDR} // Create NetworkPolicy which blocks access to podServer with except clause. policyAllowCIDRWithExceptServerPod := &networkingv1.NetworkPolicy{ @@ -1595,7 +1617,7 @@ var _ = SIGDescribe("NetworkPolicy [LinuxOnly]", func() { To: []networkingv1.NetworkPolicyPeer{ { IPBlock: &networkingv1.IPBlock{ - CIDR: podServerIP, + CIDR: podServerCIDR, }, }, }, diff --git a/vendor/k8s.io/kubernetes/test/e2e/node/BUILD b/vendor/k8s.io/kubernetes/test/e2e/node/BUILD index 68a9a95b4e8e..b087ebbf7124 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/node/BUILD +++ b/vendor/k8s.io/kubernetes/test/e2e/node/BUILD @@ -26,6 +26,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//pkg/kubelet/apis/stats/v1alpha1:go_default_library", + "//pkg/kubelet/events:go_default_library", "//pkg/kubelet/runtimeclass/testing:go_default_library", "//pkg/master/ports:go_default_library", "//pkg/util/slice:go_default_library", diff --git a/vendor/k8s.io/kubernetes/test/e2e/node/pods.go b/vendor/k8s.io/kubernetes/test/e2e/node/pods.go index f863f7c4bf11..583eeb96f089 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/node/pods.go +++ b/vendor/k8s.io/kubernetes/test/e2e/node/pods.go @@ -31,10 +31,12 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/uuid" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/watch" + "k8s.io/kubernetes/pkg/kubelet/events" "k8s.io/kubernetes/test/e2e/framework" e2ekubelet "k8s.io/kubernetes/test/e2e/framework/kubelet" e2epod "k8s.io/kubernetes/test/e2e/framework/pod" @@ -274,6 +276,7 @@ var _ = SIGDescribe("Pods Extended", func() { start := time.Now() created := podClient.Create(pod) ch := make(chan []watch.Event) + waitForWatch := make(chan struct{}) go func() { defer ginkgo.GinkgoRecover() defer close(ch) @@ -286,6 +289,7 @@ var _ = SIGDescribe("Pods Extended", func() { return } defer w.Stop() + close(waitForWatch) events := []watch.Event{ {Type: watch.Added, Object: created}, } @@ -302,6 +306,10 @@ var _ = SIGDescribe("Pods Extended", func() { ch <- events }() + select { + case <-ch: // in case the goroutine above exits before establishing the watch + case <-waitForWatch: // when the watch is established + } t := time.Duration(rand.Intn(delay)) * time.Millisecond time.Sleep(t) err := podClient.Delete(context.TODO(), pod.Name, metav1.DeleteOptions{}) @@ -445,5 +453,83 @@ var _ = SIGDescribe("Pods Extended", func() { framework.Failf("%d errors:\n%v", len(errs), strings.Join(messages, "\n")) } }) + + }) + + framework.KubeDescribe("Pod Container lifecycle", func() { + var podClient *framework.PodClient + ginkgo.BeforeEach(func() { + podClient = f.PodClient() + }) + + ginkgo.It("should not create extra sandbox if all containers are done", func() { + ginkgo.By("creating the pod that should always exit 0") + + name := "pod-always-succeed" + string(uuid.NewUUID()) + image := imageutils.GetE2EImage(imageutils.BusyBox) + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: v1.PodSpec{ + RestartPolicy: v1.RestartPolicyOnFailure, + InitContainers: []v1.Container{ + { + Name: "foo", + Image: image, + Command: []string{ + "/bin/true", + }, + }, + }, + Containers: []v1.Container{ + { + Name: "bar", + Image: image, + Command: []string{ + "/bin/true", + }, + }, + }, + }, + } + + ginkgo.By("submitting the pod to kubernetes") + createdPod := podClient.Create(pod) + defer func() { + ginkgo.By("deleting the pod") + podClient.Delete(context.TODO(), pod.Name, metav1.DeleteOptions{}) + }() + + framework.ExpectNoError(e2epod.WaitForPodSuccessInNamespace(f.ClientSet, pod.Name, f.Namespace.Name)) + + var eventList *v1.EventList + var err error + ginkgo.By("Getting events about the pod") + framework.ExpectNoError(wait.Poll(time.Second*2, time.Second*60, func() (bool, error) { + selector := fields.Set{ + "involvedObject.kind": "Pod", + "involvedObject.uid": string(createdPod.UID), + "involvedObject.namespace": f.Namespace.Name, + "source": "kubelet", + }.AsSelector().String() + options := metav1.ListOptions{FieldSelector: selector} + eventList, err = f.ClientSet.CoreV1().Events(f.Namespace.Name).List(context.TODO(), options) + if err != nil { + return false, err + } + if len(eventList.Items) > 0 { + return true, nil + } + return false, nil + })) + + ginkgo.By("Checking events about the pod") + for _, event := range eventList.Items { + if event.Reason == events.SandboxChanged { + framework.Fail("Unexpected SandboxChanged event") + } + } + }) }) }) diff --git a/vendor/k8s.io/kubernetes/test/e2e/storage/persistent_volumes.go b/vendor/k8s.io/kubernetes/test/e2e/storage/persistent_volumes.go index 6e80e620ce8f..94a189f61557 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/storage/persistent_volumes.go +++ b/vendor/k8s.io/kubernetes/test/e2e/storage/persistent_volumes.go @@ -307,6 +307,11 @@ var _ = utils.SIGDescribe("PersistentVolumes", func() { framework.ExpectNoError(e2epod.DeletePodWithWait(c, pod)) framework.Logf("Pod exited without failure; the volume has been recycled.") + + // Delete the PVC and wait for the recycler to finish before the NFS server gets shutdown during cleanup. + framework.Logf("Removing second PVC, waiting for the recycler to finish before cleanup.") + framework.ExpectNoError(e2epv.DeletePVCandValidatePV(c, ns, pvc, pv, v1.VolumeAvailable)) + pvc = nil }) }) }) diff --git a/vendor/k8s.io/kubernetes/test/e2e/storage/testsuites/base.go b/vendor/k8s.io/kubernetes/test/e2e/storage/testsuites/base.go index aafbb630f2b2..7519d0a0806b 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/storage/testsuites/base.go +++ b/vendor/k8s.io/kubernetes/test/e2e/storage/testsuites/base.go @@ -149,50 +149,36 @@ func skipUnsupportedTest(driver TestDriver, pattern testpatterns.TestPattern) { dInfo := driver.GetDriverInfo() var isSupported bool - // 1. Check if Whether SnapshotType is supported by driver from its interface - // if isSupported, we still execute the driver and suite tests - if len(pattern.SnapshotType) > 0 { - switch pattern.SnapshotType { - case testpatterns.DynamicCreatedSnapshot: - _, isSupported = driver.(SnapshottableTestDriver) - default: - isSupported = false - } - if !isSupported { - e2eskipper.Skipf("Driver %s doesn't support snapshot type %v -- skipping", dInfo.Name, pattern.SnapshotType) - } - } else { - // 2. Check if Whether volType is supported by driver from its interface - switch pattern.VolType { - case testpatterns.InlineVolume: - _, isSupported = driver.(InlineVolumeTestDriver) - case testpatterns.PreprovisionedPV: - _, isSupported = driver.(PreprovisionedPVTestDriver) - case testpatterns.DynamicPV, testpatterns.GenericEphemeralVolume: - _, isSupported = driver.(DynamicPVTestDriver) - case testpatterns.CSIInlineVolume: - _, isSupported = driver.(EphemeralTestDriver) - default: - isSupported = false - } + // 1. Check if Whether volType is supported by driver from its interface + switch pattern.VolType { + case testpatterns.InlineVolume: + _, isSupported = driver.(InlineVolumeTestDriver) + case testpatterns.PreprovisionedPV: + _, isSupported = driver.(PreprovisionedPVTestDriver) + case testpatterns.DynamicPV, testpatterns.GenericEphemeralVolume: + _, isSupported = driver.(DynamicPVTestDriver) + case testpatterns.CSIInlineVolume: + _, isSupported = driver.(EphemeralTestDriver) + default: + isSupported = false + } - if !isSupported { - e2eskipper.Skipf("Driver %s doesn't support %v -- skipping", dInfo.Name, pattern.VolType) - } + if !isSupported { + e2eskipper.Skipf("Driver %s doesn't support %v -- skipping", dInfo.Name, pattern.VolType) + } - // 3. Check if fsType is supported - if !dInfo.SupportedFsType.Has(pattern.FsType) { - e2eskipper.Skipf("Driver %s doesn't support %v -- skipping", dInfo.Name, pattern.FsType) - } - if pattern.FsType == "xfs" && framework.NodeOSDistroIs("gci", "cos", "windows") { - e2eskipper.Skipf("Distro doesn't support xfs -- skipping") - } - if pattern.FsType == "ntfs" && !framework.NodeOSDistroIs("windows") { - e2eskipper.Skipf("Distro %s doesn't support ntfs -- skipping", framework.TestContext.NodeOSDistro) - } + // 2. Check if fsType is supported + if !dInfo.SupportedFsType.Has(pattern.FsType) { + e2eskipper.Skipf("Driver %s doesn't support %v -- skipping", dInfo.Name, pattern.FsType) + } + if pattern.FsType == "xfs" && framework.NodeOSDistroIs("gci", "cos", "windows") { + e2eskipper.Skipf("Distro doesn't support xfs -- skipping") + } + if pattern.FsType == "ntfs" && !framework.NodeOSDistroIs("windows") { + e2eskipper.Skipf("Distro %s doesn't support ntfs -- skipping", framework.TestContext.NodeOSDistro) } - // 4. Check with driver specific logic + // 3. Check with driver specific logic driver.SkipUnsupportedTest(pattern) } diff --git a/vendor/k8s.io/kubernetes/test/e2e/storage/testsuites/multivolume.go b/vendor/k8s.io/kubernetes/test/e2e/storage/testsuites/multivolume.go index 6934bd2a400a..e4cc1640ad25 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/storage/testsuites/multivolume.go +++ b/vendor/k8s.io/kubernetes/test/e2e/storage/testsuites/multivolume.go @@ -35,6 +35,7 @@ import ( e2evolume "k8s.io/kubernetes/test/e2e/framework/volume" "k8s.io/kubernetes/test/e2e/storage/testpatterns" "k8s.io/kubernetes/test/e2e/storage/utils" + imageutils "k8s.io/kubernetes/test/utils/image" ) type multiVolumeTestSuite struct { @@ -423,14 +424,14 @@ func testAccessMultipleVolumes(f *framework.Framework, cs clientset.Interface, n if readSeedBase > 0 { ginkgo.By(fmt.Sprintf("Checking if read from the volume%d works properly", index)) - utils.CheckReadFromPath(f, pod, *pvc.Spec.VolumeMode, path, byteLen, readSeedBase+int64(i)) + utils.CheckReadFromPath(f, pod, *pvc.Spec.VolumeMode, false, path, byteLen, readSeedBase+int64(i)) } ginkgo.By(fmt.Sprintf("Checking if write to the volume%d works properly", index)) - utils.CheckWriteToPath(f, pod, *pvc.Spec.VolumeMode, path, byteLen, writeSeedBase+int64(i)) + utils.CheckWriteToPath(f, pod, *pvc.Spec.VolumeMode, false, path, byteLen, writeSeedBase+int64(i)) ginkgo.By(fmt.Sprintf("Checking if read from the volume%d works properly", index)) - utils.CheckReadFromPath(f, pod, *pvc.Spec.VolumeMode, path, byteLen, writeSeedBase+int64(i)) + utils.CheckReadFromPath(f, pod, *pvc.Spec.VolumeMode, false, path, byteLen, writeSeedBase+int64(i)) } pod, err = cs.CoreV1().Pods(pod.Namespace).Get(context.TODO(), pod.Name, metav1.GetOptions{}) @@ -481,6 +482,7 @@ func TestConcurrentAccessToSingleVolume(f *framework.Framework, cs clientset.Int ginkgo.By(fmt.Sprintf("Creating pod%d with a volume on %+v", index, node)) podConfig := e2epod.Config{ NS: ns, + ImageID: imageutils.DebianIptables, PVCs: []*v1.PersistentVolumeClaim{pvc}, SeLinuxLabel: e2epv.SELinuxLabel, NodeSelection: node, @@ -506,6 +508,14 @@ func TestConcurrentAccessToSingleVolume(f *framework.Framework, cs clientset.Int var seed int64 byteLen := 64 + directIO := false + // direct IO is needed for Block-mode PVs + if *pvc.Spec.VolumeMode == v1.PersistentVolumeBlock { + // byteLen should be the size of a sector to enable direct I/O + byteLen = 512 + directIO = true + } + path := "/mnt/volume1" // Check if volume can be accessed from each pod for i, pod := range pods { @@ -521,17 +531,17 @@ func TestConcurrentAccessToSingleVolume(f *framework.Framework, cs clientset.Int if i != 0 { ginkgo.By(fmt.Sprintf("From pod%d, checking if reading the data that pod%d write works properly", index, index-1)) // For 1st pod, no one has written data yet, so pass the read check - utils.CheckReadFromPath(f, pod, *pvc.Spec.VolumeMode, path, byteLen, seed) + utils.CheckReadFromPath(f, pod, *pvc.Spec.VolumeMode, directIO, path, byteLen, seed) } // Update the seed and check if write/read works properly seed = time.Now().UTC().UnixNano() ginkgo.By(fmt.Sprintf("Checking if write to the volume in pod%d works properly", index)) - utils.CheckWriteToPath(f, pod, *pvc.Spec.VolumeMode, path, byteLen, seed) + utils.CheckWriteToPath(f, pod, *pvc.Spec.VolumeMode, directIO, path, byteLen, seed) ginkgo.By(fmt.Sprintf("Checking if read from the volume in pod%d works properly", index)) - utils.CheckReadFromPath(f, pod, *pvc.Spec.VolumeMode, path, byteLen, seed) + utils.CheckReadFromPath(f, pod, *pvc.Spec.VolumeMode, directIO, path, byteLen, seed) } // Delete the last pod and remove from slice of pods @@ -560,16 +570,16 @@ func TestConcurrentAccessToSingleVolume(f *framework.Framework, cs clientset.Int } else { ginkgo.By(fmt.Sprintf("From pod%d, rechecking if reading the data that pod%d write works properly", index, index-1)) } - utils.CheckReadFromPath(f, pod, *pvc.Spec.VolumeMode, path, byteLen, seed) + utils.CheckReadFromPath(f, pod, *pvc.Spec.VolumeMode, directIO, path, byteLen, seed) // Update the seed and check if write/read works properly seed = time.Now().UTC().UnixNano() ginkgo.By(fmt.Sprintf("Rechecking if write to the volume in pod%d works properly", index)) - utils.CheckWriteToPath(f, pod, *pvc.Spec.VolumeMode, path, byteLen, seed) + utils.CheckWriteToPath(f, pod, *pvc.Spec.VolumeMode, directIO, path, byteLen, seed) ginkgo.By(fmt.Sprintf("Rechecking if read from the volume in pod%d works properly", index)) - utils.CheckReadFromPath(f, pod, *pvc.Spec.VolumeMode, path, byteLen, seed) + utils.CheckReadFromPath(f, pod, *pvc.Spec.VolumeMode, directIO, path, byteLen, seed) } } diff --git a/vendor/k8s.io/kubernetes/test/e2e/storage/utils/utils.go b/vendor/k8s.io/kubernetes/test/e2e/storage/utils/utils.go index e6ac7027b306..7ef722284e50 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/storage/utils/utils.go +++ b/vendor/k8s.io/kubernetes/test/e2e/storage/utils/utils.go @@ -241,13 +241,13 @@ func TestKubeletRestartsAndRestoresMount(c clientset.Interface, f *framework.Fra seed := time.Now().UTC().UnixNano() ginkgo.By("Writing to the volume.") - CheckWriteToPath(f, clientPod, v1.PersistentVolumeFilesystem, path, byteLen, seed) + CheckWriteToPath(f, clientPod, v1.PersistentVolumeFilesystem, false, path, byteLen, seed) ginkgo.By("Restarting kubelet") KubeletCommand(KRestart, c, clientPod) ginkgo.By("Testing that written file is accessible.") - CheckReadFromPath(f, clientPod, v1.PersistentVolumeFilesystem, path, byteLen, seed) + CheckReadFromPath(f, clientPod, v1.PersistentVolumeFilesystem, false, path, byteLen, seed) framework.Logf("Volume mount detected on pod %s and written file %s is readable post-restart.", clientPod.Name, path) } @@ -259,13 +259,13 @@ func TestKubeletRestartsAndRestoresMap(c clientset.Interface, f *framework.Frame seed := time.Now().UTC().UnixNano() ginkgo.By("Writing to the volume.") - CheckWriteToPath(f, clientPod, v1.PersistentVolumeBlock, path, byteLen, seed) + CheckWriteToPath(f, clientPod, v1.PersistentVolumeBlock, false, path, byteLen, seed) ginkgo.By("Restarting kubelet") KubeletCommand(KRestart, c, clientPod) ginkgo.By("Testing that written pv is accessible.") - CheckReadFromPath(f, clientPod, v1.PersistentVolumeBlock, path, byteLen, seed) + CheckReadFromPath(f, clientPod, v1.PersistentVolumeBlock, false, path, byteLen, seed) framework.Logf("Volume map detected on pod %s and written data %s is readable post-restart.", clientPod.Name, path) } @@ -656,33 +656,54 @@ func genBinDataFromSeed(len int, seed int64) []byte { } // CheckReadFromPath validate that file can be properly read. -func CheckReadFromPath(f *framework.Framework, pod *v1.Pod, volMode v1.PersistentVolumeMode, path string, len int, seed int64) { +// +// Note: directIO does not work with (default) BusyBox Pods. A requirement for +// directIO to function correctly, is to read whole sector(s) for Block-mode +// PVCs (normally a sector is 512 bytes), or memory pages for files (commonly +// 4096 bytes). +func CheckReadFromPath(f *framework.Framework, pod *v1.Pod, volMode v1.PersistentVolumeMode, directIO bool, path string, len int, seed int64) { var pathForVolMode string + var iflag string + if volMode == v1.PersistentVolumeBlock { pathForVolMode = path } else { pathForVolMode = filepath.Join(path, "file1.txt") } + if directIO { + iflag = "iflag=direct" + } + sum := sha256.Sum256(genBinDataFromSeed(len, seed)) - VerifyExecInPodSucceed(f, pod, fmt.Sprintf("dd if=%s bs=%d count=1 | sha256sum", pathForVolMode, len)) - VerifyExecInPodSucceed(f, pod, fmt.Sprintf("dd if=%s bs=%d count=1 | sha256sum | grep -Fq %x", pathForVolMode, len, sum)) + VerifyExecInPodSucceed(f, pod, fmt.Sprintf("dd if=%s %s bs=%d count=1 | sha256sum", pathForVolMode, iflag, len)) + VerifyExecInPodSucceed(f, pod, fmt.Sprintf("dd if=%s %s bs=%d count=1 | sha256sum | grep -Fq %x", pathForVolMode, iflag, len, sum)) } // CheckWriteToPath that file can be properly written. -func CheckWriteToPath(f *framework.Framework, pod *v1.Pod, volMode v1.PersistentVolumeMode, path string, len int, seed int64) { +// +// Note: nocache does not work with (default) BusyBox Pods. To read without +// caching, enable directIO with CheckReadFromPath and check the hints about +// the len requirements. +func CheckWriteToPath(f *framework.Framework, pod *v1.Pod, volMode v1.PersistentVolumeMode, nocache bool, path string, len int, seed int64) { var pathForVolMode string + var oflag string + if volMode == v1.PersistentVolumeBlock { pathForVolMode = path } else { pathForVolMode = filepath.Join(path, "file1.txt") } + if nocache { + oflag = "oflag=nocache" + } + encoded := base64.StdEncoding.EncodeToString(genBinDataFromSeed(len, seed)) VerifyExecInPodSucceed(f, pod, fmt.Sprintf("echo %s | base64 -d | sha256sum", encoded)) - VerifyExecInPodSucceed(f, pod, fmt.Sprintf("echo %s | base64 -d | dd of=%s bs=%d count=1", encoded, pathForVolMode, len)) + VerifyExecInPodSucceed(f, pod, fmt.Sprintf("echo %s | base64 -d | dd of=%s %s bs=%d count=1", encoded, pathForVolMode, oflag, len)) } // findMountPoints returns all mount points on given node under specified directory. diff --git a/vendor/k8s.io/kubernetes/test/e2e/upgrades/BUILD b/vendor/k8s.io/kubernetes/test/e2e/upgrades/BUILD index 3bece0cc2e40..72ad542dc159 100644 --- a/vendor/k8s.io/kubernetes/test/e2e/upgrades/BUILD +++ b/vendor/k8s.io/kubernetes/test/e2e/upgrades/BUILD @@ -17,6 +17,7 @@ go_library( "mysql.go", "nvidia-gpu.go", "secrets.go", + "serviceaccount_admission_controller_migration.go", "services.go", "sysctl.go", "upgrade.go", @@ -34,11 +35,13 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/client-go/kubernetes:go_default_library", + "//test/e2e/auth:go_default_library", "//test/e2e/framework:go_default_library", "//test/e2e/framework/autoscaling:go_default_library", "//test/e2e/framework/job:go_default_library", "//test/e2e/framework/kubectl:go_default_library", "//test/e2e/framework/node:go_default_library", + "//test/e2e/framework/pod:go_default_library", "//test/e2e/framework/security:go_default_library", "//test/e2e/framework/service:go_default_library", "//test/e2e/framework/skipper:go_default_library", diff --git a/vendor/k8s.io/kubernetes/test/e2e/upgrades/serviceaccount_admission_controller_migration.go b/vendor/k8s.io/kubernetes/test/e2e/upgrades/serviceaccount_admission_controller_migration.go new file mode 100644 index 000000000000..f53fb349da7d --- /dev/null +++ b/vendor/k8s.io/kubernetes/test/e2e/upgrades/serviceaccount_admission_controller_migration.go @@ -0,0 +1,140 @@ +/* +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 upgrades + +import ( + "context" + "fmt" + "time" + + "github.com/onsi/ginkgo" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + e2eauth "k8s.io/kubernetes/test/e2e/auth" + "k8s.io/kubernetes/test/e2e/framework" + e2epod "k8s.io/kubernetes/test/e2e/framework/pod" + imageutils "k8s.io/kubernetes/test/utils/image" +) + +const ( + podBeforeMigrationName = "pod-before-migration" + podAfterMigrationName = "pod-after-migration" +) + +// ServiceAccountAdmissionControllerMigrationTest test that a pod is functioning before and after +// a cluster upgrade. +type ServiceAccountAdmissionControllerMigrationTest struct { + pod *v1.Pod +} + +// Name returns the tracking name of the test. +func (ServiceAccountAdmissionControllerMigrationTest) Name() string { + return "[sig-auth] serviceaccount-admission-controller-migration" +} + +// Setup creates pod-before-migration which has legacy service account token. +func (t *ServiceAccountAdmissionControllerMigrationTest) Setup(f *framework.Framework) { + t.pod = createPod(f, podBeforeMigrationName) + inClusterClientMustWork(f, t.pod) +} + +// Test waits for the upgrade to complete, and then verifies pod-before-migration +// and pod-after-migration are able to make requests using in cluster config. +func (t *ServiceAccountAdmissionControllerMigrationTest) Test(f *framework.Framework, done <-chan struct{}, upgrade UpgradeType) { + ginkgo.By("Waiting for upgrade to finish") + <-done + + ginkgo.By("Starting post-upgrade check") + ginkgo.By("Checking pod-before-migration makes successful requests using in cluster config") + podBeforeMigration, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Get(context.TODO(), podBeforeMigrationName, metav1.GetOptions{}) + framework.ExpectNoError(err) + if podBeforeMigration.GetUID() != t.pod.GetUID() { + framework.Failf("Pod %q GetUID() = %q, want %q.", podBeforeMigration.Name, podBeforeMigration.GetUID(), t.pod.GetUID()) + } + if podBeforeMigration.Status.ContainerStatuses[0].RestartCount != 0 { + framework.Failf("Pod %q RestartCount = %d, want 0.", podBeforeMigration.Name, podBeforeMigration.Status.ContainerStatuses[0].RestartCount) + } + inClusterClientMustWork(f, podBeforeMigration) + + ginkgo.By("Checking pod-after-migration makes successful requests using in cluster config") + podAfterMigration := createPod(f, podAfterMigrationName) + if len(podAfterMigration.Spec.Volumes) != 1 || podAfterMigration.Spec.Volumes[0].Projected == nil { + framework.Failf("Pod %q Volumes[0].Projected.Sources = nil, want non-nil.", podAfterMigration.Name) + } + inClusterClientMustWork(f, podAfterMigration) + + ginkgo.By("Finishing post-upgrade check") +} + +// Teardown cleans up any remaining resources. +func (t *ServiceAccountAdmissionControllerMigrationTest) Teardown(f *framework.Framework) { + // rely on the namespace deletion to clean up everything +} + +func inClusterClientMustWork(f *framework.Framework, pod *v1.Pod) { + var logs string + since := time.Now() + if err := wait.PollImmediate(15*time.Second, 5*time.Minute, func() (done bool, err error) { + framework.Logf("Polling logs") + logs, err = e2epod.GetPodLogsSince(f.ClientSet, pod.Namespace, pod.Name, "inclusterclient", since) + if err != nil { + framework.Logf("Error pulling logs: %v", err) + return false, nil + } + numTokens, err := e2eauth.ParseInClusterClientLogs(logs) + if err != nil { + framework.Logf("Error parsing inclusterclient logs: %v", err) + return false, fmt.Errorf("inclusterclient reported an error: %v", err) + } + if numTokens == 0 { + framework.Logf("No authenticated API calls found") + return false, nil + } + return true, nil + }); err != nil { + framework.Failf("Unexpected error: %v\n%s", err, logs) + } +} + +// createPod creates a pod. +func createPod(f *framework.Framework, podName string) *v1.Pod { + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: podName, + Namespace: f.Namespace.Name, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{{ + Name: "inclusterclient", + Image: imageutils.GetE2EImage(imageutils.Agnhost), + Args: []string{"inclusterclient", "--poll-interval=5"}, + }}, + RestartPolicy: v1.RestartPolicyNever, + }, + } + + createdPod, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(context.TODO(), pod, metav1.CreateOptions{}) + framework.ExpectNoError(err) + framework.Logf("Created pod %s", podName) + + if !e2epod.CheckPodsRunningReady(f.ClientSet, f.Namespace.Name, []string{pod.Name}, time.Minute) { + framework.Failf("Pod %q/%q never became ready", createdPod.Namespace, createdPod.Name) + } + + return createdPod +} diff --git a/vendor/k8s.io/kubernetes/test/utils/image/manifest.go b/vendor/k8s.io/kubernetes/test/utils/image/manifest.go index 5df50a5a5f09..9a1a0262c10a 100644 --- a/vendor/k8s.io/kubernetes/test/utils/image/manifest.go +++ b/vendor/k8s.io/kubernetes/test/utils/image/manifest.go @@ -17,9 +17,12 @@ limitations under the License. package image import ( + "crypto/sha256" + "encoding/base64" "fmt" "io/ioutil" "os" + "regexp" "strings" yaml "gopkg.in/yaml.v2" @@ -115,12 +118,14 @@ var ( sampleRegistry = registry.SampleRegistry // Preconfigured image configs - imageConfigs = initImageConfigs() + imageConfigs, originalImageConfigs = initImageConfigs() ) const ( + // None is to be used for unset/default images + None = iota // Agnhost image - Agnhost = iota + Agnhost // AgnhostPrivate image AgnhostPrivate // APIServer image @@ -198,7 +203,7 @@ const ( VolumeRBDServer ) -func initImageConfigs() map[int]Config { +func initImageConfigs() (map[int]Config, map[int]Config) { configs := map[int]Config{} configs[Agnhost] = Config{promoterE2eRegistry, "agnhost", "2.20"} configs[AgnhostPrivate] = Config{PrivateRegistry, "agnhost", "2.6"} @@ -212,7 +217,7 @@ func initImageConfigs() map[int]Config { configs[CudaVectorAdd2] = Config{e2eRegistry, "cuda-vector-add", "2.0"} configs[DebianIptables] = Config{buildImageRegistry, "debian-iptables", "v12.1.2"} configs[EchoServer] = Config{e2eRegistry, "echoserver", "2.2"} - configs[Etcd] = Config{gcRegistry, "etcd", "3.4.9"} + configs[Etcd] = Config{gcRegistry, "etcd", "3.4.13-0"} configs[GlusterDynamicProvisioner] = Config{dockerGluster, "glusterdynamic-provisioner", "v1.0"} configs[Httpd] = Config{dockerLibraryRegistry, "httpd", "2.4.38-alpine"} configs[HttpdNew] = Config{dockerLibraryRegistry, "httpd", "2.4.39-alpine"} @@ -239,9 +244,97 @@ func initImageConfigs() map[int]Config { configs[VolumeISCSIServer] = Config{e2eVolumeRegistry, "iscsi", "2.0"} configs[VolumeGlusterServer] = Config{e2eVolumeRegistry, "gluster", "1.0"} configs[VolumeRBDServer] = Config{e2eVolumeRegistry, "rbd", "1.0.1"} + + // if requested, map all the SHAs into a known format based on the input + originalImageConfigs := configs + if repo := os.Getenv("KUBE_TEST_REPO"); len(repo) > 0 { + configs = GetMappedImageConfigs(originalImageConfigs, repo) + } + + return configs, originalImageConfigs +} + +// GetMappedImageConfigs returns the images if they were mapped to the provided +// image repository. This method is public to allow tooling to convert these configs +// to an arbitrary repo. +func GetMappedImageConfigs(originalImageConfigs map[int]Config, repo string) map[int]Config { + configs := make(map[int]Config) + for i, config := range originalImageConfigs { + switch i { + case InvalidRegistryImage, AuthenticatedAlpine, + AuthenticatedWindowsNanoServer, AgnhostPrivate: + // These images are special and can't be run out of the cloud - some because they + // are authenticated, and others because they are not real images. Tests that depend + // on these images can't be run without access to the public internet. + configs[i] = config + continue + } + + // Build a new tag with a the index, a hash of the image spec (to be unique) and + // shorten and make the pull spec "safe" so it will fit in the tag + configs[i] = mapConfigToRepos(i, config, repo) + } return configs } +var ( + reCharSafe = regexp.MustCompile(`[^\w]`) + reDashes = regexp.MustCompile(`-+`) +) + +// mapConfigToRepos maps an existing image to the provided repo, generating a +// tag that is unique with the input config. The tag will contain the index, a hash of +// the image spec (to be unique) and shorten and make the pull spec "safe" so it will +// fit in the tag to allow a human to recognize the value. If index is -1, then no +// index will be added to the tag. +func mapConfigToRepos(index int, config Config, repo string) Config { + parts := strings.SplitN(repo, "/", 2) + registry, name := parts[0], parts[1] + + pullSpec := config.GetE2EImage() + + const ( + // length of hash in base64-url chosen to minimize possible collisions (64^16 possible) + hashLength = 16 + // maximum length of a Docker spec image tag + maxTagLength = 127 + // when building a tag, there are at most 6 characters in the format (e2e and 3 dashes), + // and we should allow up to 10 digits for the index and additional qualifiers we may add + // in the future + tagFormatCharacters = 6 + 10 + ) + + h := sha256.New() + h.Write([]byte(pullSpec)) + hash := base64.RawURLEncoding.EncodeToString(h.Sum(nil))[:hashLength] + + shortName := reCharSafe.ReplaceAllLiteralString(pullSpec, "-") + shortName = reDashes.ReplaceAllLiteralString(shortName, "-") + maxLength := maxTagLength - hashLength - tagFormatCharacters + if len(shortName) > maxLength { + shortName = shortName[len(shortName)-maxLength:] + } + var version string + if index == -1 { + version = fmt.Sprintf("e2e-%s-%s", shortName, hash) + } else { + version = fmt.Sprintf("e2e-%d-%s-%s", index, shortName, hash) + } + + return Config{ + registry: registry, + name: name, + version: version, + } +} + +// GetOriginalImageConfigs returns the configuration before any mapping rules. This +// method is public to allow tooling gain access to the default values for images regardless +// of environment variable being set. +func GetOriginalImageConfigs() map[int]Config { + return originalImageConfigs +} + // GetImageConfigs returns the map of imageConfigs func GetImageConfigs() map[int]Config { return imageConfigs @@ -273,6 +366,23 @@ func ReplaceRegistryInImageURL(imageURL string) (string, error) { countParts := len(parts) registryAndUser := strings.Join(parts[:countParts-1], "/") + if repo := os.Getenv("KUBE_TEST_REPO"); len(repo) > 0 { + index := -1 + for i, v := range originalImageConfigs { + if v.GetE2EImage() == imageURL { + index = i + break + } + } + last := strings.SplitN(parts[countParts-1], ":", 2) + config := mapConfigToRepos(index, Config{ + registry: parts[0], + name: strings.Join([]string{strings.Join(parts[1:countParts-1], "/"), last[0]}, "/"), + version: last[1], + }, repo) + return config.GetE2EImage(), nil + } + switch registryAndUser { case "gcr.io/kubernetes-e2e-test-images": registryAndUser = e2eRegistry diff --git a/vendor/k8s.io/legacy-cloud-providers/aws/aws.go b/vendor/k8s.io/legacy-cloud-providers/aws/aws.go index 6aeaaa7e09c3..d0cc73a17fc3 100644 --- a/vendor/k8s.io/legacy-cloud-providers/aws/aws.go +++ b/vendor/k8s.io/legacy-cloud-providers/aws/aws.go @@ -3665,6 +3665,27 @@ func buildListener(port v1.ServicePort, annotations map[string]string, sslPorts return listener, nil } +func (c *Cloud) getSubnetCidrs(subnetIDs []string) ([]string, error) { + request := &ec2.DescribeSubnetsInput{} + for _, subnetID := range subnetIDs { + request.SubnetIds = append(request.SubnetIds, aws.String(subnetID)) + } + + subnets, err := c.ec2.DescribeSubnets(request) + if err != nil { + return nil, fmt.Errorf("error querying Subnet for ELB: %q", err) + } + if len(subnets) != len(subnetIDs) { + return nil, fmt.Errorf("error querying Subnet for ELB, got %d subnets for %v", len(subnets), subnetIDs) + } + + cidrs := make([]string, 0, len(subnets)) + for _, subnet := range subnets { + cidrs = append(cidrs, aws.StringValue(subnet.CidrBlock)) + } + return cidrs, nil +} + // EnsureLoadBalancer implements LoadBalancer.EnsureLoadBalancer func (c *Cloud) EnsureLoadBalancer(ctx context.Context, clusterName string, apiService *v1.Service, nodes []*v1.Node) (*v1.LoadBalancerStatus, error) { annotations := apiService.Annotations @@ -3794,6 +3815,12 @@ func (c *Cloud) EnsureLoadBalancer(ctx context.Context, clusterName string, apiS return nil, err } + subnetCidrs, err := c.getSubnetCidrs(subnetIDs) + if err != nil { + klog.Errorf("Error getting subnet cidrs: %q", err) + return nil, err + } + sourceRangeCidrs := []string{} for cidr := range sourceRanges { sourceRangeCidrs = append(sourceRangeCidrs, cidr) @@ -3802,7 +3829,7 @@ func (c *Cloud) EnsureLoadBalancer(ctx context.Context, clusterName string, apiS sourceRangeCidrs = append(sourceRangeCidrs, "0.0.0.0/0") } - err = c.updateInstanceSecurityGroupsForNLB(loadBalancerName, instances, sourceRangeCidrs, v2Mappings) + err = c.updateInstanceSecurityGroupsForNLB(loadBalancerName, instances, subnetCidrs, sourceRangeCidrs, v2Mappings) if err != nil { klog.Warningf("Error opening ingress rules for the load balancer to the instances: %q", err) return nil, err @@ -4373,7 +4400,7 @@ func (c *Cloud) EnsureLoadBalancerDeleted(ctx context.Context, clusterName strin } } - return c.updateInstanceSecurityGroupsForNLB(loadBalancerName, nil, nil, nil) + return c.updateInstanceSecurityGroupsForNLB(loadBalancerName, nil, nil, nil, nil) } lb, err := c.describeLoadBalancer(loadBalancerName) diff --git a/vendor/k8s.io/legacy-cloud-providers/aws/aws_loadbalancer.go b/vendor/k8s.io/legacy-cloud-providers/aws/aws_loadbalancer.go index 2b90906572e3..07bb7106b1b4 100644 --- a/vendor/k8s.io/legacy-cloud-providers/aws/aws_loadbalancer.go +++ b/vendor/k8s.io/legacy-cloud-providers/aws/aws_loadbalancer.go @@ -716,30 +716,9 @@ func (c *Cloud) ensureTargetGroup(targetGroup *elbv2.TargetGroup, serviceName ty return targetGroup, nil } -func (c *Cloud) getVpcCidrBlocks() ([]string, error) { - vpcs, err := c.ec2.DescribeVpcs(&ec2.DescribeVpcsInput{ - VpcIds: []*string{aws.String(c.vpcID)}, - }) - if err != nil { - return nil, fmt.Errorf("error querying VPC for ELB: %q", err) - } - if len(vpcs.Vpcs) != 1 { - return nil, fmt.Errorf("error querying VPC for ELB, got %d vpcs for %s", len(vpcs.Vpcs), c.vpcID) - } - - cidrBlocks := make([]string, 0, len(vpcs.Vpcs[0].CidrBlockAssociationSet)) - for _, cidr := range vpcs.Vpcs[0].CidrBlockAssociationSet { - if aws.StringValue(cidr.CidrBlockState.State) != ec2.VpcCidrBlockStateCodeAssociated { - continue - } - cidrBlocks = append(cidrBlocks, aws.StringValue(cidr.CidrBlock)) - } - return cidrBlocks, nil -} - // updateInstanceSecurityGroupsForNLB will adjust securityGroup's settings to allow inbound traffic into instances from clientCIDRs and portMappings. // TIP: if either instances or clientCIDRs or portMappings are nil, then the securityGroup rules for lbName are cleared. -func (c *Cloud) updateInstanceSecurityGroupsForNLB(lbName string, instances map[InstanceID]*ec2.Instance, clientCIDRs []string, portMappings []nlbPortMapping) error { +func (c *Cloud) updateInstanceSecurityGroupsForNLB(lbName string, instances map[InstanceID]*ec2.Instance, subnetCIDRs []string, clientCIDRs []string, portMappings []nlbPortMapping) error { if c.cfg.Global.DisableSecurityGroupIngress { return nil } @@ -787,14 +766,10 @@ func (c *Cloud) updateInstanceSecurityGroupsForNLB(lbName string, instances map[ } clientRuleAnnotation := fmt.Sprintf("%s=%s", NLBClientRuleDescription, lbName) healthRuleAnnotation := fmt.Sprintf("%s=%s", NLBHealthCheckRuleDescription, lbName) - vpcCIDRs, err := c.getVpcCidrBlocks() - if err != nil { - return err - } for sgID, sg := range clusterSGs { sgPerms := NewIPPermissionSet(sg.IpPermissions...).Ungroup() if desiredSGIDs.Has(sgID) { - if err := c.updateInstanceSecurityGroupForNLBTraffic(sgID, sgPerms, healthRuleAnnotation, "tcp", healthCheckPorts, vpcCIDRs); err != nil { + if err := c.updateInstanceSecurityGroupForNLBTraffic(sgID, sgPerms, healthRuleAnnotation, "tcp", healthCheckPorts, subnetCIDRs); err != nil { return err } if err := c.updateInstanceSecurityGroupForNLBTraffic(sgID, sgPerms, clientRuleAnnotation, clientProtocol, clientPorts, clientCIDRs); err != nil { diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/azure.go b/vendor/k8s.io/legacy-cloud-providers/azure/azure.go index fcccf5786804..b2e7a50d134c 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/azure.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/azure.go @@ -248,7 +248,7 @@ type Cloud struct { ResourceRequestBackoff wait.Backoff metadata *InstanceMetadataService - vmSet VMSet + VMSet VMSet // ipv6DualStack allows overriding for unit testing. It's normally initialized from featuregates ipv6DualStackEnabled bool @@ -491,12 +491,12 @@ func (az *Cloud) InitializeCloudFromConfig(config *Config, fromSecret bool) erro } if strings.EqualFold(vmTypeVMSS, az.Config.VMType) { - az.vmSet, err = newScaleSet(az) + az.VMSet, err = newScaleSet(az) if err != nil { return err } } else { - az.vmSet = newAvailabilitySet(az) + az.VMSet = newAvailabilitySet(az) } az.vmCache, err = az.newVMCache() diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/azure_backoff.go b/vendor/k8s.io/legacy-cloud-providers/azure/azure_backoff.go index c0091e3ce388..0634d7e0388f 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/azure_backoff.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/azure_backoff.go @@ -20,6 +20,7 @@ package azure import ( "net/http" + "regexp" "strings" "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" @@ -42,6 +43,12 @@ const ( // operationCanceledErrorMessage means the operation is canceled by another new operation. operationCanceledErrorMessage = "canceledandsupersededduetoanotheroperation" + + referencedResourceNotProvisionedMessageCode = "ReferencedResourceNotProvisioned" +) + +var ( + pipErrorMessageRE = regexp.MustCompile(`(?:.*)/subscriptions/(?:.*)/resourceGroups/(.*)/providers/Microsoft.Network/publicIPAddresses/([^\s]+)(?:.*)`) ) // RequestBackoff if backoff is disabled in cloud provider it @@ -111,7 +118,7 @@ func (az *Cloud) getPrivateIPsForMachineWithRetry(nodeName types.NodeName) ([]st var privateIPs []string err := wait.ExponentialBackoff(az.RequestBackoff(), func() (bool, error) { var retryErr error - privateIPs, retryErr = az.vmSet.GetPrivateIPsByNodeName(string(nodeName)) + privateIPs, retryErr = az.VMSet.GetPrivateIPsByNodeName(string(nodeName)) if retryErr != nil { // won't retry since the instance doesn't exist on Azure. if retryErr == cloudprovider.InstanceNotFound { @@ -135,7 +142,7 @@ func (az *Cloud) GetIPForMachineWithRetry(name types.NodeName) (string, string, var ip, publicIP string err := wait.ExponentialBackoff(az.RequestBackoff(), func() (bool, error) { var retryErr error - ip, publicIP, retryErr = az.vmSet.GetIPByNodeName(string(name)) + ip, publicIP, retryErr = az.VMSet.GetIPByNodeName(string(name)) if retryErr != nil { klog.Errorf("GetIPForMachineWithRetry(%s): backoff failure, will retry,err=%v", name, retryErr) return false, nil @@ -180,7 +187,7 @@ func (az *Cloud) CreateOrUpdateLB(service *v1.Service, lb network.LoadBalancer) defer cancel() rgName := az.getLoadBalancerResourceGroup() - rerr := az.LoadBalancerClient.CreateOrUpdate(ctx, rgName, *lb.Name, lb, to.String(lb.Etag)) + rerr := az.LoadBalancerClient.CreateOrUpdate(ctx, rgName, to.String(lb.Name), lb, to.String(lb.Etag)) klog.V(10).Infof("LoadBalancerClient.CreateOrUpdate(%s): end", *lb.Name) if rerr == nil { // Invalidate the cache right after updating @@ -190,12 +197,39 @@ func (az *Cloud) CreateOrUpdateLB(service *v1.Service, lb network.LoadBalancer) // Invalidate the cache because ETAG precondition mismatch. if rerr.HTTPStatusCode == http.StatusPreconditionFailed { - klog.V(3).Infof("LoadBalancer cache for %s is cleanup because of http.StatusPreconditionFailed", *lb.Name) + klog.V(3).Infof("LoadBalancer cache for %s is cleanup because of http.StatusPreconditionFailed", to.String(lb.Name)) az.lbCache.Delete(*lb.Name) } + + retryErrorMessage := rerr.Error().Error() // Invalidate the cache because another new operation has canceled the current request. - if strings.Contains(strings.ToLower(rerr.Error().Error()), operationCanceledErrorMessage) { - klog.V(3).Infof("LoadBalancer cache for %s is cleanup because CreateOrUpdate is canceled by another operation", *lb.Name) + if strings.Contains(strings.ToLower(retryErrorMessage), operationCanceledErrorMessage) { + klog.V(3).Infof("LoadBalancer cache for %s is cleanup because CreateOrUpdate is canceled by another operation", to.String(lb.Name)) + az.lbCache.Delete(*lb.Name) + } + + // The LB update may fail because the referenced PIP is not in the Succeeded provisioning state + if strings.Contains(strings.ToLower(retryErrorMessage), strings.ToLower(referencedResourceNotProvisionedMessageCode)) { + matches := pipErrorMessageRE.FindStringSubmatch(retryErrorMessage) + if len(matches) != 3 { + klog.Warningf("Failed to parse the retry error message %s", retryErrorMessage) + return rerr.Error() + } + pipRG, pipName := matches[1], matches[2] + klog.V(3).Infof("The public IP %s referenced by load balancer %s is not in Succeeded provisioning state, will try to update it", pipName, to.String(lb.Name)) + pip, _, err := az.getPublicIPAddress(pipRG, pipName) + if err != nil { + klog.Warningf("Failed to get the public IP %s in resource group %s: %v", pipName, pipRG, err) + return rerr.Error() + } + // Perform a dummy update to fix the provisioning state + err = az.CreateOrUpdatePIP(service, pipRG, pip) + if err != nil { + klog.Warningf("Failed to update the public IP %s in resource group %s: %v", pipName, pipRG, err) + return rerr.Error() + } + // Invalidate the LB cache, return the error, and the controller manager + // would retry the LB update in the next reconcile loop az.lbCache.Delete(*lb.Name) } @@ -239,10 +273,10 @@ func (az *Cloud) CreateOrUpdatePIP(service *v1.Service, pipResourceGroup string, ctx, cancel := getContextWithCancel() defer cancel() - rerr := az.PublicIPAddressesClient.CreateOrUpdate(ctx, pipResourceGroup, *pip.Name, pip) - klog.V(10).Infof("PublicIPAddressesClient.CreateOrUpdate(%s, %s): end", pipResourceGroup, *pip.Name) + rerr := az.PublicIPAddressesClient.CreateOrUpdate(ctx, pipResourceGroup, to.String(pip.Name), pip) + klog.V(10).Infof("PublicIPAddressesClient.CreateOrUpdate(%s, %s): end", pipResourceGroup, to.String(pip.Name)) if rerr != nil { - klog.Errorf("PublicIPAddressesClient.CreateOrUpdate(%s, %s) failed: %s", pipResourceGroup, *pip.Name, rerr.Error().Error()) + klog.Errorf("PublicIPAddressesClient.CreateOrUpdate(%s, %s) failed: %s", pipResourceGroup, to.String(pip.Name), rerr.Error().Error()) az.Event(service, v1.EventTypeWarning, "CreateOrUpdatePublicIPAddress", rerr.Error().Error()) return rerr.Error() } diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/azure_controller_common.go b/vendor/k8s.io/legacy-cloud-providers/azure/azure_controller_common.go index 5e396c80dfa5..446b0d4192d5 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/azure_controller_common.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/azure_controller_common.go @@ -44,12 +44,17 @@ const ( maxStorageAccounts = 100 // max # is 200 (250 with special request). this allows 100 for everything else including stand alone disks maxDisksPerStorageAccounts = 60 storageAccountUtilizationBeforeGrowing = 0.5 + // Disk Caching is not supported for disks 4 TiB and larger + // https://docs.microsoft.com/en-us/azure/virtual-machines/premium-storage-performance#disk-caching + diskCachingLimit = 4096 // GiB maxLUN = 64 // max number of LUNs per VM errLeaseFailed = "AcquireDiskLeaseFailed" errLeaseIDMissing = "LeaseIdMissing" errContainerNotFound = "ContainerNotFound" - errDiskBlobNotFound = "DiskBlobNotFound" + errStatusCode400 = "statuscode=400" + errInvalidParameter = `code="invalidparameter"` + errTargetInstanceIds = `target="instanceids"` sourceSnapshot = "snapshot" sourceVolume = "volume" @@ -90,15 +95,15 @@ type controllerCommon struct { // getNodeVMSet gets the VMSet interface based on config.VMType and the real virtual machine type. func (c *controllerCommon) getNodeVMSet(nodeName types.NodeName, crt azcache.AzureCacheReadType) (VMSet, error) { - // 1. vmType is standard, return cloud.vmSet directly. + // 1. vmType is standard, return cloud.VMSet directly. if c.cloud.VMType == vmTypeStandard { - return c.cloud.vmSet, nil + return c.cloud.VMSet, nil } // 2. vmType is Virtual Machine Scale Set (vmss), convert vmSet to scaleSet. - ss, ok := c.cloud.vmSet.(*scaleSet) + ss, ok := c.cloud.VMSet.(*scaleSet) if !ok { - return nil, fmt.Errorf("error of converting vmSet (%q) to scaleSet with vmType %q", c.cloud.vmSet, c.cloud.VMType) + return nil, fmt.Errorf("error of converting vmSet (%q) to scaleSet with vmType %q", c.cloud.VMSet, c.cloud.VMType) } // 3. If the node is managed by availability set, then return ss.availabilitySet. @@ -154,10 +159,21 @@ func (c *controllerCommon) AttachDisk(isManagedDisk bool, diskName, diskURI stri return -1, danglingErr } - if disk.DiskProperties != nil && disk.DiskProperties.Encryption != nil && - disk.DiskProperties.Encryption.DiskEncryptionSetID != nil { - diskEncryptionSetID = *disk.DiskProperties.Encryption.DiskEncryptionSetID + if disk.DiskProperties != nil { + if disk.DiskProperties.DiskSizeGB != nil && *disk.DiskProperties.DiskSizeGB >= diskCachingLimit && cachingMode != compute.CachingTypesNone { + // Disk Caching is not supported for disks 4 TiB and larger + // https://docs.microsoft.com/en-us/azure/virtual-machines/premium-storage-performance#disk-caching + cachingMode = compute.CachingTypesNone + klog.Warningf("size of disk(%s) is %dGB which is bigger than limit(%dGB), set cacheMode as None", + diskURI, *disk.DiskProperties.DiskSizeGB, diskCachingLimit) + } + + if disk.DiskProperties.Encryption != nil && + disk.DiskProperties.Encryption.DiskEncryptionSetID != nil { + diskEncryptionSetID = *disk.DiskProperties.Encryption.DiskEncryptionSetID + } } + if v, ok := disk.Tags[WriteAcceleratorEnabled]; ok { if v != nil && strings.EqualFold(*v, "true") { writeAcceleratorEnabled = true @@ -214,24 +230,32 @@ func (c *controllerCommon) DetachDisk(diskName, diskURI string, nodeName types.N c.diskAttachDetachMap.Delete(strings.ToLower(diskURI)) c.vmLockMap.UnlockEntry(strings.ToLower(string(nodeName))) - if err != nil && retry.IsErrorRetriable(err) && c.cloud.CloudProviderBackoff { - klog.V(2).Infof("azureDisk - update backing off: detach disk(%s, %s), err: %v", diskName, diskURI, err) - retryErr := kwait.ExponentialBackoff(c.cloud.RequestBackoff(), func() (bool, error) { - c.vmLockMap.LockEntry(strings.ToLower(string(nodeName))) - c.diskAttachDetachMap.Store(strings.ToLower(diskURI), "detaching") - err := vmset.DetachDisk(diskName, diskURI, nodeName) - c.diskAttachDetachMap.Delete(strings.ToLower(diskURI)) - c.vmLockMap.UnlockEntry(strings.ToLower(string(nodeName))) - - retriable := false - if err != nil && retry.IsErrorRetriable(err) { - retriable = true + if err != nil { + if isInstanceNotFoundError(err) { + // if host doesn't exist, no need to detach + klog.Warningf("azureDisk - got InstanceNotFoundError(%v), DetachDisk(%s) will assume disk is already detached", + err, diskURI) + return nil + } + if retry.IsErrorRetriable(err) && c.cloud.CloudProviderBackoff { + klog.Warningf("azureDisk - update backing off: detach disk(%s, %s), err: %v", diskName, diskURI, err) + retryErr := kwait.ExponentialBackoff(c.cloud.RequestBackoff(), func() (bool, error) { + c.vmLockMap.LockEntry(strings.ToLower(string(nodeName))) + c.diskAttachDetachMap.Store(strings.ToLower(diskURI), "detaching") + err := vmset.DetachDisk(diskName, diskURI, nodeName) + c.diskAttachDetachMap.Delete(strings.ToLower(diskURI)) + c.vmLockMap.UnlockEntry(strings.ToLower(string(nodeName))) + + retriable := false + if err != nil && retry.IsErrorRetriable(err) { + retriable = true + } + return !retriable, err + }) + if retryErr != nil { + err = retryErr + klog.V(2).Infof("azureDisk - update abort backoff: detach disk(%s, %s), err: %v", diskName, diskURI, err) } - return !retriable, err - }) - if retryErr != nil { - err = retryErr - klog.V(2).Infof("azureDisk - update abort backoff: detach disk(%s, %s), err: %v", diskName, diskURI, err) } } if err != nil { @@ -426,3 +450,8 @@ func getValidCreationData(subscriptionID, resourceGroup, sourceResourceID, sourc SourceResourceID: &sourceResourceID, }, nil } + +func isInstanceNotFoundError(err error) bool { + errMsg := strings.ToLower(err.Error()) + return strings.Contains(errMsg, errStatusCode400) && strings.Contains(errMsg, errInvalidParameter) && strings.Contains(errMsg, errTargetInstanceIds) +} diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/azure_controller_standard.go b/vendor/k8s.io/legacy-cloud-providers/azure/azure_controller_standard.go index 54ca4f880ff9..abe89e396dd1 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/azure_controller_standard.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/azure_controller_standard.go @@ -142,7 +142,11 @@ func (as *availabilitySet) DetachDisk(diskName, diskURI string, nodeName types.N (disk.ManagedDisk != nil && diskURI != "" && strings.EqualFold(*disk.ManagedDisk.ID, diskURI)) { // found the disk klog.V(2).Infof("azureDisk - detach disk: name %q uri %q", diskName, diskURI) - disks[i].ToBeDetached = to.BoolPtr(true) + if strings.EqualFold(as.cloud.Environment.Name, "AZURESTACKCLOUD") { + disks = append(disks[:i], disks[i+1:]...) + } else { + disks[i].ToBeDetached = to.BoolPtr(true) + } bFoundDisk = true break } diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/azure_controller_vmss.go b/vendor/k8s.io/legacy-cloud-providers/azure/azure_controller_vmss.go index 344e4f03d4a9..8958bdb29fc3 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/azure_controller_vmss.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/azure_controller_vmss.go @@ -147,7 +147,11 @@ func (ss *scaleSet) DetachDisk(diskName, diskURI string, nodeName types.NodeName (disk.ManagedDisk != nil && diskURI != "" && strings.EqualFold(*disk.ManagedDisk.ID, diskURI)) { // found the disk klog.V(2).Infof("azureDisk - detach disk: name %q uri %q", diskName, diskURI) - disks[i].ToBeDetached = to.BoolPtr(true) + if strings.EqualFold(ss.cloud.Environment.Name, "AZURESTACKCLOUD") { + disks = append(disks[:i], disks[i+1:]...) + } else { + disks[i].ToBeDetached = to.BoolPtr(true) + } bFoundDisk = true break } diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/azure_fakes.go b/vendor/k8s.io/legacy-cloud-providers/azure/azure_fakes.go index 59e260cdec71..2e4f549ff48f 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/azure_fakes.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/azure_fakes.go @@ -83,7 +83,7 @@ func GetTestCloud(ctrl *gomock.Controller) (az *Cloud) { az.VirtualMachineScaleSetsClient = mockvmssclient.NewMockInterface(ctrl) az.VirtualMachineScaleSetVMsClient = mockvmssvmclient.NewMockInterface(ctrl) az.VirtualMachinesClient = mockvmclient.NewMockInterface(ctrl) - az.vmSet = newAvailabilitySet(az) + az.VMSet = newAvailabilitySet(az) az.vmCache, _ = az.newVMCache() az.lbCache, _ = az.newLBCache() az.nsgCache, _ = az.newNSGCache() diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/azure_instances.go b/vendor/k8s.io/legacy-cloud-providers/azure/azure_instances.go index a0f19f85fbe4..95f8f49ae733 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/azure_instances.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/azure_instances.go @@ -95,7 +95,7 @@ func (az *Cloud) NodeAddresses(ctx context.Context, name types.NodeName) ([]v1.N // Not local instance, get addresses from Azure ARM API. if !isLocalInstance { - if az.vmSet != nil { + if az.VMSet != nil { return az.addressGetter(name) } @@ -168,7 +168,7 @@ func (az *Cloud) NodeAddressesByProviderID(ctx context.Context, providerID strin return nil, nil } - name, err := az.vmSet.GetNodeNameByProviderID(providerID) + name, err := az.VMSet.GetNodeNameByProviderID(providerID) if err != nil { return nil, err } @@ -189,7 +189,7 @@ func (az *Cloud) InstanceExistsByProviderID(ctx context.Context, providerID stri return true, nil } - name, err := az.vmSet.GetNodeNameByProviderID(providerID) + name, err := az.VMSet.GetNodeNameByProviderID(providerID) if err != nil { if err == cloudprovider.InstanceNotFound { return false, nil @@ -214,7 +214,7 @@ func (az *Cloud) InstanceShutdownByProviderID(ctx context.Context, providerID st return false, nil } - nodeName, err := az.vmSet.GetNodeNameByProviderID(providerID) + nodeName, err := az.VMSet.GetNodeNameByProviderID(providerID) if err != nil { // Returns false, so the controller manager will continue to check InstanceExistsByProviderID(). if err == cloudprovider.InstanceNotFound { @@ -224,7 +224,7 @@ func (az *Cloud) InstanceShutdownByProviderID(ctx context.Context, providerID st return false, err } - powerStatus, err := az.vmSet.GetPowerStatusByNodeName(string(nodeName)) + powerStatus, err := az.VMSet.GetPowerStatusByNodeName(string(nodeName)) if err != nil { // Returns false, so the controller manager will continue to check InstanceExistsByProviderID(). if err == cloudprovider.InstanceNotFound { @@ -292,8 +292,8 @@ func (az *Cloud) InstanceID(ctx context.Context, name types.NodeName) (string, e // Not local instance, get instanceID from Azure ARM API. if !isLocalInstance { - if az.vmSet != nil { - return az.vmSet.GetInstanceIDByNodeName(nodeName) + if az.VMSet != nil { + return az.VMSet.GetInstanceIDByNodeName(nodeName) } // vmSet == nil indicates credentials are not provided. @@ -302,7 +302,7 @@ func (az *Cloud) InstanceID(ctx context.Context, name types.NodeName) (string, e return az.getLocalInstanceProviderID(metadata, nodeName) } - return az.vmSet.GetInstanceIDByNodeName(nodeName) + return az.VMSet.GetInstanceIDByNodeName(nodeName) } func (az *Cloud) getLocalInstanceProviderID(metadata *InstanceMetadata, nodeName string) (string, error) { @@ -342,7 +342,7 @@ func (az *Cloud) InstanceTypeByProviderID(ctx context.Context, providerID string return "", nil } - name, err := az.vmSet.GetNodeNameByProviderID(providerID) + name, err := az.VMSet.GetNodeNameByProviderID(providerID) if err != nil { return "", err } @@ -380,8 +380,8 @@ func (az *Cloud) InstanceType(ctx context.Context, name types.NodeName) (string, return "", err } if !isLocalInstance { - if az.vmSet != nil { - return az.vmSet.GetInstanceTypeByNodeName(string(name)) + if az.VMSet != nil { + return az.VMSet.GetInstanceTypeByNodeName(string(name)) } // vmSet == nil indicates credentials are not provided. @@ -393,7 +393,7 @@ func (az *Cloud) InstanceType(ctx context.Context, name types.NodeName) (string, } } - return az.vmSet.GetInstanceTypeByNodeName(string(name)) + return az.VMSet.GetInstanceTypeByNodeName(string(name)) } // AddSSHKeyToAllInstances adds an SSH public key as a legal identity for all instances diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/azure_loadbalancer.go b/vendor/k8s.io/legacy-cloud-providers/azure/azure_loadbalancer.go index e12b9accb50a..9744507c8cbb 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/azure_loadbalancer.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/azure_loadbalancer.go @@ -36,6 +36,7 @@ import ( servicehelpers "k8s.io/cloud-provider/service/helpers" "k8s.io/klog/v2" azcache "k8s.io/legacy-cloud-providers/azure/cache" + "k8s.io/legacy-cloud-providers/azure/retry" utilnet "k8s.io/utils/net" ) @@ -216,7 +217,7 @@ func (az *Cloud) EnsureLoadBalancerDeleted(ctx context.Context, clusterName stri klog.V(5).Infof("Delete service (%s): START clusterName=%q", serviceName, clusterName) serviceIPToCleanup, err := az.findServiceIPAddress(ctx, clusterName, service, isInternal) - if err != nil { + if err != nil && !retry.HasStatusForbiddenOrIgnoredError(err) { return err } @@ -225,7 +226,7 @@ func (az *Cloud) EnsureLoadBalancerDeleted(ctx context.Context, clusterName stri return err } - if _, err := az.reconcileLoadBalancer(clusterName, service, nil, false /* wantLb */); err != nil { + if _, err := az.reconcileLoadBalancer(clusterName, service, nil, false /* wantLb */); err != nil && !retry.HasStatusForbiddenOrIgnoredError(err) { return err } @@ -258,7 +259,7 @@ func (az *Cloud) getLoadBalancerResourceGroup() string { func (az *Cloud) getServiceLoadBalancer(service *v1.Service, clusterName string, nodes []*v1.Node, wantLb bool) (lb *network.LoadBalancer, status *v1.LoadBalancerStatus, exists bool, err error) { isInternal := requiresInternalLoadBalancer(service) var defaultLB *network.LoadBalancer - primaryVMSetName := az.vmSet.GetPrimaryVMSetName() + primaryVMSetName := az.VMSet.GetPrimaryVMSetName() defaultLBName := az.getAzureLoadBalancerName(clusterName, primaryVMSetName, isInternal) existingLBs, err := az.ListLB(service) @@ -329,7 +330,7 @@ func (az *Cloud) selectLoadBalancer(clusterName string, service *v1.Service, exi isInternal := requiresInternalLoadBalancer(service) serviceName := getServiceName(service) klog.V(2).Infof("selectLoadBalancer for service (%s): isInternal(%v) - start", serviceName, isInternal) - vmSetNames, err := az.vmSet.GetVMSetNames(service, nodes) + vmSetNames, err := az.VMSet.GetVMSetNames(service, nodes) if err != nil { klog.Errorf("az.selectLoadBalancer: cluster(%s) service(%s) isInternal(%t) - az.GetVMSetNames failed, err=(%v)", clusterName, serviceName, isInternal, err) return nil, false, err @@ -935,7 +936,7 @@ func (az *Cloud) reconcileLoadBalancer(clusterName string, service *v1.Service, // Remove backend pools from vmSets. This is required for virtual machine scale sets before removing the LB. vmSetName := az.mapLoadBalancerNameToVMSet(lbName, clusterName) klog.V(10).Infof("EnsureBackendPoolDeleted(%s,%s) for service %s: start", lbBackendPoolID, vmSetName, serviceName) - err := az.vmSet.EnsureBackendPoolDeleted(service, lbBackendPoolID, vmSetName, lb.BackendAddressPools) + err := az.VMSet.EnsureBackendPoolDeleted(service, lbBackendPoolID, vmSetName, lb.BackendAddressPools) if err != nil { klog.Errorf("EnsureBackendPoolDeleted(%s) for service %s failed: %v", lbBackendPoolID, serviceName, err) return nil, err @@ -979,7 +980,7 @@ func (az *Cloud) reconcileLoadBalancer(clusterName string, service *v1.Service, vmSetName := az.mapLoadBalancerNameToVMSet(lbName, clusterName) // Etag would be changed when updating backend pools, so invalidate lbCache after it. defer az.lbCache.Delete(lbName) - err := az.vmSet.EnsureHostsInPool(service, nodes, lbBackendPoolID, vmSetName, isInternal) + err := az.VMSet.EnsureHostsInPool(service, nodes, lbBackendPoolID, vmSetName, isInternal) if err != nil { return nil, err } diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/azure_managedDiskController.go b/vendor/k8s.io/legacy-cloud-providers/azure/azure_managedDiskController.go index 2168498c733b..6189519998b3 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/azure_managedDiskController.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/azure_managedDiskController.go @@ -297,11 +297,15 @@ func (c *ManagedDiskController) ResizeDisk(diskURI string, oldSize resource.Quan return newSizeQuant, nil } - result.DiskProperties.DiskSizeGB = &requestGiB + diskParameter := compute.DiskUpdate{ + DiskUpdateProperties: &compute.DiskUpdateProperties{ + DiskSizeGB: &requestGiB, + }, + } ctx, cancel = getContextWithCancel() defer cancel() - if rerr := c.common.cloud.DisksClient.CreateOrUpdate(ctx, resourceGroup, diskName, result); rerr != nil { + if rerr := c.common.cloud.DisksClient.Update(ctx, resourceGroup, diskName, diskParameter); rerr != nil { return oldSize, rerr.Error() } diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/azure_standard.go b/vendor/k8s.io/legacy-cloud-providers/azure/azure_standard.go index e9a2f049c12e..174ba45e69d9 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/azure_standard.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/azure_standard.go @@ -135,7 +135,7 @@ func (az *Cloud) getNetworkResourceSubscriptionID() string { func (az *Cloud) mapLoadBalancerNameToVMSet(lbName string, clusterName string) (vmSetName string) { vmSetName = strings.TrimSuffix(lbName, InternalLoadBalancerNameSuffix) if strings.EqualFold(clusterName, vmSetName) { - vmSetName = az.vmSet.GetPrimaryVMSetName() + vmSetName = az.VMSet.GetPrimaryVMSetName() } return vmSetName @@ -150,7 +150,7 @@ func (az *Cloud) getAzureLoadBalancerName(clusterName string, vmSetName string, clusterName = az.LoadBalancerName } lbNamePrefix := vmSetName - if strings.EqualFold(vmSetName, az.vmSet.GetPrimaryVMSetName()) || az.useStandardLoadBalancer() { + if strings.EqualFold(vmSetName, az.VMSet.GetPrimaryVMSetName()) || az.useStandardLoadBalancer() { lbNamePrefix = clusterName } if isInternal { @@ -732,7 +732,7 @@ func (as *availabilitySet) EnsureHostInPool(service *v1.Service, nodeName types. return "", "", "", nil, nil } - klog.Errorf("error: az.EnsureHostInPool(%s), az.vmSet.GetPrimaryInterface.Get(%s, %s), err=%v", nodeName, vmName, vmSetName, err) + klog.Errorf("error: az.EnsureHostInPool(%s), az.VMSet.GetPrimaryInterface.Get(%s, %s), err=%v", nodeName, vmName, vmSetName, err) return "", "", "", nil, err } diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/azure_vmss.go b/vendor/k8s.io/legacy-cloud-providers/azure/azure_vmss.go index c1ce257c5d3f..7f14dcacab5d 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/azure_vmss.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/azure_vmss.go @@ -534,17 +534,21 @@ func (ss *scaleSet) GetPrivateIPsByNodeName(nodeName string) ([]string, error) { // This returns the full identifier of the primary NIC for the given VM. func (ss *scaleSet) getPrimaryInterfaceID(machine compute.VirtualMachineScaleSetVM) (string, error) { + if machine.NetworkProfile == nil || machine.NetworkProfile.NetworkInterfaces == nil { + return "", fmt.Errorf("failed to find the network interfaces for vm %s", to.String(machine.Name)) + } + if len(*machine.NetworkProfile.NetworkInterfaces) == 1 { return *(*machine.NetworkProfile.NetworkInterfaces)[0].ID, nil } for _, ref := range *machine.NetworkProfile.NetworkInterfaces { - if *ref.Primary { + if to.Bool(ref.Primary) { return *ref.ID, nil } } - return "", fmt.Errorf("failed to find a primary nic for the vm. vmname=%q", *machine.Name) + return "", fmt.Errorf("failed to find a primary nic for the vm. vmname=%q", to.String(machine.Name)) } // getVmssMachineID returns the full identifier of a vmss virtual machine. @@ -692,6 +696,9 @@ func (ss *scaleSet) listScaleSetVMs(scaleSetName, resourceGroup string) ([]compu allVMs, rerr := ss.VirtualMachineScaleSetVMsClient.List(ctx, resourceGroup, scaleSetName, string(compute.InstanceView)) if rerr != nil { klog.Errorf("VirtualMachineScaleSetVMsClient.List failed: %v", rerr) + if rerr.IsNotFound() { + return nil, cloudprovider.InstanceNotFound + } return nil, rerr.Error() } @@ -1406,6 +1413,9 @@ func (ss *scaleSet) ensureBackendPoolDeletedFromVMSS(service *v1.Service, backen for vmssName := range vmssNamesMap { vmss, err := ss.getVMSS(vmssName, azcache.CacheReadTypeDefault) + if err != nil { + return err + } // When vmss is being deleted, CreateOrUpdate API would report "the vmss is being deleted" error. // Since it is being deleted, we shouldn't send more CreateOrUpdate requests for it. @@ -1413,10 +1423,6 @@ func (ss *scaleSet) ensureBackendPoolDeletedFromVMSS(service *v1.Service, backen klog.V(3).Infof("ensureVMSSInPool: found vmss %s being deleted, skipping", vmssName) continue } - - if err != nil { - return err - } if vmss.VirtualMachineProfile.NetworkProfile.NetworkInterfaceConfigurations == nil { klog.V(4).Infof("EnsureHostInPool: cannot obtain the primary network interface configuration, of vmss %s", vmssName) continue diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/azure_zones.go b/vendor/k8s.io/legacy-cloud-providers/azure/azure_zones.go index 36c78002dee1..f3e546296256 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/azure_zones.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/azure_zones.go @@ -87,7 +87,7 @@ func (az *Cloud) GetZone(ctx context.Context) (cloudprovider.Zone, error) { if err != nil { return cloudprovider.Zone{}, fmt.Errorf("failure getting hostname from kernel") } - return az.vmSet.GetZoneByNodeName(strings.ToLower(hostname)) + return az.VMSet.GetZoneByNodeName(strings.ToLower(hostname)) } // GetZoneByProviderID implements Zones.GetZoneByProviderID @@ -104,7 +104,7 @@ func (az *Cloud) GetZoneByProviderID(ctx context.Context, providerID string) (cl return cloudprovider.Zone{}, nil } - nodeName, err := az.vmSet.GetNodeNameByProviderID(providerID) + nodeName, err := az.VMSet.GetNodeNameByProviderID(providerID) if err != nil { return cloudprovider.Zone{}, err } @@ -126,5 +126,5 @@ func (az *Cloud) GetZoneByNodeName(ctx context.Context, nodeName types.NodeName) return cloudprovider.Zone{}, nil } - return az.vmSet.GetZoneByNodeName(string(nodeName)) + return az.VMSet.GetZoneByNodeName(string(nodeName)) } diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/BUILD b/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/BUILD index f162bab2db35..283a95d042a9 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/BUILD +++ b/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/BUILD @@ -19,6 +19,7 @@ go_library( "//vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest:go_default_library", "//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library", + "//vendor/github.com/Azure/go-autorest/autorest/to:go_default_library", "//vendor/k8s.io/klog/v2:go_default_library", ], ) diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/azure_diskclient.go b/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/azure_diskclient.go index 396510e6463f..3ac28f1f75aa 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/azure_diskclient.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/azure_diskclient.go @@ -20,12 +20,14 @@ package diskclient import ( "context" + "fmt" "net/http" "time" "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-12-01/compute" "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/to" "k8s.io/client-go/util/flowcontrol" "k8s.io/klog/v2" @@ -204,6 +206,74 @@ func (c *Client) createOrUpdateResponder(resp *http.Response) (*compute.Disk, *r return result, retry.GetError(resp, err) } +// Update creates or updates a Disk. +func (c *Client) Update(ctx context.Context, resourceGroupName string, diskName string, diskParameter compute.DiskUpdate) *retry.Error { + mc := metrics.NewMetricContext("disks", "update", resourceGroupName, c.subscriptionID, "") + + // Report errors if the client is rate limited. + if !c.rateLimiterWriter.TryAccept() { + mc.RateLimitedCount() + return retry.GetRateLimitError(true, "DiskUpdate") + } + + // Report errors if the client is throttled. + if c.RetryAfterWriter.After(time.Now()) { + mc.ThrottledCount() + rerr := retry.GetThrottlingError("DiskUpdate", "client throttled", c.RetryAfterWriter) + return rerr + } + + rerr := c.updateDisk(ctx, resourceGroupName, diskName, diskParameter) + mc.Observe(rerr.Error()) + if rerr != nil { + if rerr.IsThrottled() { + // Update RetryAfterReader so that no more requests would be sent until RetryAfter expires. + c.RetryAfterWriter = rerr.RetryAfter + } + + return rerr + } + + return nil +} + +// updateDisk updates a Disk. +func (c *Client) updateDisk(ctx context.Context, resourceGroupName string, diskName string, diskParameter compute.DiskUpdate) *retry.Error { + resourceID := armclient.GetResourceID( + c.subscriptionID, + resourceGroupName, + "Microsoft.Compute/disks", + diskName, + ) + + response, rerr := c.armClient.PatchResource(ctx, resourceID, diskParameter) + defer c.armClient.CloseResponse(ctx, response) + if rerr != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "disk.put.request", resourceID, rerr.Error()) + return rerr + } + + if response != nil && response.StatusCode != http.StatusNoContent { + _, rerr = c.updateResponder(response) + if rerr != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "disk.put.respond", resourceID, rerr.Error()) + return rerr + } + } + + return nil +} + +func (c *Client) updateResponder(resp *http.Response) (*compute.Disk, *retry.Error) { + result := &compute.Disk{} + err := autorest.Respond( + resp, + azure.WithErrorUnlessStatusCode(http.StatusOK, http.StatusCreated), + autorest.ByUnmarshallingJSON(&result)) + result.Response = autorest.Response{Response: resp} + return result, retry.GetError(resp, err) +} + // Delete deletes a Disk by name. func (c *Client) Delete(ctx context.Context, resourceGroupName string, diskName string) *retry.Error { mc := metrics.NewMetricContext("disks", "delete", resourceGroupName, c.subscriptionID, "") @@ -246,3 +316,126 @@ func (c *Client) deleteDisk(ctx context.Context, resourceGroupName string, diskN return c.armClient.DeleteResource(ctx, resourceID, "") } + +// ListByResourceGroup lists all the disks under a resource group. +func (c *Client) ListByResourceGroup(ctx context.Context, resourceGroupName string) ([]compute.Disk, *retry.Error) { + resourceID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/disks", + autorest.Encode("path", c.subscriptionID), + autorest.Encode("path", resourceGroupName)) + + result := make([]compute.Disk, 0) + page := &DiskListPage{} + page.fn = c.listNextResults + + resp, rerr := c.armClient.GetResource(ctx, resourceID, "") + defer c.armClient.CloseResponse(ctx, resp) + if rerr != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "disk.list.request", resourceID, rerr.Error()) + return result, rerr + } + + var err error + page.dl, err = c.listResponder(resp) + if err != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "disk.list.respond", resourceID, err) + return result, retry.GetError(resp, err) + } + + for page.NotDone() { + result = append(result, *page.Response().Value...) + if err = page.NextWithContext(ctx); err != nil { + klog.V(5).Infof("Received error in %s: resourceID: %s, error: %s", "disk.list.next", resourceID, err) + return result, retry.GetError(page.Response().Response.Response, err) + } + } + + return result, nil +} + +// listNextResults retrieves the next set of results, if any. +func (c *Client) listNextResults(ctx context.Context, lastResults compute.DiskList) (result compute.DiskList, err error) { + req, err := c.diskListPreparer(ctx, lastResults) + if err != nil { + return result, autorest.NewErrorWithError(err, "diskclient", "listNextResults", nil, "Failure preparing next results request") + } + if req == nil { + return + } + + resp, rerr := c.armClient.Send(ctx, req) + defer c.armClient.CloseResponse(ctx, resp) + if rerr != nil { + result.Response = autorest.Response{Response: resp} + return result, autorest.NewErrorWithError(rerr.Error(), "diskclient", "listNextResults", resp, "Failure sending next results request") + } + + result, err = c.listResponder(resp) + if err != nil { + err = autorest.NewErrorWithError(err, "diskclient", "listNextResults", resp, "Failure responding to next results request") + } + return +} + +// listResponder handles the response to the List request. The method always +// closes the http.Response Body. +func (c *Client) listResponder(resp *http.Response) (result compute.DiskList, err error) { + err = autorest.Respond( + resp, + azure.WithErrorUnlessStatusCode(http.StatusOK), + autorest.ByUnmarshallingJSON(&result), + autorest.ByClosing()) + result.Response = autorest.Response{Response: resp} + return +} + +func (c *Client) diskListPreparer(ctx context.Context, lr compute.DiskList) (*http.Request, error) { + if lr.NextLink == nil || len(to.String(lr.NextLink)) < 1 { + return nil, nil + } + return autorest.Prepare((&http.Request{}).WithContext(ctx), + autorest.AsJSON(), + autorest.AsGet(), + autorest.WithBaseURL(to.String(lr.NextLink))) +} + +// DiskListPage contains a page of Disk values. +type DiskListPage struct { + fn func(context.Context, compute.DiskList) (compute.DiskList, error) + dl compute.DiskList +} + +// NextWithContext advances to the next page of values. If there was an error making +// the request the page does not advance and the error is returned. +func (page *DiskListPage) NextWithContext(ctx context.Context) (err error) { + next, err := page.fn(ctx, page.dl) + if err != nil { + return err + } + page.dl = next + return nil +} + +// Next advances to the next page of values. If there was an error making +// the request the page does not advance and the error is returned. +// Deprecated: Use NextWithContext() instead. +func (page *DiskListPage) Next() error { + return page.NextWithContext(context.Background()) +} + +// NotDone returns true if the page enumeration should be started or is not yet complete. +func (page DiskListPage) NotDone() bool { + return !page.dl.IsEmpty() +} + +// Response returns the raw server response from the last page request. +func (page DiskListPage) Response() compute.DiskList { + return page.dl +} + +// Values returns the slice of values for the current page or nil if there are no values. +func (page DiskListPage) Values() []compute.Disk { + if page.dl.IsEmpty() { + return nil + } + return *page.dl.Value +} diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/interface.go b/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/interface.go index 3f4be1e5939e..f68c4282c4bd 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/interface.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/interface.go @@ -40,6 +40,12 @@ type Interface interface { // CreateOrUpdate creates or updates a Disk. CreateOrUpdate(ctx context.Context, resourceGroupName string, diskName string, diskParameter compute.Disk) *retry.Error + // Update updates a Disk. + Update(ctx context.Context, resourceGroupName string, diskName string, diskParameter compute.DiskUpdate) *retry.Error + // Delete deletes a Disk by name. Delete(ctx context.Context, resourceGroupName string, diskName string) *retry.Error + + // ListByResourceGroup lists all the disks under a resource group. + ListByResourceGroup(ctx context.Context, resourceGroupName string) ([]compute.Disk, *retry.Error) } diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/interface.go b/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/interface.go index dfd26723592c..eb60a91264ba 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/interface.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/clients/diskclient/mockdiskclient/interface.go @@ -79,6 +79,20 @@ func (mr *MockInterfaceMockRecorder) CreateOrUpdate(ctx, resourceGroupName, disk return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOrUpdate", reflect.TypeOf((*MockInterface)(nil).CreateOrUpdate), ctx, resourceGroupName, diskName, diskParameter) } +// Update mocks base method +func (m *MockInterface) Update(ctx context.Context, resourceGroupName, diskName string, diskParameter compute.DiskUpdate) *retry.Error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Update", ctx, resourceGroupName, diskName, diskParameter) + ret0, _ := ret[0].(*retry.Error) + return ret0 +} + +// Update indicates an expected call of Update +func (mr *MockInterfaceMockRecorder) Update(ctx, resourceGroupName, diskName, diskParameter interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockInterface)(nil).Update), ctx, resourceGroupName, diskName, diskParameter) +} + // Delete mocks base method func (m *MockInterface) Delete(ctx context.Context, resourceGroupName, diskName string) *retry.Error { m.ctrl.T.Helper() @@ -92,3 +106,18 @@ func (mr *MockInterfaceMockRecorder) Delete(ctx, resourceGroupName, diskName int mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockInterface)(nil).Delete), ctx, resourceGroupName, diskName) } + +// ListByResourceGroup mocks base method +func (m *MockInterface) ListByResourceGroup(ctx context.Context, resourceGroupName string) ([]compute.Disk, *retry.Error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListByResourceGroup", ctx, resourceGroupName) + ret0, _ := ret[0].([]compute.Disk) + ret1, _ := ret[1].(*retry.Error) + return ret0, ret1 +} + +// ListByResourceGroup indicates an expected call of ListByResourceGroup +func (mr *MockInterfaceMockRecorder) ListByResourceGroup(ctx, resourceGroupName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListByResourceGroup", reflect.TypeOf((*MockInterface)(nil).Delete), ctx, resourceGroupName) +} diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/metrics/azure_metrics.go b/vendor/k8s.io/legacy-cloud-providers/azure/metrics/azure_metrics.go index 93c51daa87c9..928c9c42fb83 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/metrics/azure_metrics.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/metrics/azure_metrics.go @@ -86,6 +86,7 @@ func registerAPIMetrics(attributes ...string) *apiCallMetrics { &metrics.HistogramOpts{ Name: "cloudprovider_azure_api_request_duration_seconds", Help: "Latency of an Azure API call", + Buckets: []float64{.1, .25, .5, 1, 2.5, 5, 10, 15, 25, 50, 120, 300, 600, 1200}, StabilityLevel: metrics.ALPHA, }, attributes, diff --git a/vendor/k8s.io/legacy-cloud-providers/azure/retry/azure_error.go b/vendor/k8s.io/legacy-cloud-providers/azure/retry/azure_error.go index 02403e7ef015..ed130852ab0d 100644 --- a/vendor/k8s.io/legacy-cloud-providers/azure/retry/azure_error.go +++ b/vendor/k8s.io/legacy-cloud-providers/azure/retry/azure_error.go @@ -89,6 +89,15 @@ func (err *Error) IsThrottled() bool { return err.HTTPStatusCode == http.StatusTooManyRequests || err.RetryAfter.After(now()) } +// IsNotFound returns true the if the requested object wasn't found +func (err *Error) IsNotFound() bool { + if err == nil { + return false + } + + return err.HTTPStatusCode == http.StatusNotFound +} + // NewError creates a new Error. func NewError(retriable bool, err error) *Error { return &Error{ @@ -286,3 +295,20 @@ func IsErrorRetriable(err error) bool { return strings.Contains(err.Error(), "Retriable: true") } + +// HasStatusForbiddenOrIgnoredError return true if the given error code is part of the error message +// This should only be used when trying to delete resources +func HasStatusForbiddenOrIgnoredError(err error) bool { + if err == nil { + return false + } + + if strings.Contains(err.Error(), fmt.Sprintf("HTTPStatusCode: %d", http.StatusNotFound)) { + return true + } + + if strings.Contains(err.Error(), fmt.Sprintf("HTTPStatusCode: %d", http.StatusForbidden)) { + return true + } + return false +} diff --git a/vendor/k8s.io/legacy-cloud-providers/gce/gce_instances.go b/vendor/k8s.io/legacy-cloud-providers/gce/gce_instances.go index 6a1e1acb9f97..33a3c119b47a 100644 --- a/vendor/k8s.io/legacy-cloud-providers/gce/gce_instances.go +++ b/vendor/k8s.io/legacy-cloud-providers/gce/gce_instances.go @@ -498,7 +498,11 @@ func (g *Cloud) getInstancesByNames(names []string) ([]*gceInstance, error) { return nil, err } if len(foundInstances) != len(names) { - return nil, cloudprovider.InstanceNotFound + if len(foundInstances) == 0 { + // return error so the TargetPool nodecount does not drop to 0 unexpectedly. + return nil, cloudprovider.InstanceNotFound + } + klog.Warningf("getFoundInstanceByNames - input instances %d, found %d. Continuing LoadBalancer Update", len(names), len(foundInstances)) } return foundInstances, nil } diff --git a/vendor/k8s.io/legacy-cloud-providers/openstack/openstack.go b/vendor/k8s.io/legacy-cloud-providers/openstack/openstack.go index 9d56ba11cec4..8355cf8eff27 100644 --- a/vendor/k8s.io/legacy-cloud-providers/openstack/openstack.go +++ b/vendor/k8s.io/legacy-cloud-providers/openstack/openstack.go @@ -281,7 +281,7 @@ func (os *OpenStack) setConfigFromSecret() error { secret, err := os.secretLister.Secrets(os.secretNamespace).Get(os.secretName) if err != nil { - klog.Errorf("Cannot get secret %s in namespace %s. error: %q", os.secretName, os.secretNamespace, err) + klog.Errorf("cannot get secret %s in namespace %s. error: %q", os.secretName, os.secretNamespace, err) return err } @@ -290,11 +290,11 @@ func (os *OpenStack) setConfigFromSecret() error { err = gcfg.ReadStringInto(cfg, string(content)) if err != nil { - return fmt.Errorf("cannot parse data from the secret") + return fmt.Errorf("cannot parse data from the secret: %s", err) } provider, err := newProvider(*cfg) if err != nil { - return fmt.Errorf("cannot initialize cloud provider using data from the secret") + return fmt.Errorf("cannot initialize cloud provider using data from the secret: %s", err) } os.provider = provider os.region = cfg.Global.Region @@ -312,9 +312,10 @@ func (os *OpenStack) ensureCloudProviderWasInitialized() error { if os.secretName != "" && os.secretNamespace != "" { err := os.setConfigFromSecret() - if err == nil { - return nil + if err != nil { + return fmt.Errorf("cloud provider is not initialized: %s", err) } + return nil } return fmt.Errorf("cloud provider is not initialized") @@ -876,6 +877,10 @@ func (os *OpenStack) Routes() (cloudprovider.Routes, bool) { } func (os *OpenStack) volumeService(forceVersion string) (volumeService, error) { + if err := os.ensureCloudProviderWasInitialized(); err != nil { + return nil, err + } + bsVersion := "" if forceVersion == "" { bsVersion = os.bsOpts.BSVersion diff --git a/vendor/k8s.io/legacy-cloud-providers/vsphere/vsphere.go b/vendor/k8s.io/legacy-cloud-providers/vsphere/vsphere.go index 12da586427a6..aa09c1419756 100644 --- a/vendor/k8s.io/legacy-cloud-providers/vsphere/vsphere.go +++ b/vendor/k8s.io/legacy-cloud-providers/vsphere/vsphere.go @@ -1500,7 +1500,7 @@ func (vs *VSphere) SecretAdded(obj interface{}) { return } - klog.V(4).Infof("secret added: %+v", obj) + klog.V(4).Infof("refreshing node cache for secret: %s/%s", secret.Namespace, secret.Name) vs.refreshNodesForSecretChange() } @@ -1524,7 +1524,7 @@ func (vs *VSphere) SecretUpdated(obj interface{}, newObj interface{}) { return } - klog.V(4).Infof("secret updated: %+v", newObj) + klog.V(4).Infof("refreshing node cache for secret: %s/%s", secret.Namespace, secret.Name) vs.refreshNodesForSecretChange() } diff --git a/vendor/modules.txt b/vendor/modules.txt index 12cdc420656f..1cc4a2f483b7 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -173,7 +173,7 @@ github.com/containernetworking/cni/pkg/types/current github.com/containernetworking/cni/pkg/version # github.com/coreos/go-oidc v2.1.0+incompatible => github.com/coreos/go-oidc v2.1.0+incompatible github.com/coreos/go-oidc -# github.com/coreos/go-semver v0.3.0 => github.com/coreos/go-semver v0.3.0 +# github.com/coreos/go-semver v0.2.0 => github.com/coreos/go-semver v0.3.0 github.com/coreos/go-semver/semver # github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e => github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e github.com/coreos/go-systemd/daemon @@ -792,7 +792,7 @@ github.com/openshift/client-go/user/informers/externalversions/internalinterface github.com/openshift/client-go/user/informers/externalversions/user github.com/openshift/client-go/user/informers/externalversions/user/v1 github.com/openshift/client-go/user/listers/user/v1 -# github.com/openshift/library-go v0.0.0-20200902112127-a4e32e339219 +# github.com/openshift/library-go v0.0.0-20201123125610-83d6d67a1e98 ## explicit github.com/openshift/library-go/pkg/apiserver/admission/admissionrestconfig github.com/openshift/library-go/pkg/apiserver/admission/admissiontimeout @@ -821,6 +821,7 @@ github.com/openshift/library-go/pkg/image/imageutil github.com/openshift/library-go/pkg/image/internal/digest github.com/openshift/library-go/pkg/image/internal/reference github.com/openshift/library-go/pkg/image/reference +github.com/openshift/library-go/pkg/network github.com/openshift/library-go/pkg/network/networkutils github.com/openshift/library-go/pkg/oauth/oauthdiscovery github.com/openshift/library-go/pkg/operator/events @@ -974,7 +975,7 @@ github.com/xanzy/ssh-agent ## explicit # github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 => github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 github.com/xiang90/probing -# go.etcd.io/bbolt v1.3.5 => go.etcd.io/bbolt v1.3.3 +# go.etcd.io/bbolt v1.3.3 => go.etcd.io/bbolt v1.3.3 go.etcd.io/bbolt # go.etcd.io/etcd v3.3.17+incompatible => go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 ## explicit @@ -1494,7 +1495,7 @@ k8s.io/apimachinery/pkg/watch k8s.io/apimachinery/third_party/forked/golang/json k8s.io/apimachinery/third_party/forked/golang/netutil k8s.io/apimachinery/third_party/forked/golang/reflect -# k8s.io/apiserver v0.19.0 => github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20201002011447-1fc699e9f6be +# k8s.io/apiserver v0.19.0 => github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20210219020830-8d1242094f14 ## explicit k8s.io/apiserver/pkg/admission k8s.io/apiserver/pkg/admission/configuration @@ -1639,7 +1640,7 @@ k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/patch k8s.io/cli-runtime/pkg/kustomize/k8sdeps/validator k8s.io/cli-runtime/pkg/printers k8s.io/cli-runtime/pkg/resource -# k8s.io/client-go v0.19.0 => github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20201002011447-1fc699e9f6be +# k8s.io/client-go v0.19.0 => github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20210219020830-8d1242094f14 ## explicit k8s.io/client-go/discovery k8s.io/client-go/discovery/cached @@ -1885,7 +1886,7 @@ k8s.io/client-go/util/jsonpath k8s.io/client-go/util/keyutil k8s.io/client-go/util/retry k8s.io/client-go/util/workqueue -# k8s.io/cloud-provider v0.19.0-rc.2 => github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20201002011447-1fc699e9f6be +# k8s.io/cloud-provider v0.19.0-rc.2 => github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20210219020830-8d1242094f14 k8s.io/cloud-provider k8s.io/cloud-provider/api k8s.io/cloud-provider/node/helpers @@ -1898,7 +1899,7 @@ k8s.io/cluster-bootstrap/token/api k8s.io/cluster-bootstrap/token/util k8s.io/cluster-bootstrap/util/secrets k8s.io/cluster-bootstrap/util/tokens -# k8s.io/component-base v0.19.0 => k8s.io/component-base v0.19.0-rc.2 +# k8s.io/component-base v0.19.0 => github.com/openshift/kubernetes/staging/src/k8s.io/component-base v0.0.0-20210219020830-8d1242094f14 ## explicit k8s.io/component-base/cli/flag k8s.io/component-base/cli/globalflag @@ -1926,11 +1927,11 @@ k8s.io/cri-api/pkg/apis/runtime/v1alpha2 k8s.io/csi-translation-lib k8s.io/csi-translation-lib/plugins # k8s.io/klog v1.0.0 => k8s.io/klog v1.0.0 -## explicit k8s.io/klog # k8s.io/klog/v2 v2.3.0 +## explicit k8s.io/klog/v2 -# k8s.io/kube-aggregator v0.19.0 => github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20201002011447-1fc699e9f6be +# k8s.io/kube-aggregator v0.19.0 => github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20210219020830-8d1242094f14 k8s.io/kube-aggregator/pkg/apis/apiregistration k8s.io/kube-aggregator/pkg/apis/apiregistration/install k8s.io/kube-aggregator/pkg/apis/apiregistration/v1 @@ -2002,7 +2003,7 @@ k8s.io/kubectl/pkg/validation k8s.io/kubelet/config/v1beta1 k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1 k8s.io/kubelet/pkg/apis/pluginregistration/v1 -# k8s.io/kubernetes v1.19.0 => github.com/openshift/kubernetes v1.20.0-alpha.0.0.20201002011447-1fc699e9f6be +# k8s.io/kubernetes v1.19.0 => github.com/openshift/kubernetes v1.20.0-alpha.0.0.20210219020830-8d1242094f14 ## explicit k8s.io/kubernetes/cmd/kube-apiserver/app k8s.io/kubernetes/cmd/kube-apiserver/app/options @@ -2753,7 +2754,7 @@ k8s.io/kubernetes/third_party/forked/gonum/graph k8s.io/kubernetes/third_party/forked/gonum/graph/internal/linear k8s.io/kubernetes/third_party/forked/gonum/graph/simple k8s.io/kubernetes/third_party/forked/gonum/graph/traverse -# k8s.io/legacy-cloud-providers v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/legacy-cloud-providers v0.0.0-20201002011447-1fc699e9f6be +# k8s.io/legacy-cloud-providers v0.0.0 => github.com/openshift/kubernetes/staging/src/k8s.io/legacy-cloud-providers v0.0.0-20210219020830-8d1242094f14 ## explicit k8s.io/legacy-cloud-providers/aws k8s.io/legacy-cloud-providers/azure @@ -3205,26 +3206,26 @@ sigs.k8s.io/yaml # k8s.io/api => k8s.io/api v0.19.0-rc.2 # k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.19.0-rc.2 # k8s.io/apimachinery => k8s.io/apimachinery v0.19.0-rc.2 -# k8s.io/apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20201002011447-1fc699e9f6be +# k8s.io/apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20210219020830-8d1242094f14 # k8s.io/cli-runtime => k8s.io/cli-runtime v0.19.0-rc.2 -# k8s.io/client-go => github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20201002011447-1fc699e9f6be -# k8s.io/cloud-provider => github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20201002011447-1fc699e9f6be +# k8s.io/client-go => github.com/openshift/kubernetes/staging/src/k8s.io/client-go v0.0.0-20210219020830-8d1242094f14 +# k8s.io/cloud-provider => github.com/openshift/kubernetes/staging/src/k8s.io/cloud-provider v0.0.0-20210219020830-8d1242094f14 # k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.19.0-rc.2 # k8s.io/code-generator => k8s.io/code-generator v0.19.0-rc.2 -# k8s.io/component-base => k8s.io/component-base v0.19.0-rc.2 +# k8s.io/component-base => github.com/openshift/kubernetes/staging/src/k8s.io/component-base v0.0.0-20210219020830-8d1242094f14 # k8s.io/cri-api => k8s.io/cri-api v0.19.0-rc.2 # k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.19.0-rc.2 # k8s.io/gengo => k8s.io/gengo v0.0.0-20200114144118-36b2048a9120 # k8s.io/heapster => k8s.io/heapster v1.2.0-beta.1 # k8s.io/klog => k8s.io/klog v1.0.0 -# k8s.io/kube-aggregator => github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20201002011447-1fc699e9f6be +# k8s.io/kube-aggregator => github.com/openshift/kubernetes/staging/src/k8s.io/kube-aggregator v0.0.0-20210219020830-8d1242094f14 # k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.19.0-rc.2 # k8s.io/kube-proxy => k8s.io/kube-proxy v0.19.0-rc.2 # k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.19.0-rc.2 # k8s.io/kubectl => k8s.io/kubectl v0.19.0-rc.2 # k8s.io/kubelet => k8s.io/kubelet v0.19.0-rc.2 -# k8s.io/kubernetes => github.com/openshift/kubernetes v1.20.0-alpha.0.0.20201002011447-1fc699e9f6be -# k8s.io/legacy-cloud-providers => github.com/openshift/kubernetes/staging/src/k8s.io/legacy-cloud-providers v0.0.0-20201002011447-1fc699e9f6be +# k8s.io/kubernetes => github.com/openshift/kubernetes v1.20.0-alpha.0.0.20210219020830-8d1242094f14 +# k8s.io/legacy-cloud-providers => github.com/openshift/kubernetes/staging/src/k8s.io/legacy-cloud-providers v0.0.0-20210219020830-8d1242094f14 # k8s.io/metrics => k8s.io/metrics v0.19.0-rc.2 # k8s.io/repo-infra => k8s.io/repo-infra v0.0.1-alpha.1 # k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.19.0-rc.2