// waitForLimitSync waits until a usage of a quota reaches given limit with a short timeout func waitForLimitSync(oc *exutil.CLI, hardLimit kapi.ResourceList) error { g.By(fmt.Sprintf("waiting for resource quota %s to get updated", quotaName)) return testutil.WaitForResourceQuotaLimitSync( oc.KubeREST().ResourceQuotas(oc.Namespace()), quotaName, hardLimit, waitTimeout) }
func waitForEndpointsAvailable(oc *exutil.CLI, serviceName string) error { return wait.Poll(200*time.Millisecond, 2*time.Minute, func() (bool, error) { ep, err := oc.KubeREST().Endpoints(oc.Namespace()).Get(serviceName) // Tolerate NotFound b/c it could take a moment for the endpoints to be created if errors.TolerateNotFoundError(err) != nil { return false, err } return (len(ep.Subsets) > 0) && (len(ep.Subsets[0].Addresses) > 0), nil }) }
func waitForNoPodsAvailable(oc *exutil.CLI) error { return wait.Poll(200*time.Millisecond, 2*time.Minute, func() (bool, error) { //ep, err := oc.KubeREST().Endpoints(oc.Namespace()).Get(serviceName) pods, err := oc.KubeREST().Pods(oc.Namespace()).List(kapi.ListOptions{}) if err != nil { return false, err } return len(pods.Items) == 0, nil }) }
// QueryPrivileged executes an SQL query as a root user and returns the result. func (m MySQL) QueryPrivileged(oc *util.CLI, query string) (string, error) { container, err := firstContainerName(oc.KubeREST().Pods(oc.Namespace()), m.podName) if err != nil { return "", err } masterConf, err := getPodConfig(oc.KubeREST().Pods(oc.Namespace()), m.masterPodName) if err != nil { return "", err } return oc.Run("exec").Args(m.podName, "-c", container, "--", "bash", "-c", fmt.Sprintf("mysql -h 127.0.0.1 -uroot -e \"%s\" %s", query, masterConf.Env["MYSQL_DATABASE"])).Output() }
// QueryPrivileged executes an SQL query as a root user and returns the result. func (m PostgreSQL) QueryPrivileged(oc *util.CLI, query string) (string, error) { container, err := firstContainerName(oc.KubeREST().Pods(oc.Namespace()), m.podName) if err != nil { return "", err } masterConf, err := getPodConfig(oc.KubeREST().Pods(oc.Namespace()), m.masterPodName) if err != nil { return "", err } return oc.Run("exec").Args(m.podName, "-c", container, "--", "bash", "-c", fmt.Sprintf("psql postgres://postgres:%[email protected]/%s -x -c \"%s\"", masterConf.Env["POSTGRESQL_ADMIN_PASSWORD"], masterConf.Env["POSTGRESQL_DATABASE"], query)).Output() }
// waitForResourceQuotaSync waits until a usage of a quota reaches given limit with a short timeout func waitForResourceQuotaSync(oc *exutil.CLI, name string, expectedResources kapi.ResourceList) (kapi.ResourceList, error) { g.By(fmt.Sprintf("waiting for resource quota %s to get updated", name)) used, err := exutil.WaitForResourceQuotaSync( oc.KubeREST().ResourceQuotas(oc.Namespace()), quotaName, expectedResources, false, waitTimeout, ) if err != nil { return nil, err } return used, nil }
func waitForNumberOfPodsWithLabel(oc *exutil.CLI, number int, label string) []string { g.By(fmt.Sprintf("expecting that there are %d running pods with label name=%s", number, label)) podNames, err := exutil.WaitForPods( oc.KubeREST().Pods(oc.Namespace()), exutil.ParseLabelsOrDie("name="+label), exutil.CheckPodIsRunningFn, number, 1*time.Minute, ) o.Expect(err).ShouldNot(o.HaveOccurred()) o.Expect(podNames).Should(o.HaveLen(number)) return podNames }
// TestRemoteLogin will test whether we can login through to a remote database. func (m PostgreSQL) TestRemoteLogin(oc *util.CLI, hostAddress string) error { container, err := firstContainerName(oc.KubeREST().Pods(oc.Namespace()), m.podName) if err != nil { return err } masterConf, err := getPodConfig(oc.KubeREST().Pods(oc.Namespace()), m.masterPodName) if err != nil { return err } err = oc.Run("exec").Args(m.podName, "-c", container, "--", "bash", "-c", fmt.Sprintf("psql postgres://%s:%s@%s/%s -x -c \"SELECT 1;\"", masterConf.Env["POSTGRESQL_USER"], masterConf.Env["POSTGRESQL_PASSWORD"], hostAddress, masterConf.Env["POSTGRESQL_DATABASE"])).Execute() return err }
// ModifySourceCode will modify source code in the pod of the application // according to the sed script. func ModifySourceCode(oc *exutil.CLI, selector labels.Selector, sedScript, file string) error { pods, err := exutil.WaitForPods(oc.KubeREST().Pods(oc.Namespace()), selector, exutil.CheckPodIsRunningFunc, 1, 120*time.Second) if err != nil { return err } if len(pods) != 1 { return fmt.Errorf("Got %d pods for selector %v, expected 1", len(pods), selector) } pod, err := oc.KubeREST().Pods(oc.Namespace()).Get(pods[0]) if err != nil { return err } return oc.Run("exec").Args(pod.Name, "-c", pod.Spec.Containers[0].Name, "--", "sed", "-ie", sedScript, file).Execute() }
// TestRemoteLogin will test whether we can login through to a remote database. func (m MySQL) TestRemoteLogin(oc *util.CLI, hostAddress string) error { container, err := firstContainerName(oc.KubeREST().Pods(oc.Namespace()), m.podName) if err != nil { return err } masterConf, err := getPodConfig(oc.KubeREST().Pods(oc.Namespace()), m.masterPodName) if err != nil { return err } err = oc.Run("exec").Args(m.podName, "-c", container, "--", "bash", "-c", fmt.Sprintf("mysql -h %s -u%s -p%s -e \"SELECT 1;\" %s", hostAddress, masterConf.Env["MYSQL_USER"], masterConf.Env["MYSQL_PASSWORD"], masterConf.Env["MYSQL_DATABASE"])).Execute() return err }
// IsReady pings the PostgreSQL server. func (m PostgreSQL) IsReady(oc *util.CLI) (bool, error) { conf, err := getPodConfig(oc.KubeREST().Pods(oc.Namespace()), m.podName) if err != nil { return false, err } out, err := oc.Run("exec").Args(m.podName, "-c", conf.Container, "--", "bash", "-c", "psql postgresql://[email protected] -x -c \"SELECT 1;\"").Output() if err != nil { switch err.(type) { case *util.ExitError, *exec.ExitError: return false, nil default: return false, err } } return strings.Contains(out, "-[ RECORD 1 ]\n?column? | 1"), nil }
// RunInPodContainer will run provided command in the specified pod container. func RunInPodContainer(oc *exutil.CLI, selector labels.Selector, cmd []string) error { pods, err := exutil.WaitForPods(oc.KubeREST().Pods(oc.Namespace()), selector, exutil.CheckPodIsRunningFn, 1, 2*time.Minute) if err != nil { return err } if len(pods) != 1 { return fmt.Errorf("Got %d pods for selector %v, expected 1", len(pods), selector) } pod, err := oc.KubeREST().Pods(oc.Namespace()).Get(pods[0]) if err != nil { return err } args := []string{pod.Name, "-c", pod.Spec.Containers[0].Name, "--"} args = append(args, cmd...) return oc.Run("exec").Args(args...).Execute() }
// IsReady pings the MySQL server. func (m MySQL) IsReady(oc *util.CLI) (bool, error) { conf, err := getPodConfig(oc.KubeREST().Pods(oc.Namespace()), m.podName) if err != nil { return false, err } out, err := oc.Run("exec").Args(m.podName, "-c", conf.Container, "--", "bash", "-c", "mysqladmin -h 127.0.0.1 -uroot ping").Output() if err != nil { switch err.(type) { case *util.ExitError, *exec.ExitError: return false, nil default: return false, err } } return strings.Contains(out, "mysqld is alive"), nil }
func checkSingleIdle(oc *exutil.CLI, idlingFile string, resources map[string][]string, resourceName string, kind string) { g.By("Idling the service") _, err := oc.Run("idle").Args("--resource-names-file", idlingFile).Output() o.Expect(err).ToNot(o.HaveOccurred()) g.By("Ensuring the scale is zero (and stays zero)") objName := resources[resourceName][0] // make sure we don't get woken up by an incorrect router health check or anything like that o.Consistently(func() (string, error) { return oc.Run("get").Args(resourceName+"/"+objName, "--output=jsonpath=\"{.spec.replicas}\"").Output() }, 20*time.Second, 500*time.Millisecond).Should(o.ContainSubstring("0")) g.By("Fetching the service and checking the annotations are present") serviceName := resources["service"][0] endpoints, err := oc.KubeREST().Endpoints(oc.Namespace()).Get(serviceName) o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(endpoints.Annotations).To(o.HaveKey(unidlingapi.IdledAtAnnotation)) o.Expect(endpoints.Annotations).To(o.HaveKey(unidlingapi.UnidleTargetAnnotation)) g.By("Checking the idled-at time") idledAtAnnotation := endpoints.Annotations[unidlingapi.IdledAtAnnotation] idledAtTime, err := time.Parse(time.RFC3339, idledAtAnnotation) o.Expect(err).ToNot(o.HaveOccurred()) o.Expect(idledAtTime).To(o.BeTemporally("~", time.Now(), 5*time.Minute)) g.By("Checking the idle targets") unidleTargetAnnotation := endpoints.Annotations[unidlingapi.UnidleTargetAnnotation] unidleTargets := []unidlingapi.RecordedScaleReference{} err = json.Unmarshal([]byte(unidleTargetAnnotation), &unidleTargets) o.Expect(err).ToNot(o.HaveOccurred()) o.Expect(unidleTargets).To(o.Equal([]unidlingapi.RecordedScaleReference{ { Replicas: 2, CrossGroupObjectReference: unidlingapi.CrossGroupObjectReference{ Name: resources[resourceName][0], Kind: kind, }, }, })) }
func deploymentInfo(oc *exutil.CLI, name string) (*deployapi.DeploymentConfig, []kapi.ReplicationController, []kapi.Pod, error) { dc, err := oc.REST().DeploymentConfigs(oc.Namespace()).Get(name) if err != nil { return nil, nil, nil, err } // get pods before RCs, so we see more RCs than pods. pods, err := oc.KubeREST().Pods(oc.Namespace()).List(kapi.ListOptions{}) if err != nil { return nil, nil, nil, err } rcs, err := oc.KubeREST().ReplicationControllers(oc.Namespace()).List(kapi.ListOptions{ LabelSelector: deployutil.ConfigSelector(name), }) if err != nil { return nil, nil, nil, err } sort.Sort(deployutil.ByLatestVersionAsc(rcs.Items)) return dc, rcs.Items, pods.Items, nil }
func PostgreSQLReplicationTestFactory(oc *exutil.CLI, image string) func() { return func() { oc.SetOutputDir(exutil.TestContext.OutputDir) defer cleanup(oc) _, err := exutil.SetupHostPathVolumes(oc.AdminKubeREST().PersistentVolumes(), oc.Namespace(), "512Mi", 1) o.Expect(err).NotTo(o.HaveOccurred()) err = testutil.WaitForPolicyUpdate(oc.REST(), oc.Namespace(), "create", templateapi.Resource("templates"), true) o.Expect(err).NotTo(o.HaveOccurred()) exutil.CheckOpenShiftNamespaceImageStreams(oc) err = oc.Run("new-app").Args("-f", postgreSQLReplicationTemplate, "-p", fmt.Sprintf("POSTGRESQL_IMAGE=%s", image)).Execute() o.Expect(err).NotTo(o.HaveOccurred()) err = oc.Run("new-app").Args("-f", postgreSQLEphemeralTemplate, "-p", fmt.Sprintf("DATABASE_SERVICE_NAME=%s", postgreSQLHelperName)).Execute() o.Expect(err).NotTo(o.HaveOccurred()) // oc.KubeFramework().WaitForAnEndpoint currently will wait forever; for now, prefacing with our WaitForADeploymentToComplete, // which does have a timeout, since in most cases a failure in the service coming up stems from a failed deployment err = exutil.WaitForADeploymentToComplete(oc.KubeREST().ReplicationControllers(oc.Namespace()), postgreSQLHelperName, oc) o.Expect(err).NotTo(o.HaveOccurred()) err = oc.KubeFramework().WaitForAnEndpoint(postgreSQLHelperName) o.Expect(err).NotTo(o.HaveOccurred()) tableCounter := 0 assertReplicationIsWorking := func(masterDeployment, slaveDeployment string, slaveCount int) (exutil.Database, []exutil.Database, exutil.Database) { tableCounter++ table := fmt.Sprintf("table_%0.2d", tableCounter) master, slaves, helper := CreatePostgreSQLReplicationHelpers(oc.KubeREST().Pods(oc.Namespace()), masterDeployment, slaveDeployment, fmt.Sprintf("%s-1", postgreSQLHelperName), slaveCount) err := exutil.WaitUntilAllHelpersAreUp(oc, []exutil.Database{master, helper}) if err != nil { exutil.DumpDeploymentLogs("postgresql-helper", oc) } o.Expect(err).NotTo(o.HaveOccurred()) err = exutil.WaitUntilAllHelpersAreUp(oc, slaves) if err != nil { exutil.DumpDeploymentLogs("postgresql-slave", oc) } o.Expect(err).NotTo(o.HaveOccurred()) // Test if we can query as admin oc.KubeFramework().WaitForAnEndpoint("postgresql-master") err = helper.TestRemoteLogin(oc, "postgresql-master") o.Expect(err).NotTo(o.HaveOccurred()) // Create a new table with random name _, err = master.Query(oc, fmt.Sprintf("CREATE TABLE %s (col1 VARCHAR(20), col2 VARCHAR(20));", table)) o.Expect(err).NotTo(o.HaveOccurred()) // Write new data to the table through master _, err = master.Query(oc, fmt.Sprintf("INSERT INTO %s (col1, col2) VALUES ('val1', 'val2');", table)) o.Expect(err).NotTo(o.HaveOccurred()) // Make sure data is present on master err = exutil.WaitForQueryOutputContains(oc, master, 10*time.Second, false, fmt.Sprintf("SELECT * FROM %s;", table), "col1 | val1\ncol2 | val2") o.Expect(err).NotTo(o.HaveOccurred()) // Make sure data was replicated to all slaves for _, slave := range slaves { err = exutil.WaitForQueryOutputContains(oc, slave, 90*time.Second, false, fmt.Sprintf("SELECT * FROM %s;", table), "col1 | val1\ncol2 | val2") o.Expect(err).NotTo(o.HaveOccurred()) } return master, slaves, helper } g.By("after initial deployment") master, _, _ := assertReplicationIsWorking("postgresql-master-1", "postgresql-slave-1", 1) g.By("after master is restarted by changing the Deployment Config") err = oc.Run("env").Args("dc", "postgresql-master", "POSTGRESQL_ADMIN_PASSWORD=newpass").Execute() o.Expect(err).NotTo(o.HaveOccurred()) err = exutil.WaitUntilPodIsGone(oc.KubeREST().Pods(oc.Namespace()), master.PodName(), 1*time.Minute) master, _, _ = assertReplicationIsWorking("postgresql-master-2", "postgresql-slave-1", 1) g.By("after master is restarted by deleting the pod") err = oc.Run("delete").Args("pod", "-l", "deployment=postgresql-master-2").Execute() o.Expect(err).NotTo(o.HaveOccurred()) err = exutil.WaitUntilPodIsGone(oc.KubeREST().Pods(oc.Namespace()), master.PodName(), 1*time.Minute) o.Expect(err).NotTo(o.HaveOccurred()) _, slaves, _ := assertReplicationIsWorking("postgresql-master-2", "postgresql-slave-1", 1) g.By("after slave is restarted by deleting the pod") err = oc.Run("delete").Args("pod", "-l", "deployment=postgresql-slave-1").Execute() o.Expect(err).NotTo(o.HaveOccurred()) err = exutil.WaitUntilPodIsGone(oc.KubeREST().Pods(oc.Namespace()), slaves[0].PodName(), 1*time.Minute) o.Expect(err).NotTo(o.HaveOccurred()) assertReplicationIsWorking("postgresql-master-2", "postgresql-slave-1", 1) pods, err := oc.KubeREST().Pods(oc.Namespace()).List(kapi.ListOptions{LabelSelector: exutil.ParseLabelsOrDie("deployment=postgresql-slave-1")}) o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(len(pods.Items)).To(o.Equal(1)) g.By("after slave is scaled to 0 and then back to 4 replicas") err = oc.Run("scale").Args("dc", "postgresql-slave", "--replicas=0").Execute() o.Expect(err).NotTo(o.HaveOccurred()) err = exutil.WaitUntilPodIsGone(oc.KubeREST().Pods(oc.Namespace()), pods.Items[0].Name, 1*time.Minute) o.Expect(err).NotTo(o.HaveOccurred()) err = oc.Run("scale").Args("dc", "postgresql-slave", "--replicas=4").Execute() o.Expect(err).NotTo(o.HaveOccurred()) assertReplicationIsWorking("postgresql-master-2", "postgresql-slave-1", 4) } }
func replicationTestFactory(oc *exutil.CLI, template string) func() { return func() { oc.SetOutputDir(exutil.TestContext.OutputDir) defer cleanup(oc) _, err := exutil.SetupHostPathVolumes(oc.AdminKubeREST().PersistentVolumes(), oc.Namespace(), "512Mi", 1) o.Expect(err).NotTo(o.HaveOccurred()) err = testutil.WaitForPolicyUpdate(oc.REST(), oc.Namespace(), "create", "templates", true) o.Expect(err).NotTo(o.HaveOccurred()) err = oc.Run("new-app").Args("-f", template).Execute() o.Expect(err).NotTo(o.HaveOccurred()) err = oc.Run("new-app").Args("-f", helperTemplate, "-p", fmt.Sprintf("DATABASE_SERVICE_NAME=%s", helperName)).Execute() o.Expect(err).NotTo(o.HaveOccurred()) err = oc.KubeFramework().WaitForAnEndpoint(helperName) o.Expect(err).NotTo(o.HaveOccurred()) tableCounter := 0 assertReplicationIsWorking := func(masterDeployment, slaveDeployment string, slaveCount int) (exutil.Database, []exutil.Database, exutil.Database) { tableCounter++ table := fmt.Sprintf("table_%0.2d", tableCounter) master, slaves, helper := CreateMySQLReplicationHelpers(oc.KubeREST().Pods(oc.Namespace()), masterDeployment, slaveDeployment, fmt.Sprintf("%s-1", helperName), slaveCount) o.Expect(exutil.WaitUntilAllHelpersAreUp(oc, []exutil.Database{master, helper})).NotTo(o.HaveOccurred()) o.Expect(exutil.WaitUntilAllHelpersAreUp(oc, slaves)).NotTo(o.HaveOccurred()) // Test if we can query as root oc.KubeFramework().WaitForAnEndpoint("mysql-master") err := helper.TestRemoteLogin(oc, "mysql-master") o.Expect(err).NotTo(o.HaveOccurred()) // Create a new table with random name _, err = master.Query(oc, fmt.Sprintf("CREATE TABLE %s (col1 VARCHAR(20), col2 VARCHAR(20));", table)) o.Expect(err).NotTo(o.HaveOccurred()) // Write new data to the table through master _, err = master.Query(oc, fmt.Sprintf("INSERT INTO %s (col1, col2) VALUES ('val1', 'val2');", table)) o.Expect(err).NotTo(o.HaveOccurred()) // Make sure data is present on master err = exutil.WaitForQueryOutput(oc, master, 10*time.Second, false, fmt.Sprintf("SELECT * FROM %s\\G;", table), "col1: val1\ncol2: val2") o.Expect(err).NotTo(o.HaveOccurred()) // Make sure data was replicated to all slaves for _, slave := range slaves { err = exutil.WaitForQueryOutput(oc, slave, 90*time.Second, false, fmt.Sprintf("SELECT * FROM %s\\G;", table), "col1: val1\ncol2: val2") o.Expect(err).NotTo(o.HaveOccurred()) } return master, slaves, helper } g.By("after initial deployment") master, _, _ := assertReplicationIsWorking("mysql-master-1", "mysql-slave-1", 1) g.By("after master is restarted by changing the Deployment Config") err = oc.Run("env").Args("dc", "mysql-master", "MYSQL_ROOT_PASSWORD=newpass").Execute() o.Expect(err).NotTo(o.HaveOccurred()) err = exutil.WaitUntilPodIsGone(oc.KubeREST().Pods(oc.Namespace()), master.PodName(), 1*time.Minute) master, _, _ = assertReplicationIsWorking("mysql-master-2", "mysql-slave-1", 1) g.By("after master is restarted by deleting the pod") err = oc.Run("delete").Args("pod", "-l", "deployment=mysql-master-2").Execute() o.Expect(err).NotTo(o.HaveOccurred()) err = exutil.WaitUntilPodIsGone(oc.KubeREST().Pods(oc.Namespace()), master.PodName(), 1*time.Minute) o.Expect(err).NotTo(o.HaveOccurred()) _, slaves, _ := assertReplicationIsWorking("mysql-master-2", "mysql-slave-1", 1) g.By("after slave is restarted by deleting the pod") err = oc.Run("delete").Args("pod", "-l", "deployment=mysql-slave-1").Execute() o.Expect(err).NotTo(o.HaveOccurred()) err = exutil.WaitUntilPodIsGone(oc.KubeREST().Pods(oc.Namespace()), slaves[0].PodName(), 1*time.Minute) o.Expect(err).NotTo(o.HaveOccurred()) assertReplicationIsWorking("mysql-master-2", "mysql-slave-1", 1) pods, err := oc.KubeREST().Pods(oc.Namespace()).List(kapi.ListOptions{LabelSelector: exutil.ParseLabelsOrDie("deployment=mysql-slave-1")}) o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(len(pods.Items)).To(o.Equal(1)) g.By("after slave is scaled to 0 and then back to 4 replicas") err = oc.Run("scale").Args("dc", "mysql-slave", "--replicas=0").Execute() o.Expect(err).NotTo(o.HaveOccurred()) err = exutil.WaitUntilPodIsGone(oc.KubeREST().Pods(oc.Namespace()), pods.Items[0].Name, 1*time.Minute) o.Expect(err).NotTo(o.HaveOccurred()) err = oc.Run("scale").Args("dc", "mysql-slave", "--replicas=4").Execute() o.Expect(err).NotTo(o.HaveOccurred()) assertReplicationIsWorking("mysql-master-2", "mysql-slave-1", 4) } }