...

Source file src/github.com/fluxcd/helm-controller/api/v2/snapshot_types.go

Documentation: github.com/fluxcd/helm-controller/api/v2

     1  /*
     2  Copyright 2024 The Flux authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package v2
    18  
    19  import (
    20  	"fmt"
    21  	"sort"
    22  
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  )
    25  
    26  const (
    27  	// snapshotStatusDeployed indicates that the release the snapshot was taken
    28  	// from is currently deployed.
    29  	snapshotStatusDeployed = "deployed"
    30  	// snapshotStatusSuperseded indicates that the release the snapshot was taken
    31  	// from has been superseded by a newer release.
    32  	snapshotStatusSuperseded = "superseded"
    33  
    34  	// snapshotTestPhaseFailed indicates that the test of the release the snapshot
    35  	// was taken from has failed.
    36  	snapshotTestPhaseFailed = "Failed"
    37  )
    38  
    39  // Snapshots is a list of Snapshot objects.
    40  type Snapshots []*Snapshot
    41  
    42  // Len returns the number of Snapshots.
    43  func (in Snapshots) Len() int {
    44  	return len(in)
    45  }
    46  
    47  // SortByVersion sorts the Snapshots by version, in descending order.
    48  func (in Snapshots) SortByVersion() {
    49  	sort.Slice(in, func(i, j int) bool {
    50  		return in[i].Version > in[j].Version
    51  	})
    52  }
    53  
    54  // Latest returns the most recent Snapshot.
    55  func (in Snapshots) Latest() *Snapshot {
    56  	if len(in) == 0 {
    57  		return nil
    58  	}
    59  	in.SortByVersion()
    60  	return in[0]
    61  }
    62  
    63  // Previous returns the most recent Snapshot before the Latest that has a
    64  // status of "deployed" or "superseded", or nil if there is no such Snapshot.
    65  // Unless ignoreTests is true, Snapshots with a test in the "Failed" phase are
    66  // ignored.
    67  func (in Snapshots) Previous(ignoreTests bool) *Snapshot {
    68  	if len(in) < 2 {
    69  		return nil
    70  	}
    71  	in.SortByVersion()
    72  	for i := range in[1:] {
    73  		s := in[i+1]
    74  		if s.Status == snapshotStatusDeployed || s.Status == snapshotStatusSuperseded {
    75  			if ignoreTests || !s.HasTestInPhase(snapshotTestPhaseFailed) {
    76  				return s
    77  			}
    78  		}
    79  	}
    80  	return nil
    81  }
    82  
    83  // Truncate removes all Snapshots up to the Previous deployed Snapshot.
    84  // If there is no previous-deployed Snapshot, the most recent 5 Snapshots are
    85  // retained.
    86  func (in *Snapshots) Truncate(ignoreTests bool) {
    87  	if in.Len() < 2 {
    88  		return
    89  	}
    90  
    91  	in.SortByVersion()
    92  	for i := range (*in)[1:] {
    93  		s := (*in)[i+1]
    94  		if s.Status == snapshotStatusDeployed || s.Status == snapshotStatusSuperseded {
    95  			if ignoreTests || !s.HasTestInPhase(snapshotTestPhaseFailed) {
    96  				*in = (*in)[:i+2]
    97  				return
    98  			}
    99  		}
   100  	}
   101  
   102  	if in.Len() > defaultMaxHistory {
   103  		// If none of the Snapshots are deployed or superseded, and there
   104  		// are more than the defaultMaxHistory, truncate to the most recent
   105  		// Snapshots.
   106  		*in = (*in)[:defaultMaxHistory]
   107  	}
   108  }
   109  
   110  // Snapshot captures a point-in-time copy of the status information for a Helm release,
   111  // as managed by the controller.
   112  type Snapshot struct {
   113  	// APIVersion is the API version of the Snapshot.
   114  	// Provisional: when the calculation method of the Digest field is changed,
   115  	// this field will be used to distinguish between the old and new methods.
   116  	// +optional
   117  	APIVersion string `json:"apiVersion,omitempty"`
   118  	// Digest is the checksum of the release object in storage.
   119  	// It has the format of `<algo>:<checksum>`.
   120  	// +required
   121  	Digest string `json:"digest"`
   122  	// Name is the name of the release.
   123  	// +required
   124  	Name string `json:"name"`
   125  	// Namespace is the namespace the release is deployed to.
   126  	// +required
   127  	Namespace string `json:"namespace"`
   128  	// Version is the version of the release object in storage.
   129  	// +required
   130  	Version int `json:"version"`
   131  	// Status is the current state of the release.
   132  	// +required
   133  	Status string `json:"status"`
   134  	// ChartName is the chart name of the release object in storage.
   135  	// +required
   136  	ChartName string `json:"chartName"`
   137  	// ChartVersion is the chart version of the release object in
   138  	// storage.
   139  	// +required
   140  	ChartVersion string `json:"chartVersion"`
   141  	// AppVersion is the chart app version of the release object in storage.
   142  	// +optional
   143  	AppVersion string `json:"appVersion,omitempty"`
   144  	// ConfigDigest is the checksum of the config (better known as
   145  	// "values") of the release object in storage.
   146  	// It has the format of `<algo>:<checksum>`.
   147  	// +required
   148  	ConfigDigest string `json:"configDigest"`
   149  	// FirstDeployed is when the release was first deployed.
   150  	// +required
   151  	FirstDeployed metav1.Time `json:"firstDeployed"`
   152  	// LastDeployed is when the release was last deployed.
   153  	// +required
   154  	LastDeployed metav1.Time `json:"lastDeployed"`
   155  	// Deleted is when the release was deleted.
   156  	// +optional
   157  	Deleted metav1.Time `json:"deleted,omitempty"`
   158  	// TestHooks is the list of test hooks for the release as observed to be
   159  	// run by the controller.
   160  	// +optional
   161  	TestHooks *map[string]*TestHookStatus `json:"testHooks,omitempty"`
   162  	// OCIDigest is the digest of the OCI artifact associated with the release.
   163  	// +optional
   164  	OCIDigest string `json:"ociDigest,omitempty"`
   165  }
   166  
   167  // FullReleaseName returns the full name of the release in the format
   168  // of '<namespace>/<name>.<version>
   169  func (in *Snapshot) FullReleaseName() string {
   170  	if in == nil {
   171  		return ""
   172  	}
   173  	return fmt.Sprintf("%s/%s.v%d", in.Namespace, in.Name, in.Version)
   174  }
   175  
   176  // VersionedChartName returns the full name of the chart in the format of
   177  // '<name>@<version>'.
   178  func (in *Snapshot) VersionedChartName() string {
   179  	if in == nil {
   180  		return ""
   181  	}
   182  	return fmt.Sprintf("%s@%s", in.ChartName, in.ChartVersion)
   183  }
   184  
   185  // HasBeenTested returns true if TestHooks is not nil. This includes an empty
   186  // map, which indicates the chart has no tests.
   187  func (in *Snapshot) HasBeenTested() bool {
   188  	return in != nil && in.TestHooks != nil
   189  }
   190  
   191  // GetTestHooks returns the TestHooks for the release if not nil.
   192  func (in *Snapshot) GetTestHooks() map[string]*TestHookStatus {
   193  	if in == nil || in.TestHooks == nil {
   194  		return nil
   195  	}
   196  	return *in.TestHooks
   197  }
   198  
   199  // HasTestInPhase returns true if any of the TestHooks is in the given phase.
   200  func (in *Snapshot) HasTestInPhase(phase string) bool {
   201  	if in != nil {
   202  		for _, h := range in.GetTestHooks() {
   203  			if h.Phase == phase {
   204  				return true
   205  			}
   206  		}
   207  	}
   208  	return false
   209  }
   210  
   211  // SetTestHooks sets the TestHooks for the release.
   212  func (in *Snapshot) SetTestHooks(hooks map[string]*TestHookStatus) {
   213  	if in == nil || hooks == nil {
   214  		return
   215  	}
   216  	in.TestHooks = &hooks
   217  }
   218  
   219  // Targets returns true if the Snapshot targets the given release data.
   220  func (in *Snapshot) Targets(name, namespace string, version int) bool {
   221  	if in != nil {
   222  		return in.Name == name && in.Namespace == namespace && in.Version == version
   223  	}
   224  	return false
   225  }
   226  
   227  // TestHookStatus holds the status information for a test hook as observed
   228  // to be run by the controller.
   229  type TestHookStatus struct {
   230  	// LastStarted is the time the test hook was last started.
   231  	// +optional
   232  	LastStarted metav1.Time `json:"lastStarted,omitempty"`
   233  	// LastCompleted is the time the test hook last completed.
   234  	// +optional
   235  	LastCompleted metav1.Time `json:"lastCompleted,omitempty"`
   236  	// Phase the test hook was observed to be in.
   237  	// +optional
   238  	Phase string `json:"phase,omitempty"`
   239  }
   240  

View as plain text