GitOps for k8s
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

automated.go 3.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package update
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/go-kit/kit/log"
  6. "github.com/weaveworks/flux"
  7. "github.com/weaveworks/flux/image"
  8. "github.com/weaveworks/flux/resource"
  9. )
  10. type Automated struct {
  11. Changes []Change
  12. }
  13. type Change struct {
  14. ServiceID flux.ResourceID
  15. Container resource.Container
  16. ImageID image.Ref
  17. }
  18. func (a *Automated) Add(service flux.ResourceID, container resource.Container, image image.Ref) {
  19. a.Changes = append(a.Changes, Change{service, container, image})
  20. }
  21. func (a *Automated) CalculateRelease(rc ReleaseContext, logger log.Logger) ([]*ControllerUpdate, Result, error) {
  22. prefilters := []ControllerFilter{
  23. &IncludeFilter{a.serviceIDs()},
  24. }
  25. result := Result{}
  26. updates, err := rc.SelectServices(result, prefilters, nil)
  27. if err != nil {
  28. return nil, nil, err
  29. }
  30. a.markSkipped(result)
  31. updates, err = a.calculateImageUpdates(rc, updates, result, logger)
  32. if err != nil {
  33. return nil, nil, err
  34. }
  35. return updates, result, err
  36. }
  37. func (a *Automated) ReleaseType() ReleaseType {
  38. return "automated"
  39. }
  40. func (a *Automated) ReleaseKind() ReleaseKind {
  41. return ReleaseKindExecute
  42. }
  43. func (a *Automated) CommitMessage() string {
  44. var images []string
  45. for _, image := range a.Images() {
  46. images = append(images, image.String())
  47. }
  48. return fmt.Sprintf("Release %s to automated", strings.Join(images, ", "))
  49. }
  50. func (a *Automated) Images() []image.Ref {
  51. imageMap := map[image.Ref]struct{}{}
  52. for _, change := range a.Changes {
  53. imageMap[change.ImageID] = struct{}{}
  54. }
  55. var images []image.Ref
  56. for image, _ := range imageMap {
  57. images = append(images, image)
  58. }
  59. return images
  60. }
  61. func (a *Automated) markSkipped(results Result) {
  62. for _, v := range a.serviceIDs() {
  63. if _, ok := results[v]; !ok {
  64. results[v] = ControllerResult{
  65. Status: ReleaseStatusSkipped,
  66. Error: NotInRepo,
  67. }
  68. }
  69. }
  70. }
  71. func (a *Automated) calculateImageUpdates(rc ReleaseContext, candidates []*ControllerUpdate, result Result, logger log.Logger) ([]*ControllerUpdate, error) {
  72. updates := []*ControllerUpdate{}
  73. serviceMap := a.serviceMap()
  74. for _, u := range candidates {
  75. containers, err := u.Controller.ContainersOrError()
  76. if err != nil {
  77. result[u.ResourceID] = ControllerResult{
  78. Status: ReleaseStatusFailed,
  79. Error: err.Error(),
  80. }
  81. continue
  82. }
  83. changes := serviceMap[u.ResourceID]
  84. containerUpdates := []ContainerUpdate{}
  85. for _, container := range containers {
  86. currentImageID := container.Image
  87. for _, change := range changes {
  88. if change.Container.Name != container.Name {
  89. continue
  90. }
  91. newImageID := currentImageID.WithNewTag(change.ImageID.Tag)
  92. u.ManifestBytes, err = rc.Manifests().UpdateDefinition(u.ManifestBytes, container.Name, newImageID)
  93. if err != nil {
  94. return nil, err
  95. }
  96. containerUpdates = append(containerUpdates, ContainerUpdate{
  97. Container: container.Name,
  98. Current: currentImageID,
  99. Target: newImageID,
  100. })
  101. }
  102. }
  103. if len(containerUpdates) > 0 {
  104. u.Updates = containerUpdates
  105. updates = append(updates, u)
  106. result[u.ResourceID] = ControllerResult{
  107. Status: ReleaseStatusSuccess,
  108. PerContainer: containerUpdates,
  109. }
  110. } else {
  111. result[u.ResourceID] = ControllerResult{
  112. Status: ReleaseStatusIgnored,
  113. Error: DoesNotUseImage,
  114. }
  115. }
  116. }
  117. return updates, nil
  118. }
  119. func (a *Automated) serviceMap() map[flux.ResourceID][]Change {
  120. set := map[flux.ResourceID][]Change{}
  121. for _, change := range a.Changes {
  122. set[change.ServiceID] = append(set[change.ServiceID], change)
  123. }
  124. return set
  125. }
  126. func (a *Automated) serviceIDs() []flux.ResourceID {
  127. slice := []flux.ResourceID{}
  128. for service, _ := range a.serviceMap() {
  129. slice = append(slice, flux.MustParseResourceID(service.String()))
  130. }
  131. return slice
  132. }