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.

container.go 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. package v6
  2. import (
  3. "github.com/pkg/errors"
  4. "github.com/fluxcd/flux/image"
  5. "github.com/fluxcd/flux/policy"
  6. "github.com/fluxcd/flux/registry"
  7. "github.com/fluxcd/flux/update"
  8. )
  9. // Container describes an individual container including current image info and
  10. // available images.
  11. type Container struct {
  12. Name string `json:",omitempty"`
  13. Current image.Info `json:",omitempty"`
  14. LatestFiltered image.Info `json:",omitempty"`
  15. // All available images (ignoring tag filters)
  16. Available update.SortedImageInfos `json:",omitempty"`
  17. AvailableError string `json:",omitempty"`
  18. AvailableImagesCount int `json:",omitempty"`
  19. NewAvailableImagesCount int `json:",omitempty"`
  20. // Filtered available images (matching tag filters)
  21. FilteredImagesCount int `json:",omitempty"`
  22. NewFilteredImagesCount int `json:",omitempty"`
  23. }
  24. type imageSorter interface {
  25. // SortedImages returns the known images, sorted according to the
  26. // pattern given
  27. SortedImages(policy.Pattern) update.SortedImageInfos
  28. // Images returns the images in no defined order
  29. Images() []image.Info
  30. }
  31. // NewContainer creates a Container given a list of images and the current image
  32. func NewContainer(name string, images imageSorter, currentImage image.Info, tagPattern policy.Pattern, fields []string) (Container, error) {
  33. // Default fields
  34. if len(fields) == 0 {
  35. fields = []string{
  36. "Name",
  37. "Current",
  38. "LatestFiltered",
  39. "Available",
  40. "AvailableError",
  41. "AvailableImagesCount",
  42. "NewAvailableImagesCount",
  43. "FilteredImagesCount",
  44. "NewFilteredImagesCount",
  45. }
  46. }
  47. var c Container
  48. // The following machinery attempts to minimise the number of
  49. // filters (`O(n)`) and sorts (`O(n log n)`), by memoising and
  50. // sharing intermediate results.
  51. var (
  52. sortedImages update.SortedImageInfos
  53. filteredImages []image.Info
  54. sortedFilteredImages update.SortedImageInfos
  55. )
  56. getFilteredImages := func() []image.Info {
  57. if filteredImages == nil {
  58. filteredImages = update.FilterImages(images.Images(), tagPattern)
  59. }
  60. return filteredImages
  61. }
  62. getSortedFilteredImages := func() update.SortedImageInfos {
  63. if sortedFilteredImages == nil {
  64. sortedFilteredImages = update.SortImages(getFilteredImages(), tagPattern)
  65. }
  66. return sortedFilteredImages
  67. }
  68. getSortedImages := func() update.SortedImageInfos {
  69. if sortedImages == nil {
  70. sortedImages = images.SortedImages(tagPattern)
  71. // now that we have the sorted images anyway, the fastest
  72. // way to get sorted, filtered images will be to filter
  73. // the already sorted images
  74. getSortedFilteredImages = func() update.SortedImageInfos {
  75. if sortedFilteredImages == nil {
  76. sortedFilteredImages = update.FilterImages(sortedImages, tagPattern)
  77. }
  78. return sortedFilteredImages
  79. }
  80. getFilteredImages = func() []image.Info {
  81. return []image.Info(getSortedFilteredImages())
  82. }
  83. }
  84. return sortedImages
  85. }
  86. // do these after we've gone through all the field names, since
  87. // they depend on what else is happening
  88. assignFields := []func(){}
  89. for _, field := range fields {
  90. switch field {
  91. // these first few rely only on the inputs
  92. case "Name":
  93. c.Name = name
  94. case "Current":
  95. c.Current = currentImage
  96. case "AvailableError":
  97. if images == nil {
  98. c.AvailableError = registry.ErrNoImageData.Error()
  99. }
  100. case "AvailableImagesCount":
  101. c.AvailableImagesCount = len(images.Images())
  102. // these required the sorted images, which we can get
  103. // straight away
  104. case "Available":
  105. c.Available = getSortedImages()
  106. case "NewAvailableImagesCount":
  107. newImagesCount := 0
  108. for _, img := range getSortedImages() {
  109. if !tagPattern.Newer(&img, &currentImage) {
  110. break
  111. }
  112. newImagesCount++
  113. }
  114. c.NewAvailableImagesCount = newImagesCount
  115. // these depend on what else gets calculated, so do them afterwards
  116. case "LatestFiltered": // needs sorted, filtered images
  117. assignFields = append(assignFields, func() {
  118. latest, _ := getSortedFilteredImages().Latest()
  119. c.LatestFiltered = latest
  120. })
  121. case "FilteredImagesCount": // needs filtered tags
  122. assignFields = append(assignFields, func() {
  123. c.FilteredImagesCount = len(getFilteredImages())
  124. })
  125. case "NewFilteredImagesCount": // needs filtered images
  126. assignFields = append(assignFields, func() {
  127. newFilteredImagesCount := 0
  128. for _, img := range getSortedFilteredImages() {
  129. if !tagPattern.Newer(&img, &currentImage) {
  130. break
  131. }
  132. newFilteredImagesCount++
  133. }
  134. c.NewFilteredImagesCount = newFilteredImagesCount
  135. })
  136. default:
  137. return c, errors.Errorf("%s is an invalid field", field)
  138. }
  139. }
  140. for _, fn := range assignFields {
  141. fn()
  142. }
  143. return c, nil
  144. }