mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-11-03 23:40:03 +00:00 
			
		
		
		
	Merge pull request #26913 from bprashanth/petset_e2e
Automatic merge from submit-queue Improve petset e2es Mainly * scale petset to 0 and wait for volume provisioner to delete pvs so we don't leak them * bake binaries into init[0] and cp into destination, instead of wgetting at runtime * dump verbose debug output on failure https://github.com/kubernetes/test-infra/pull/115, https://github.com/kubernetes/kubernetes/issues/26824
This commit is contained in:
		@@ -37,6 +37,7 @@ import (
 | 
			
		||||
	"k8s.io/kubernetes/pkg/controller/petset"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/labels"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/util/sets"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/util/wait"
 | 
			
		||||
	utilyaml "k8s.io/kubernetes/pkg/util/yaml"
 | 
			
		||||
	"k8s.io/kubernetes/test/e2e/framework"
 | 
			
		||||
@@ -49,9 +50,15 @@ const (
 | 
			
		||||
	zookeeperManifestPath   = "test/e2e/testing-manifests/petset/zookeeper"
 | 
			
		||||
	mysqlGaleraManifestPath = "test/e2e/testing-manifests/petset/mysql-galera"
 | 
			
		||||
	redisManifestPath       = "test/e2e/testing-manifests/petset/redis"
 | 
			
		||||
	// Should the test restart petset clusters?
 | 
			
		||||
	// TODO: enable when we've productionzed bringup of pets in this e2e.
 | 
			
		||||
	restartCluster = false
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ = framework.KubeDescribe("PetSet", func() {
 | 
			
		||||
// Time: 25m, slow by design.
 | 
			
		||||
// GCE Quota requirements: 3 pds, one per pet manifest declared above.
 | 
			
		||||
// GCE Api requirements: nodes and master need storage r/w permissions.
 | 
			
		||||
var _ = framework.KubeDescribe("PetSet [Slow] [Feature:PetSet]", func() {
 | 
			
		||||
	f := framework.NewDefaultFramework("petset")
 | 
			
		||||
	var ns string
 | 
			
		||||
	var c *client.Client
 | 
			
		||||
@@ -81,13 +88,16 @@ var _ = framework.KubeDescribe("PetSet", func() {
 | 
			
		||||
			Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		AfterEach(func() {
 | 
			
		||||
			if CurrentGinkgoTestDescription().Failed {
 | 
			
		||||
				dumpDebugInfo(c, ns)
 | 
			
		||||
			}
 | 
			
		||||
			framework.Logf("Deleting all petset in ns %v", ns)
 | 
			
		||||
			deleteAllPetSets(c, ns)
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		It("should provide basic identity [Feature:PetSet]", func() {
 | 
			
		||||
			By("creating petset " + psName + " in namespace " + ns)
 | 
			
		||||
			defer func() {
 | 
			
		||||
				err := c.Apps().PetSets(ns).Delete(psName, nil)
 | 
			
		||||
				Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
			}()
 | 
			
		||||
 | 
			
		||||
			petMounts := []api.VolumeMount{{Name: "datadir", MountPath: "/data/"}}
 | 
			
		||||
			podMounts := []api.VolumeMount{{Name: "home", MountPath: "/home"}}
 | 
			
		||||
			ps := newPetSet(psName, ns, headlessSvcName, 3, petMounts, podMounts, labels)
 | 
			
		||||
@@ -99,7 +109,7 @@ var _ = framework.KubeDescribe("PetSet", func() {
 | 
			
		||||
			By("Saturating pet set " + ps.Name)
 | 
			
		||||
			pst.saturate(ps)
 | 
			
		||||
 | 
			
		||||
			cmd := "echo $(hostname) > /data/hostname"
 | 
			
		||||
			cmd := "echo $(hostname) > /data/hostname; sync;"
 | 
			
		||||
			By("Running " + cmd + " in all pets")
 | 
			
		||||
			pst.execInPets(ps, cmd)
 | 
			
		||||
 | 
			
		||||
@@ -114,10 +124,6 @@ var _ = framework.KubeDescribe("PetSet", func() {
 | 
			
		||||
 | 
			
		||||
		It("should handle healthy pet restarts during scale [Feature:PetSet]", func() {
 | 
			
		||||
			By("creating petset " + psName + " in namespace " + ns)
 | 
			
		||||
			defer func() {
 | 
			
		||||
				err := c.Apps().PetSets(ns).Delete(psName, nil)
 | 
			
		||||
				Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
			}()
 | 
			
		||||
 | 
			
		||||
			petMounts := []api.VolumeMount{{Name: "datadir", MountPath: "/data/"}}
 | 
			
		||||
			podMounts := []api.VolumeMount{{Name: "home", MountPath: "/home"}}
 | 
			
		||||
@@ -126,6 +132,7 @@ var _ = framework.KubeDescribe("PetSet", func() {
 | 
			
		||||
			Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
 | 
			
		||||
			pst := petSetTester{c: c}
 | 
			
		||||
 | 
			
		||||
			pst.waitForRunning(1, ps)
 | 
			
		||||
 | 
			
		||||
			By("Marking pet at index 0 as healthy.")
 | 
			
		||||
@@ -152,17 +159,17 @@ var _ = framework.KubeDescribe("PetSet", func() {
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	framework.KubeDescribe("Deploy clustered applications", func() {
 | 
			
		||||
	framework.KubeDescribe("Deploy clustered applications [Slow] [Feature:PetSet]", func() {
 | 
			
		||||
		BeforeEach(func() {
 | 
			
		||||
			framework.SkipUnlessProviderIs("gce")
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		AfterEach(func() {
 | 
			
		||||
			// TODO: delete pvs
 | 
			
		||||
			if !CurrentGinkgoTestDescription().Failed {
 | 
			
		||||
				return
 | 
			
		||||
			if CurrentGinkgoTestDescription().Failed {
 | 
			
		||||
				dumpDebugInfo(c, ns)
 | 
			
		||||
			}
 | 
			
		||||
			dumpDebugInfo(c, ns)
 | 
			
		||||
			framework.Logf("Deleting all petset in ns %v", ns)
 | 
			
		||||
			deleteAllPetSets(c, ns)
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		It("should creating a working zookeeper cluster [Feature:PetSet]", func() {
 | 
			
		||||
@@ -174,9 +181,11 @@ var _ = framework.KubeDescribe("PetSet", func() {
 | 
			
		||||
			By("Creating foo:bar in member with index 0")
 | 
			
		||||
			pet.write(0, map[string]string{"foo": "bar"})
 | 
			
		||||
 | 
			
		||||
			By("Restarting pet set " + ps.Name)
 | 
			
		||||
			pst.restart(ps)
 | 
			
		||||
			pst.waitForRunning(ps.Spec.Replicas, ps)
 | 
			
		||||
			if restartCluster {
 | 
			
		||||
				By("Restarting pet set " + ps.Name)
 | 
			
		||||
				pst.restart(ps)
 | 
			
		||||
				pst.waitForRunning(ps.Spec.Replicas, ps)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			By("Reading value under foo from member with index 2")
 | 
			
		||||
			if v := pet.read(2, "foo"); v != "bar" {
 | 
			
		||||
@@ -193,9 +202,11 @@ var _ = framework.KubeDescribe("PetSet", func() {
 | 
			
		||||
			By("Creating foo:bar in member with index 0")
 | 
			
		||||
			pet.write(0, map[string]string{"foo": "bar"})
 | 
			
		||||
 | 
			
		||||
			By("Restarting pet set " + ps.Name)
 | 
			
		||||
			pst.restart(ps)
 | 
			
		||||
			pst.waitForRunning(ps.Spec.Replicas, ps)
 | 
			
		||||
			if restartCluster {
 | 
			
		||||
				By("Restarting pet set " + ps.Name)
 | 
			
		||||
				pst.restart(ps)
 | 
			
		||||
				pst.waitForRunning(ps.Spec.Replicas, ps)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			By("Reading value under foo from member with index 2")
 | 
			
		||||
			if v := pet.read(2, "foo"); v != "bar" {
 | 
			
		||||
@@ -212,9 +223,11 @@ var _ = framework.KubeDescribe("PetSet", func() {
 | 
			
		||||
			By("Creating foo:bar in member with index 0")
 | 
			
		||||
			pet.write(0, map[string]string{"foo": "bar"})
 | 
			
		||||
 | 
			
		||||
			By("Restarting pet set " + ps.Name)
 | 
			
		||||
			pst.restart(ps)
 | 
			
		||||
			pst.waitForRunning(ps.Spec.Replicas, ps)
 | 
			
		||||
			if restartCluster {
 | 
			
		||||
				By("Restarting pet set " + ps.Name)
 | 
			
		||||
				pst.restart(ps)
 | 
			
		||||
				pst.waitForRunning(ps.Spec.Replicas, ps)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			By("Reading value under foo from member with index 2")
 | 
			
		||||
			if v := pet.read(2, "foo"); v != "bar" {
 | 
			
		||||
@@ -381,6 +394,7 @@ func petSetFromManifest(fileName, ns string) *apps.PetSet {
 | 
			
		||||
	return &ps
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// petSetTester has all methods required to test a single petset.
 | 
			
		||||
type petSetTester struct {
 | 
			
		||||
	c *client.Client
 | 
			
		||||
}
 | 
			
		||||
@@ -429,30 +443,36 @@ func (p *petSetTester) deletePetAtIndex(index int, ps *apps.PetSet) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *petSetTester) restart(ps *apps.PetSet) {
 | 
			
		||||
func (p *petSetTester) scale(ps *apps.PetSet, count int) error {
 | 
			
		||||
	name := ps.Name
 | 
			
		||||
	ns := ps.Namespace
 | 
			
		||||
	oldReplicas := ps.Spec.Replicas
 | 
			
		||||
	p.update(ns, name, func(ps *apps.PetSet) { ps.Spec.Replicas = 0 })
 | 
			
		||||
	p.update(ns, name, func(ps *apps.PetSet) { ps.Spec.Replicas = count })
 | 
			
		||||
 | 
			
		||||
	var petList *api.PodList
 | 
			
		||||
	pollErr := wait.PollImmediate(petsetPoll, petsetTimeout, func() (bool, error) {
 | 
			
		||||
		petList = p.getPodList(ps)
 | 
			
		||||
		if len(petList.Items) == 0 {
 | 
			
		||||
		if len(petList.Items) == count {
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
		return false, nil
 | 
			
		||||
	})
 | 
			
		||||
	if pollErr != nil {
 | 
			
		||||
		ts := []string{}
 | 
			
		||||
		unhealthy := []string{}
 | 
			
		||||
		for _, pet := range petList.Items {
 | 
			
		||||
			if pet.DeletionTimestamp != nil {
 | 
			
		||||
				ts = append(ts, fmt.Sprintf("%v", pet.DeletionTimestamp.Time))
 | 
			
		||||
			delTs, phase, readiness := pet.DeletionTimestamp, pet.Status.Phase, api.IsPodReady(&pet)
 | 
			
		||||
			if delTs != nil || phase != api.PodRunning || !readiness {
 | 
			
		||||
				unhealthy = append(unhealthy, fmt.Sprintf("%v: deletion %v, phase %v, readiness %v", pet.Name, delTs, phase, readiness))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		framework.Failf("Failed to scale petset down to 0, %d remaining pods with deletion timestamps: %v", len(petList.Items), ts)
 | 
			
		||||
		return fmt.Errorf("Failed to scale petset to %d in %v. Remaining pods:\n%v", count, petsetTimeout, unhealthy)
 | 
			
		||||
	}
 | 
			
		||||
	p.update(ns, name, func(ps *apps.PetSet) { ps.Spec.Replicas = oldReplicas })
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *petSetTester) restart(ps *apps.PetSet) {
 | 
			
		||||
	oldReplicas := ps.Spec.Replicas
 | 
			
		||||
	ExpectNoError(p.scale(ps, 0))
 | 
			
		||||
	p.update(ps.Namespace, ps.Name, func(ps *apps.PetSet) { ps.Spec.Replicas = oldReplicas })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *petSetTester) update(ns, name string, update func(ps *apps.PetSet)) {
 | 
			
		||||
@@ -542,6 +562,74 @@ func (p *petSetTester) setHealthy(ps *apps.PetSet) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func deleteAllPetSets(c *client.Client, ns string) {
 | 
			
		||||
	pst := &petSetTester{c: c}
 | 
			
		||||
	psList, err := c.Apps().PetSets(ns).List(api.ListOptions{LabelSelector: labels.Everything()})
 | 
			
		||||
	ExpectNoError(err)
 | 
			
		||||
 | 
			
		||||
	// Scale down each petset, then delete it completely.
 | 
			
		||||
	// Deleting a pvc without doing this will leak volumes, #25101.
 | 
			
		||||
	errList := []string{}
 | 
			
		||||
	for _, ps := range psList.Items {
 | 
			
		||||
		framework.Logf("Scaling petset %v to 0", ps.Name)
 | 
			
		||||
		if err := pst.scale(&ps, 0); err != nil {
 | 
			
		||||
			errList = append(errList, fmt.Sprintf("%v", err))
 | 
			
		||||
		}
 | 
			
		||||
		framework.Logf("Deleting petset %v", ps.Name)
 | 
			
		||||
		if err := c.Apps().PetSets(ps.Namespace).Delete(ps.Name, nil); err != nil {
 | 
			
		||||
			errList = append(errList, fmt.Sprintf("%v", err))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// pvs are global, so we need to wait for the exact ones bound to the petset pvcs.
 | 
			
		||||
	pvNames := sets.NewString()
 | 
			
		||||
	// TODO: Don't assume all pvcs in the ns belong to a petset
 | 
			
		||||
	pvcPollErr := wait.PollImmediate(petsetPoll, petsetTimeout, func() (bool, error) {
 | 
			
		||||
		pvcList, err := c.PersistentVolumeClaims(ns).List(api.ListOptions{LabelSelector: labels.Everything()})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			framework.Logf("WARNING: Failed to list pvcs, retrying %v", err)
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
		for _, pvc := range pvcList.Items {
 | 
			
		||||
			pvNames.Insert(pvc.Spec.VolumeName)
 | 
			
		||||
			// TODO: Double check that there are no pods referencing the pvc
 | 
			
		||||
			framework.Logf("Deleting pvc: %v with volume %v", pvc.Name, pvc.Spec.VolumeName)
 | 
			
		||||
			if err := c.PersistentVolumeClaims(ns).Delete(pvc.Name); err != nil {
 | 
			
		||||
				return false, nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return true, nil
 | 
			
		||||
	})
 | 
			
		||||
	if pvcPollErr != nil {
 | 
			
		||||
		errList = append(errList, fmt.Sprintf("Timeout waiting for pvc deletion."))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pollErr := wait.PollImmediate(petsetPoll, petsetTimeout, func() (bool, error) {
 | 
			
		||||
		pvList, err := c.PersistentVolumes().List(api.ListOptions{LabelSelector: labels.Everything()})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			framework.Logf("WARNING: Failed to list pvs, retrying %v", err)
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
		waitingFor := []string{}
 | 
			
		||||
		for _, pv := range pvList.Items {
 | 
			
		||||
			if pvNames.Has(pv.Name) {
 | 
			
		||||
				waitingFor = append(waitingFor, fmt.Sprintf("%v: %+v", pv.Name, pv.Status))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if len(waitingFor) == 0 {
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
		framework.Logf("Still waiting for pvs of petset to disappear:\n%v", strings.Join(waitingFor, "\n"))
 | 
			
		||||
		return false, nil
 | 
			
		||||
	})
 | 
			
		||||
	if pollErr != nil {
 | 
			
		||||
		errList = append(errList, fmt.Sprintf("Timeout waiting for pv provisioner to delete pvs, this might mean the test leaked pvs."))
 | 
			
		||||
	}
 | 
			
		||||
	if len(errList) != 0 {
 | 
			
		||||
		ExpectNoError(fmt.Errorf("%v", strings.Join(errList, "\n")))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ExpectNoError(err error) {
 | 
			
		||||
	Expect(err).NotTo(HaveOccurred())
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -57,6 +57,7 @@ spec:
 | 
			
		||||
            }
 | 
			
		||||
        ]'
 | 
			
		||||
    spec:
 | 
			
		||||
      terminationGracePeriodSeconds: 0
 | 
			
		||||
      containers:
 | 
			
		||||
      - name: mysql
 | 
			
		||||
        image: gcr.io/google_containers/mysql-galera:e2e
 | 
			
		||||
@@ -73,10 +74,12 @@ spec:
 | 
			
		||||
        - --defaults-file=/etc/mysql/my-galera.cnf
 | 
			
		||||
        - --user=root
 | 
			
		||||
        readinessProbe:
 | 
			
		||||
          # TODO: If docker exec is buggy just use nc mysql-id 3306 as a ping.
 | 
			
		||||
          httpGet:
 | 
			
		||||
            path: /healthz
 | 
			
		||||
            port: 8080
 | 
			
		||||
          # TODO: If docker exec is buggy just use gcr.io/google_containers/mysql-healthz:1.0
 | 
			
		||||
          exec:
 | 
			
		||||
            command:
 | 
			
		||||
            - sh
 | 
			
		||||
            - -c
 | 
			
		||||
            - "mysql -u root -e 'show databases;'"
 | 
			
		||||
          initialDelaySeconds: 15
 | 
			
		||||
          timeoutSeconds: 5
 | 
			
		||||
          successThreshold: 2
 | 
			
		||||
@@ -85,11 +88,6 @@ spec:
 | 
			
		||||
          mountPath: /var/lib/
 | 
			
		||||
        - name: config
 | 
			
		||||
          mountPath: /etc/mysql
 | 
			
		||||
      - name: healthz
 | 
			
		||||
        image: gcr.io/google_containers/mysql-healthz:1.0
 | 
			
		||||
        args:
 | 
			
		||||
        - --port=8080
 | 
			
		||||
        - --verbose=true
 | 
			
		||||
      volumes:
 | 
			
		||||
      - name: config
 | 
			
		||||
        emptyDir: {}
 | 
			
		||||
@@ -104,4 +102,4 @@ spec:
 | 
			
		||||
      accessModes: [ "ReadWriteOnce" ]
 | 
			
		||||
      resources:
 | 
			
		||||
        requests:
 | 
			
		||||
          storage: 10Gi
 | 
			
		||||
          storage: 1Gi
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,9 @@ spec:
 | 
			
		||||
        pod.alpha.kubernetes.io/init-containers: '[
 | 
			
		||||
            {
 | 
			
		||||
                "name": "install",
 | 
			
		||||
                "image": "gcr.io/google_containers/redis-install:0.1",
 | 
			
		||||
                "image": "gcr.io/google_containers/redis-install-3.2.0:e2e",
 | 
			
		||||
                "imagePullPolicy": "Always",
 | 
			
		||||
                "args": ["--version=3.2.0", "--install-into=/opt", "--work-dir=/work-dir"],
 | 
			
		||||
                "args": ["--install-into=/opt", "--work-dir=/work-dir"],
 | 
			
		||||
                "volumeMounts": [
 | 
			
		||||
                    {
 | 
			
		||||
                        "name": "opt",
 | 
			
		||||
@@ -57,6 +57,7 @@ spec:
 | 
			
		||||
            }
 | 
			
		||||
        ]'
 | 
			
		||||
    spec:
 | 
			
		||||
      terminationGracePeriodSeconds: 0
 | 
			
		||||
      containers:
 | 
			
		||||
      - name: redis
 | 
			
		||||
        image: debian:jessie
 | 
			
		||||
@@ -94,4 +95,4 @@ spec:
 | 
			
		||||
      accessModes: [ "ReadWriteOnce" ]
 | 
			
		||||
      resources:
 | 
			
		||||
        requests:
 | 
			
		||||
          storage: 10Gi
 | 
			
		||||
          storage: 1Gi
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,9 @@ spec:
 | 
			
		||||
        pod.alpha.kubernetes.io/init-containers: '[
 | 
			
		||||
            {
 | 
			
		||||
                "name": "install",
 | 
			
		||||
                "image": "gcr.io/google_containers/zookeeper-install:0.1",
 | 
			
		||||
                "image": "gcr.io/google_containers/zookeeper-install-3.5.0-alpha:e2e",
 | 
			
		||||
                "imagePullPolicy": "Always",
 | 
			
		||||
                "args": ["--version=3.5.0-alpha", "--install-into=/opt", "--work-dir=/work-dir"],
 | 
			
		||||
                "args": ["--install-into=/opt", "--work-dir=/work-dir"],
 | 
			
		||||
                "volumeMounts": [
 | 
			
		||||
                    {
 | 
			
		||||
                        "name": "opt",
 | 
			
		||||
@@ -47,7 +47,7 @@ spec:
 | 
			
		||||
                "volumeMounts": [
 | 
			
		||||
                    {
 | 
			
		||||
                        "name": "opt",
 | 
			
		||||
                        "mountPath": "/opt/"
 | 
			
		||||
                        "mountPath": "/opt"
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        "name": "workdir",
 | 
			
		||||
@@ -61,6 +61,7 @@ spec:
 | 
			
		||||
            }
 | 
			
		||||
        ]'
 | 
			
		||||
    spec:
 | 
			
		||||
      terminationGracePeriodSeconds: 0
 | 
			
		||||
      containers:
 | 
			
		||||
      - name: zk
 | 
			
		||||
        image: java:openjdk-8-jre
 | 
			
		||||
@@ -85,7 +86,10 @@ spec:
 | 
			
		||||
        - name: datadir
 | 
			
		||||
          mountPath: /tmp/zookeeper
 | 
			
		||||
        - name: opt
 | 
			
		||||
          mountPath: /opt/
 | 
			
		||||
          mountPath: /opt
 | 
			
		||||
        # Mount the work-dir just for debugging
 | 
			
		||||
        - name: workdir
 | 
			
		||||
          mountPath: /work-dir
 | 
			
		||||
      volumes:
 | 
			
		||||
      - name: opt
 | 
			
		||||
        emptyDir: {}
 | 
			
		||||
@@ -100,4 +104,4 @@ spec:
 | 
			
		||||
      accessModes: [ "ReadWriteOnce" ]
 | 
			
		||||
      resources:
 | 
			
		||||
        requests:
 | 
			
		||||
          storage: 10Gi
 | 
			
		||||
          storage: 1Gi
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										39
									
								
								test/images/pets/redis/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								test/images/pets/redis/Dockerfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
# Copyright 2016 The Kubernetes Authors All rights reserved.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
# TODO: get rid of bash dependency and switch to plain busybox.
 | 
			
		||||
# The tar in busybox also doesn't seem to understand compression.
 | 
			
		||||
FROM debian:jessie
 | 
			
		||||
MAINTAINER Prashanth.B <beeps@google.com>
 | 
			
		||||
 | 
			
		||||
# TODO: just use standard redis when there is one for 3.2.0.
 | 
			
		||||
RUN apt-get update && apt-get install -y wget make gcc
 | 
			
		||||
 | 
			
		||||
# See README.md
 | 
			
		||||
RUN wget -qO /redis-3.2.0.tar.gz http://download.redis.io/releases/redis-3.2.0.tar.gz && \
 | 
			
		||||
    tar -xzf /redis-3.2.0.tar.gz -C /tmp/ && rm /redis-3.2.0.tar.gz
 | 
			
		||||
 | 
			
		||||
# Clean out existing deps before installation
 | 
			
		||||
# see https://github.com/antirez/redis/issues/722
 | 
			
		||||
RUN cd /tmp/redis-3.2.0 && make distclean && mkdir -p /redis && \
 | 
			
		||||
    make install INSTALL_BIN=/redis && \
 | 
			
		||||
    mv /tmp/redis-3.2.0/redis.conf /redis/redis.conf && \
 | 
			
		||||
    rm -rf /tmp/redis-3.2.0
 | 
			
		||||
 | 
			
		||||
ADD on-start.sh /
 | 
			
		||||
# See contrib/pets/peer-finder for details
 | 
			
		||||
RUN wget -qO /peer-finder https://storage.googleapis.com/kubernetes-release/pets/peer-finder
 | 
			
		||||
ADD install.sh /
 | 
			
		||||
RUN chmod -c 755 /install.sh /on-start.sh /peer-finder
 | 
			
		||||
Entrypoint ["/install.sh"]
 | 
			
		||||
							
								
								
									
										27
									
								
								test/images/pets/redis/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								test/images/pets/redis/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
# Copyright 2016 The Kubernetes Authors All rights reserved.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
all: push
 | 
			
		||||
 | 
			
		||||
TAG = e2e
 | 
			
		||||
PREFIX = gcr.io/google_containers/redis-install-3.2.0
 | 
			
		||||
 | 
			
		||||
container:
 | 
			
		||||
	docker build -t $(PREFIX):$(TAG) .
 | 
			
		||||
 | 
			
		||||
push: container
 | 
			
		||||
	gcloud docker push $(PREFIX):$(TAG)
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	docker rmi $(PREFIX):$(TAG)
 | 
			
		||||
							
								
								
									
										12
									
								
								test/images/pets/redis/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								test/images/pets/redis/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
# Redis petset e2e tester
 | 
			
		||||
 | 
			
		||||
The image in this directory is the init container for contrib/pets/redis but for one difference, it bakes a specific verfion of redis into the base image so we get deterministic test results without having to depend on a redis download server. Discussing the tradeoffs to either approach (download the version at runtime, or maintain an image per version) are outside the scope of this document.
 | 
			
		||||
 | 
			
		||||
You can execute the image locally via:
 | 
			
		||||
```
 | 
			
		||||
$ docker run -it gcr.io/google_containers/redis-install-3.2.0:e2e --cmd --install-into=/opt --work-dir=/work-dir
 | 
			
		||||
```
 | 
			
		||||
To share the installation with other containers mount the appropriate volumes as `--install-into` and `--work-dir`, where `install-into` is the directory to install redis into, and `work-dir` is the directory to install the user/admin supplied on-{start,change} hook scripts.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[]()
 | 
			
		||||
							
								
								
									
										51
									
								
								test/images/pets/redis/install.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										51
									
								
								test/images/pets/redis/install.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
#! /bin/bash
 | 
			
		||||
 | 
			
		||||
# Copyright 2016 The Kubernetes Authors All rights reserved.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
# This volume is assumed to exist and is shared with parent of the init
 | 
			
		||||
# container. It contains the redis installation.
 | 
			
		||||
INSTALL_VOLUME="/opt"
 | 
			
		||||
 | 
			
		||||
# This volume is assumed to exist and is shared with the peer-finder
 | 
			
		||||
# init container. It contains on-start/change configuration scripts.
 | 
			
		||||
WORK_DIR="/work-dir"
 | 
			
		||||
 | 
			
		||||
VERSION="3.2.0"
 | 
			
		||||
 | 
			
		||||
for i in "$@"
 | 
			
		||||
do
 | 
			
		||||
case $i in
 | 
			
		||||
    -i=*|--install-into=*)
 | 
			
		||||
    INSTALL_VOLUME="${i#*=}"
 | 
			
		||||
    shift
 | 
			
		||||
    ;;
 | 
			
		||||
    -w=*|--work-dir=*)
 | 
			
		||||
    WORK_DIR="${i#*=}"
 | 
			
		||||
    shift
 | 
			
		||||
    ;;
 | 
			
		||||
    *)
 | 
			
		||||
    # unknown option
 | 
			
		||||
    ;;
 | 
			
		||||
esac
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
echo installing config scripts into "${WORK_DIR}"
 | 
			
		||||
mkdir -p "${WORK_DIR}"
 | 
			
		||||
cp /on-start.sh "${WORK_DIR}"/
 | 
			
		||||
cp /peer-finder "${WORK_DIR}"/
 | 
			
		||||
 | 
			
		||||
echo installing redis-"${VERSION}" into "${INSTALL_VOLUME}"
 | 
			
		||||
mkdir -p "${INSTALL_VOLUME}"
 | 
			
		||||
mv /redis "${INSTALL_VOLUME}"/redis
 | 
			
		||||
							
								
								
									
										49
									
								
								test/images/pets/redis/on-start.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										49
									
								
								test/images/pets/redis/on-start.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
# Copyright 2016 The Kubernetes Authors All rights reserved.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
CFG=/opt/redis/redis.conf
 | 
			
		||||
HOSTNAME=$(hostname)
 | 
			
		||||
DATADIR="/data"
 | 
			
		||||
# Port on which redis listens for connections.
 | 
			
		||||
PORT=6379
 | 
			
		||||
 | 
			
		||||
# Ping everyone but ourself to see if there's a master. Only one pet starts at
 | 
			
		||||
# a time, so if we don't see a master we can assume the position is ours.
 | 
			
		||||
while read -ra LINE; do
 | 
			
		||||
    if [[ "${LINE}" == *"${HOSTNAME}"* ]]; then
 | 
			
		||||
        sed -i -e "s|^bind.*$|bind ${LINE}|" ${CFG}
 | 
			
		||||
    elif [ "$(/opt/redis/redis-cli -h $LINE info | grep role | sed 's,\r$,,')" = "role:master" ]; then
 | 
			
		||||
        # TODO: More restrictive regex?
 | 
			
		||||
        sed -i -e "s|^.*slaveof.*$|slaveof ${LINE} ${PORT}|" ${CFG}
 | 
			
		||||
    fi
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
# Set the data directory for append only log and snapshot files. This should
 | 
			
		||||
# be a persistent volume for consistency.
 | 
			
		||||
sed -i -e "s|^.*dir .*$|dir ${DATADIR}|" ${CFG}
 | 
			
		||||
 | 
			
		||||
# The append only log is written for every SET operation. Without this setting,
 | 
			
		||||
# redis just snapshots periodically which is only safe for a cache. This will
 | 
			
		||||
# produce an appendonly.aof file in the configured data dir.
 | 
			
		||||
sed -i -e "s|^appendonly .*$|appendonly yes|" ${CFG}
 | 
			
		||||
 | 
			
		||||
# Every write triggers an fsync. Recommended default is "everysec", which
 | 
			
		||||
# is only safe for AP applications.
 | 
			
		||||
sed -i -e "s|^appendfsync .*$|appendfsync always|" ${CFG}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										32
									
								
								test/images/pets/zookeeper/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								test/images/pets/zookeeper/Dockerfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
# Copyright 2016 The Kubernetes Authors All rights reserved.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
# TODO: get rid of bash dependency and switch to plain busybox.
 | 
			
		||||
# The tar in busybox also doesn't seem to understand compression.
 | 
			
		||||
FROM debian:jessie
 | 
			
		||||
MAINTAINER Prashanth.B <beeps@google.com>
 | 
			
		||||
 | 
			
		||||
RUN apt-get update && apt-get install -y wget netcat
 | 
			
		||||
 | 
			
		||||
ADD on-start.sh /
 | 
			
		||||
# See contrib/pets/peer-finder for details
 | 
			
		||||
RUN wget -qO /peer-finder https://storage.googleapis.com/kubernetes-release/pets/peer-finder
 | 
			
		||||
 | 
			
		||||
# See README.md
 | 
			
		||||
RUN wget -q -O /zookeeper-3.5.0-alpha.tar.gz http://apache.mirrors.pair.com/zookeeper/zookeeper-3.5.0-alpha/zookeeper-3.5.0-alpha.tar.gz && \
 | 
			
		||||
    tar -xzf /zookeeper-3.5.0-alpha.tar.gz -C /tmp/ && mv /tmp/zookeeper-3.5.0-alpha /zookeeper && rm /zookeeper-3.5.0-alpha.tar.gz
 | 
			
		||||
 | 
			
		||||
ADD install.sh /
 | 
			
		||||
RUN chmod -c 755 /install.sh /on-start.sh /peer-finder
 | 
			
		||||
Entrypoint ["/install.sh"]
 | 
			
		||||
							
								
								
									
										27
									
								
								test/images/pets/zookeeper/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								test/images/pets/zookeeper/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
# Copyright 2016 The Kubernetes Authors All rights reserved.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
all: push
 | 
			
		||||
 | 
			
		||||
TAG = e2e
 | 
			
		||||
PREFIX = gcr.io/google_containers/zookeeper-install-3.5.0-alpha
 | 
			
		||||
 | 
			
		||||
container:
 | 
			
		||||
	docker build -t $(PREFIX):$(TAG) .
 | 
			
		||||
 | 
			
		||||
push: container
 | 
			
		||||
	gcloud docker push $(PREFIX):$(TAG)
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	docker rmi $(PREFIX):$(TAG)
 | 
			
		||||
							
								
								
									
										12
									
								
								test/images/pets/zookeeper/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								test/images/pets/zookeeper/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
# Zookeeper petset e2e tester
 | 
			
		||||
 | 
			
		||||
The image in this directory is the init container for contrib/pets/zookeeper but for one difference, it bakes a specific verfion of zookeeper into the base image so we get deterministic test results without having to depend on a zookeeper download server. Discussing the tradeoffs to either approach (download the version at runtime, or maintain an image per version) are outside the scope of this document.
 | 
			
		||||
 | 
			
		||||
You can execute the image locally via:
 | 
			
		||||
```
 | 
			
		||||
$ docker run -it gcr.io/google_containers/zookeeper-install-3.5.0-alpha:e2e --cmd --install-into=/opt --work-dir=/work-dir
 | 
			
		||||
```
 | 
			
		||||
To share the installation with other containers mount the appropriate volumes as `--install-into` and `--work-dir`, where `install-into` is the directory to install zookeeper into, and `work-dir` is the directory to install the user/admin supplied on-{start,change} hook scripts.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[]()
 | 
			
		||||
							
								
								
									
										70
									
								
								test/images/pets/zookeeper/install.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										70
									
								
								test/images/pets/zookeeper/install.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
#! /bin/bash
 | 
			
		||||
 | 
			
		||||
# Copyright 2016 The Kubernetes Authors All rights reserved.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
# This volume is assumed to exist and is shared with parent of the init
 | 
			
		||||
# container. It contains the zookeeper installation.
 | 
			
		||||
INSTALL_VOLUME="/opt"
 | 
			
		||||
 | 
			
		||||
# This volume is assumed to exist and is shared with the peer-finder
 | 
			
		||||
# init container. It contains on-start/change configuration scripts.
 | 
			
		||||
WORKDIR_VOLUME="/work-dir"
 | 
			
		||||
 | 
			
		||||
# As of April-2016 is 3.4.8 is the latest stable, but versions 3.5.0 onward
 | 
			
		||||
# allow dynamic reconfiguration.
 | 
			
		||||
VERSION="3.5.0-alpha"
 | 
			
		||||
 | 
			
		||||
for i in "$@"
 | 
			
		||||
do
 | 
			
		||||
case $i in
 | 
			
		||||
    -i=*|--install-into=*)
 | 
			
		||||
    INSTALL_VOLUME="${i#*=}"
 | 
			
		||||
    shift
 | 
			
		||||
    ;;
 | 
			
		||||
    -w=*|--work-dir=*)
 | 
			
		||||
    WORKDIR_VOLUME="${i#*=}"
 | 
			
		||||
    shift
 | 
			
		||||
    ;;
 | 
			
		||||
    *)
 | 
			
		||||
    # unknown option
 | 
			
		||||
    ;;
 | 
			
		||||
esac
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
echo installing config scripts into "${WORKDIR_VOLUME}"
 | 
			
		||||
mkdir -p "${WORKDIR_VOLUME}"
 | 
			
		||||
cp /on-start.sh "${WORKDIR_VOLUME}"/
 | 
			
		||||
cp /peer-finder "${WORKDIR_VOLUME}"/
 | 
			
		||||
 | 
			
		||||
echo installing zookeeper-"${VERSION}" into "${INSTALL_VOLUME}"
 | 
			
		||||
mkdir -p "${INSTALL_VOLUME}"
 | 
			
		||||
mv /zookeeper "${INSTALL_VOLUME}"/zookeeper
 | 
			
		||||
cp "${INSTALL_VOLUME}"/zookeeper/conf/zoo_sample.cfg "${INSTALL_VOLUME}"/zookeeper/conf/zoo.cfg
 | 
			
		||||
 | 
			
		||||
# TODO: Should dynamic config be tied to the version?
 | 
			
		||||
IFS="." read -ra RELEASE <<< "${VERSION}"
 | 
			
		||||
if [ $(expr "${RELEASE[1]}") -gt 4 ]; then
 | 
			
		||||
    echo zookeeper-"${VERSION}" supports dynamic reconfiguration, enabling it
 | 
			
		||||
    echo "standaloneEnabled=false" >> "${INSTALL_VOLUME}"/zookeeper/conf/zoo.cfg
 | 
			
		||||
    echo "dynamicConfigFile="${INSTALL_VOLUME}"/zookeeper/conf/zoo.cfg.dynamic" >> "${INSTALL_VOLUME}"/zookeeper/conf/zoo.cfg
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# TODO: This is a hack, netcat is convenient to have in the zookeeper container
 | 
			
		||||
# I want to avoid using a custom zookeeper image just for this. So copy it.
 | 
			
		||||
NC=$(which nc)
 | 
			
		||||
if [ "${NC}" != "" ]; then
 | 
			
		||||
    echo copying nc into "${INSTALL_VOLUME}"
 | 
			
		||||
    cp "${NC}" "${INSTALL_VOLUME}"
 | 
			
		||||
fi
 | 
			
		||||
							
								
								
									
										106
									
								
								test/images/pets/zookeeper/on-start.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										106
									
								
								test/images/pets/zookeeper/on-start.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,106 @@
 | 
			
		||||
#! /bin/bash
 | 
			
		||||
 | 
			
		||||
# Copyright 2016 The Kubernetes Authors All rights reserved.
 | 
			
		||||
#
 | 
			
		||||
# 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.
 | 
			
		||||
 | 
			
		||||
set -eo pipefail
 | 
			
		||||
 | 
			
		||||
# This script configures zookeeper cluster member ship for version of zookeeper
 | 
			
		||||
# >= 3.5.0. It should not be used with the on-change.sh script in this example.
 | 
			
		||||
# As of April-2016 is 3.4.8 is the latest stable.
 | 
			
		||||
 | 
			
		||||
# Both /opt and /tmp/zookeeper are assumed to be volumes shared with the parent.
 | 
			
		||||
# The format of each line in the dynamic config file is:
 | 
			
		||||
# server.<1 based index>=<server-dns-name>:<peer port>:<election port>[:role];[<client port address>:]<client port>
 | 
			
		||||
# <1 based index> is the server index that matches the id in datadir/myid
 | 
			
		||||
# <peer port> is the port on which peers communicate to agree on updates
 | 
			
		||||
# <election port> is the port used for leader election
 | 
			
		||||
# [:role] can be set to observer, participant by default
 | 
			
		||||
# <client port address> is optional and defaults to 0.0.0.0
 | 
			
		||||
# <client port> is the port on which the server accepts client connections
 | 
			
		||||
 | 
			
		||||
CFG=/opt/zookeeper/conf/zoo.cfg.dynamic
 | 
			
		||||
CFG_BAK=/opt/zookeeper/conf/zoo.cfg.bak
 | 
			
		||||
MY_ID_FILE=/tmp/zookeeper/myid
 | 
			
		||||
HOSTNAME=$(hostname)
 | 
			
		||||
 | 
			
		||||
while read -ra LINE; do
 | 
			
		||||
    PEERS=("${PEERS[@]}" $LINE)
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
# Don't add the first member as an observer
 | 
			
		||||
if [ ${#PEERS[@]} -eq 1 ]; then
 | 
			
		||||
    # We need to write our index in this list of servers into MY_ID_FILE.
 | 
			
		||||
    # Note that this may not always coincide with the hostname id.
 | 
			
		||||
    echo 1 > "${MY_ID_FILE}"
 | 
			
		||||
    echo "server.1=${PEERS[0]}:2888:3888;2181" > "${CFG}"
 | 
			
		||||
    # TODO: zkServer-initialize is the safe way to handle changes to datadir
 | 
			
		||||
    # because simply starting will create a new datadir, BUT if the user changed
 | 
			
		||||
    # pod template they might end up with 2 datadirs and brief split brain.
 | 
			
		||||
    exit
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Every subsequent member is added as an observer and promoted to a participant
 | 
			
		||||
echo "" > "${CFG_BAK}"
 | 
			
		||||
i=0
 | 
			
		||||
LEADER=$HOSTNAME
 | 
			
		||||
for peer in "${PEERS[@]}"; do
 | 
			
		||||
    let i=i+1
 | 
			
		||||
    if [[ "${peer}" == *"${HOSTNAME}"* ]]; then
 | 
			
		||||
      MY_ID=$i
 | 
			
		||||
      MY_NAME=${peer}
 | 
			
		||||
      echo $i > "${MY_ID_FILE}"
 | 
			
		||||
      echo "server.${i}=${peer}:2888:3888:observer;2181" >> "${CFG_BAK}"
 | 
			
		||||
    else
 | 
			
		||||
      if [[ $(echo srvr | /opt/nc "${peer}" 2181 | grep Mode) = "Mode: leader" ]]; then
 | 
			
		||||
        LEADER="${peer}"
 | 
			
		||||
      fi
 | 
			
		||||
      echo "server.${i}=${peer}:2888:3888:participant;2181" >> "${CFG_BAK}"
 | 
			
		||||
    fi
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
# zookeeper won't start without myid anyway.
 | 
			
		||||
# This means our hostname wasn't in the peer list.
 | 
			
		||||
if [ ! -f "${MY_ID_FILE}" ]; then
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Once the dynamic config file is written it shouldn't be modified, so the final
 | 
			
		||||
# reconfigure needs to happen through the "reconfig" command.
 | 
			
		||||
cp ${CFG_BAK} ${CFG}
 | 
			
		||||
 | 
			
		||||
# TODO: zkServer-initialize is the safe way to handle changes to datadir
 | 
			
		||||
# because simply starting will create a new datadir, BUT if the user changed
 | 
			
		||||
# pod template they might end up with 2 datadirs and brief split brain.
 | 
			
		||||
/opt/zookeeper/bin/zkServer.sh start
 | 
			
		||||
 | 
			
		||||
# TODO: We shouldn't need to specify the address of the master as long as
 | 
			
		||||
# there's quorum. According to the docs the new server is just not allowed to
 | 
			
		||||
# vote, it's still allowed to propose config changes, and it knows the
 | 
			
		||||
# existing members of the ensemble from *its* config.
 | 
			
		||||
ADD_SERVER="server.$MY_ID=$MY_NAME:2888:3888:participant;0.0.0.0:2181"
 | 
			
		||||
/opt/zookeeper/bin/zkCli.sh reconfig -s "${LEADER}":2181 -add "${ADD_SERVER}"
 | 
			
		||||
 | 
			
		||||
# Prove that we've actually joined the running cluster
 | 
			
		||||
ITERATION=0
 | 
			
		||||
until $(echo config | /opt/nc localhost 2181 | grep "${ADD_SERVER}" > /dev/null); do
 | 
			
		||||
  echo $ITERATION] waiting for updated config to sync back to localhost
 | 
			
		||||
  sleep 1
 | 
			
		||||
  let ITERATION=ITERATION+1
 | 
			
		||||
  if [ $ITERATION -eq 20 ]; then
 | 
			
		||||
    exit 1
 | 
			
		||||
  fi
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
/opt/zookeeper/bin/zkServer.sh stop
 | 
			
		||||
		Reference in New Issue
	
	Block a user