fakes.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /*
  2. Copyright 2016 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package petset
  14. import (
  15. "fmt"
  16. "time"
  17. inf "gopkg.in/inf.v0"
  18. "k8s.io/kubernetes/pkg/api"
  19. api_pod "k8s.io/kubernetes/pkg/api/pod"
  20. "k8s.io/kubernetes/pkg/api/resource"
  21. "k8s.io/kubernetes/pkg/api/unversioned"
  22. "k8s.io/kubernetes/pkg/apis/apps"
  23. "k8s.io/kubernetes/pkg/client/record"
  24. "k8s.io/kubernetes/pkg/types"
  25. "k8s.io/kubernetes/pkg/util/sets"
  26. )
  27. func dec(i int64, exponent int) *inf.Dec {
  28. return inf.NewDec(i, inf.Scale(-exponent))
  29. }
  30. func newPVC(name string) api.PersistentVolumeClaim {
  31. return api.PersistentVolumeClaim{
  32. ObjectMeta: api.ObjectMeta{
  33. Name: name,
  34. },
  35. Spec: api.PersistentVolumeClaimSpec{
  36. Resources: api.ResourceRequirements{
  37. Requests: api.ResourceList{
  38. api.ResourceStorage: *resource.NewQuantity(1, resource.BinarySI),
  39. },
  40. },
  41. },
  42. }
  43. }
  44. func newPetSetWithVolumes(replicas int, name string, petMounts []api.VolumeMount, podMounts []api.VolumeMount) *apps.PetSet {
  45. mounts := append(petMounts, podMounts...)
  46. claims := []api.PersistentVolumeClaim{}
  47. for _, m := range petMounts {
  48. claims = append(claims, newPVC(m.Name))
  49. }
  50. vols := []api.Volume{}
  51. for _, m := range podMounts {
  52. vols = append(vols, api.Volume{
  53. Name: m.Name,
  54. VolumeSource: api.VolumeSource{
  55. HostPath: &api.HostPathVolumeSource{
  56. Path: fmt.Sprintf("/tmp/%v", m.Name),
  57. },
  58. },
  59. })
  60. }
  61. return &apps.PetSet{
  62. TypeMeta: unversioned.TypeMeta{
  63. Kind: "PetSet",
  64. APIVersion: "apps/v1beta1",
  65. },
  66. ObjectMeta: api.ObjectMeta{
  67. Name: name,
  68. Namespace: api.NamespaceDefault,
  69. UID: types.UID("test"),
  70. },
  71. Spec: apps.PetSetSpec{
  72. Selector: &unversioned.LabelSelector{
  73. MatchLabels: map[string]string{"foo": "bar"},
  74. },
  75. Replicas: replicas,
  76. Template: api.PodTemplateSpec{
  77. Spec: api.PodSpec{
  78. Containers: []api.Container{
  79. {
  80. Name: "nginx",
  81. Image: "nginx",
  82. VolumeMounts: mounts,
  83. },
  84. },
  85. Volumes: vols,
  86. },
  87. },
  88. VolumeClaimTemplates: claims,
  89. ServiceName: "governingsvc",
  90. },
  91. }
  92. }
  93. func runningPod(ns, name string) *api.Pod {
  94. p := &api.Pod{Status: api.PodStatus{Phase: api.PodRunning}}
  95. p.Namespace = ns
  96. p.Name = name
  97. return p
  98. }
  99. func newPodList(ps *apps.PetSet, num int) []*api.Pod {
  100. // knownPods are pods in the system
  101. knownPods := []*api.Pod{}
  102. for i := 0; i < num; i++ {
  103. k, _ := newPCB(fmt.Sprintf("%v", i), ps)
  104. knownPods = append(knownPods, k.pod)
  105. }
  106. return knownPods
  107. }
  108. func newPetSet(replicas int) *apps.PetSet {
  109. petMounts := []api.VolumeMount{
  110. {Name: "datadir", MountPath: "/tmp/zookeeper"},
  111. }
  112. podMounts := []api.VolumeMount{
  113. {Name: "home", MountPath: "/home"},
  114. }
  115. return newPetSetWithVolumes(replicas, "foo", petMounts, podMounts)
  116. }
  117. func checkPodForMount(pod *api.Pod, mountName string) error {
  118. for _, c := range pod.Spec.Containers {
  119. for _, v := range c.VolumeMounts {
  120. if v.Name == mountName {
  121. return nil
  122. }
  123. }
  124. }
  125. return fmt.Errorf("Found volume but no associated mount %v in pod %v", mountName, pod.Name)
  126. }
  127. func newFakePetClient() *fakePetClient {
  128. return &fakePetClient{
  129. pets: []*pcb{},
  130. claims: []api.PersistentVolumeClaim{},
  131. recorder: &record.FakeRecorder{},
  132. petHealthChecker: &defaultPetHealthChecker{},
  133. }
  134. }
  135. type fakePetClient struct {
  136. pets []*pcb
  137. claims []api.PersistentVolumeClaim
  138. petsCreated, petsDeleted int
  139. claimsCreated, claimsDeleted int
  140. recorder record.EventRecorder
  141. petHealthChecker
  142. }
  143. // Delete fakes pet client deletion.
  144. func (f *fakePetClient) Delete(p *pcb) error {
  145. pets := []*pcb{}
  146. found := false
  147. for i, pet := range f.pets {
  148. if p.pod.Name == pet.pod.Name {
  149. found = true
  150. f.recorder.Eventf(pet.parent, api.EventTypeNormal, "SuccessfulDelete", "pet: %v", pet.pod.Name)
  151. continue
  152. }
  153. pets = append(pets, f.pets[i])
  154. }
  155. if !found {
  156. // TODO: Return proper not found error
  157. return fmt.Errorf("Delete failed: pet %v doesn't exist", p.pod.Name)
  158. }
  159. f.pets = pets
  160. f.petsDeleted++
  161. return nil
  162. }
  163. // Get fakes getting pets.
  164. func (f *fakePetClient) Get(p *pcb) (*pcb, bool, error) {
  165. for i, pet := range f.pets {
  166. if p.pod.Name == pet.pod.Name {
  167. return f.pets[i], true, nil
  168. }
  169. }
  170. return nil, false, nil
  171. }
  172. // Create fakes pet creation.
  173. func (f *fakePetClient) Create(p *pcb) error {
  174. for _, pet := range f.pets {
  175. if p.pod.Name == pet.pod.Name {
  176. return fmt.Errorf("Create failed: pet %v already exists", p.pod.Name)
  177. }
  178. }
  179. f.recorder.Eventf(p.parent, api.EventTypeNormal, "SuccessfulCreate", "pet: %v", p.pod.Name)
  180. f.pets = append(f.pets, p)
  181. f.petsCreated++
  182. return nil
  183. }
  184. // Update fakes pet updates.
  185. func (f *fakePetClient) Update(expected, wanted *pcb) error {
  186. found := false
  187. pets := []*pcb{}
  188. for i, pet := range f.pets {
  189. if wanted.pod.Name == pet.pod.Name {
  190. f.pets[i].pod.Annotations[api_pod.PodHostnameAnnotation] = wanted.pod.Annotations[api_pod.PodHostnameAnnotation]
  191. f.pets[i].pod.Annotations[api_pod.PodSubdomainAnnotation] = wanted.pod.Annotations[api_pod.PodSubdomainAnnotation]
  192. f.pets[i].pod.Spec = wanted.pod.Spec
  193. found = true
  194. }
  195. pets = append(pets, f.pets[i])
  196. }
  197. f.pets = pets
  198. if !found {
  199. return fmt.Errorf("Cannot update pet %v not found", wanted.pod.Name)
  200. }
  201. // TODO: Delete pvcs/volumes that are in wanted but not in expected.
  202. return nil
  203. }
  204. func (f *fakePetClient) getPodList() []*api.Pod {
  205. p := []*api.Pod{}
  206. for i, pet := range f.pets {
  207. if pet.pod == nil {
  208. continue
  209. }
  210. p = append(p, f.pets[i].pod)
  211. }
  212. return p
  213. }
  214. func (f *fakePetClient) deletePetAtIndex(index int) {
  215. p := []*pcb{}
  216. for i := range f.pets {
  217. if i != index {
  218. p = append(p, f.pets[i])
  219. }
  220. }
  221. f.pets = p
  222. }
  223. func (f *fakePetClient) setHealthy(index int) error {
  224. if len(f.pets) < index {
  225. return fmt.Errorf("Index out of range, len %v index %v", len(f.pets), index)
  226. }
  227. f.pets[index].pod.Status.Phase = api.PodRunning
  228. f.pets[index].pod.Annotations[PetSetInitAnnotation] = "true"
  229. f.pets[index].pod.Status.Conditions = []api.PodCondition{
  230. {Type: api.PodReady, Status: api.ConditionTrue},
  231. }
  232. return nil
  233. }
  234. // isHealthy is a convenience wrapper around the default health checker.
  235. // The first invocation returns not-healthy, but marks the pet healthy so
  236. // subsequent invocations see it as healthy.
  237. func (f *fakePetClient) isHealthy(pod *api.Pod) bool {
  238. if f.petHealthChecker.isHealthy(pod) {
  239. return true
  240. }
  241. return false
  242. }
  243. func (f *fakePetClient) setDeletionTimestamp(index int) error {
  244. if len(f.pets) < index {
  245. return fmt.Errorf("Index out of range, len %v index %v", len(f.pets), index)
  246. }
  247. f.pets[index].pod.DeletionTimestamp = &unversioned.Time{Time: time.Now()}
  248. return nil
  249. }
  250. // SyncPVCs fakes pvc syncing.
  251. func (f *fakePetClient) SyncPVCs(pet *pcb) error {
  252. v := pet.pvcs
  253. updateClaims := map[string]api.PersistentVolumeClaim{}
  254. for i, update := range v {
  255. updateClaims[update.Name] = v[i]
  256. }
  257. claimList := []api.PersistentVolumeClaim{}
  258. for i, existing := range f.claims {
  259. if update, ok := updateClaims[existing.Name]; ok {
  260. claimList = append(claimList, update)
  261. delete(updateClaims, existing.Name)
  262. } else {
  263. claimList = append(claimList, f.claims[i])
  264. }
  265. }
  266. for _, remaining := range updateClaims {
  267. claimList = append(claimList, remaining)
  268. f.claimsCreated++
  269. f.recorder.Eventf(pet.parent, api.EventTypeNormal, "SuccessfulCreate", "pvc: %v", remaining.Name)
  270. }
  271. f.claims = claimList
  272. return nil
  273. }
  274. // DeletePVCs fakes pvc deletion.
  275. func (f *fakePetClient) DeletePVCs(pet *pcb) error {
  276. claimsToDelete := pet.pvcs
  277. deleteClaimNames := sets.NewString()
  278. for _, c := range claimsToDelete {
  279. deleteClaimNames.Insert(c.Name)
  280. }
  281. pvcs := []api.PersistentVolumeClaim{}
  282. for i, existing := range f.claims {
  283. if deleteClaimNames.Has(existing.Name) {
  284. deleteClaimNames.Delete(existing.Name)
  285. f.claimsDeleted++
  286. f.recorder.Eventf(pet.parent, api.EventTypeNormal, "SuccessfulDelete", "pvc: %v", existing.Name)
  287. continue
  288. }
  289. pvcs = append(pvcs, f.claims[i])
  290. }
  291. f.claims = pvcs
  292. if deleteClaimNames.Len() != 0 {
  293. return fmt.Errorf("Claims %+v don't exist. Failed deletion.", deleteClaimNames)
  294. }
  295. return nil
  296. }