forked from akuity/kargo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add Freight and Warehouse resource types (akuity#911)
Signed-off-by: Kent <kent.rancourt@gmail.com>
- Loading branch information
Showing
98 changed files
with
8,824 additions
and
4,201 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package v1alpha1 | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/pkg/errors" | ||
"k8s.io/apimachinery/pkg/types" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
) | ||
|
||
// GetFreight returns a pointer to the Freight resource specified by the | ||
// namespacedName argument. If no such resource is found, nil is returned | ||
// instead. | ||
func GetFreight( | ||
ctx context.Context, | ||
c client.Client, | ||
namespacedName types.NamespacedName, | ||
) (*Freight, error) { | ||
freight := Freight{} | ||
if err := c.Get(ctx, namespacedName, &freight); err != nil { | ||
if err = client.IgnoreNotFound(err); err == nil { | ||
return nil, nil | ||
} | ||
return nil, errors.Wrapf( | ||
err, | ||
"error getting Freight %q in namespace %q", | ||
namespacedName.Name, | ||
namespacedName.Namespace, | ||
) | ||
} | ||
return &freight, nil | ||
} | ||
|
||
// GetQualifiedFreight returns a pointer to the Freight resource specified by | ||
// the namespacedName argument if it is found and EITHER no Stages were | ||
// specified in the function call OR the Freight has qualified for ANY of the | ||
// specified Stages. If all other cases, nil is returned instead. | ||
// | ||
// Note: The rationale for returning the found Freight (if any) instead of nil | ||
// when no Stages are specified is that the Stages provided are typically the | ||
// names of Stages UPSTREAM from some other Stage. i.e. The typical use for this | ||
// function is to answer whether a piece of Freight has qualified for any of a | ||
// given Stage's UPSTREAM Stages. Some Stages have no upstream Stages, so any | ||
// Freight that is found is implicitly qualified. | ||
func GetQualifiedFreight( | ||
ctx context.Context, | ||
c client.Client, | ||
namespacedName types.NamespacedName, | ||
stages []string, | ||
) (*Freight, error) { | ||
freight, err := GetFreight(ctx, c, namespacedName) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if freight == nil { | ||
return nil, nil | ||
} | ||
if len(stages) == 0 { | ||
return freight, nil | ||
} | ||
for qualifiedStage := range freight.Status.Qualifications { | ||
for _, stage := range stages { | ||
if qualifiedStage == stage { | ||
return freight, nil | ||
} | ||
} | ||
} | ||
return nil, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package v1alpha1 | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
k8sruntime "k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/types" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/client/fake" | ||
) | ||
|
||
func TestGetFreight(t *testing.T) { | ||
scheme := k8sruntime.NewScheme() | ||
require.NoError(t, SchemeBuilder.AddToScheme(scheme)) | ||
|
||
testCases := []struct { | ||
name string | ||
client client.Client | ||
assertions func(*Freight, error) | ||
}{ | ||
{ | ||
name: "not found", | ||
client: fake.NewClientBuilder().WithScheme(scheme).Build(), | ||
assertions: func(freight *Freight, err error) { | ||
require.NoError(t, err) | ||
require.Nil(t, freight) | ||
}, | ||
}, | ||
|
||
{ | ||
name: "found", | ||
client: fake.NewClientBuilder().WithScheme(scheme).WithObjects( | ||
&Freight{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "fake-freight", | ||
Namespace: "fake-namespace", | ||
}, | ||
}, | ||
).Build(), | ||
assertions: func(freight *Freight, err error) { | ||
require.NoError(t, err) | ||
require.Equal(t, "fake-freight", freight.Name) | ||
require.Equal(t, "fake-namespace", freight.Namespace) | ||
}, | ||
}, | ||
} | ||
|
||
for _, testCase := range testCases { | ||
t.Run(testCase.name, func(t *testing.T) { | ||
freight, err := GetFreight( | ||
context.Background(), | ||
testCase.client, | ||
types.NamespacedName{ | ||
Namespace: "fake-namespace", | ||
Name: "fake-freight", | ||
}, | ||
) | ||
testCase.assertions(freight, err) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package v1alpha1 | ||
|
||
import ( | ||
"crypto/sha1" | ||
"fmt" | ||
"sort" | ||
"strings" | ||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
//+kubebuilder:object:root=true | ||
//+kubebuilder:subresource:status | ||
|
||
// Freight represents a collection of versioned artifacts. | ||
type Freight struct { | ||
metav1.TypeMeta `json:",inline"` | ||
metav1.ObjectMeta `json:"metadata,omitempty"` | ||
// ID is a system-assigned value that is derived deterministically from the | ||
// contents of the Freight. i.e. Two pieces of Freight can be compared for | ||
// equality by comparing their IDs. | ||
ID string `json:"id,omitempty"` | ||
// Commits describes specific Git repository commits. | ||
Commits []GitCommit `json:"commits,omitempty"` | ||
// Images describes specific versions of specific container images. | ||
Images []Image `json:"images,omitempty"` | ||
// Charts describes specific versions of specific Helm charts. | ||
Charts []Chart `json:"charts,omitempty"` | ||
// Status describes the current status of this Freight. | ||
Status FreightStatus `json:"status,omitempty"` | ||
} | ||
|
||
func (f *Freight) GetStatus() *FreightStatus { | ||
return &f.Status | ||
} | ||
|
||
// UpdateID deterministically calculates a piece of Freight's ID based on its | ||
// contents and assigns it to the ID field. | ||
func (f *Freight) UpdateID() { | ||
size := len(f.Commits) + len(f.Images) + len(f.Charts) | ||
artifacts := make([]string, 0, size) | ||
for _, commit := range f.Commits { | ||
artifacts = append( | ||
artifacts, | ||
fmt.Sprintf("%s:%s", commit.RepoURL, commit.ID), | ||
) | ||
} | ||
for _, image := range f.Images { | ||
artifacts = append( | ||
artifacts, | ||
fmt.Sprintf("%s:%s", image.RepoURL, image.Tag), | ||
) | ||
} | ||
for _, chart := range f.Charts { | ||
artifacts = append( | ||
artifacts, | ||
fmt.Sprintf("%s/%s:%s", chart.RegistryURL, chart.Name, chart.Version), | ||
) | ||
} | ||
sort.Strings(artifacts) | ||
f.ID = fmt.Sprintf( | ||
"%x", | ||
sha1.Sum([]byte(strings.Join(artifacts, "|"))), | ||
) | ||
} | ||
|
||
// GitCommit describes a specific commit from a specific Git repository. | ||
type GitCommit struct { | ||
// RepoURL is the URL of a Git repository. | ||
RepoURL string `json:"repoURL,omitempty"` | ||
// ID is the ID of a specific commit in the Git repository specified by | ||
// RepoURL. | ||
ID string `json:"id,omitempty"` | ||
// Branch denotes the branch of the repository where this commit was found. | ||
Branch string `json:"branch,omitempty"` | ||
// HealthCheckCommit is the ID of a specific commit. When specified, | ||
// assessments of Stage health will used this value (instead of ID) when | ||
// determining if applicable sources of Argo CD Application resources | ||
// associated with the Stage are or are not synced to this commit. Note that | ||
// there are cases (as in that of Bookkeeper being utilized as a promotion | ||
// mechanism) wherein the value of this field may differ from the commit ID | ||
// found in the ID field. | ||
HealthCheckCommit string `json:"healthCheckCommit,omitempty"` | ||
// Message is the git commit message | ||
Message string `json:"message,omitempty"` | ||
// Author is the git commit author | ||
Author string `json:"author,omitempty"` | ||
} | ||
|
||
// FreightStatus describes a piece of Freight's most recently observed state. | ||
type FreightStatus struct { | ||
// Qualifications describes the Stages for which this Freight has been | ||
// qualified. | ||
Qualifications map[string]Qualification `json:"qualifications,omitempty"` | ||
} | ||
|
||
// Qualification describes a Freight's qualification for a Stage. | ||
type Qualification struct{} | ||
|
||
//+kubebuilder:object:root=true | ||
|
||
// FreightList is a list of Freight resources. | ||
type FreightList struct { | ||
metav1.TypeMeta `json:",inline"` | ||
metav1.ListMeta `json:"metadata,omitempty"` | ||
Items []Freight `json:"items"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
package v1alpha1 | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestGitCommitEquals(t *testing.T) { | ||
testCases := []struct { | ||
name string | ||
lhs *GitCommit | ||
rhs *GitCommit | ||
expectedResult bool | ||
}{ | ||
{ | ||
name: "lhs and rhs both nil", | ||
expectedResult: true, | ||
}, | ||
{ | ||
name: "only lhs is nil", | ||
rhs: &GitCommit{}, | ||
expectedResult: false, | ||
}, | ||
{ | ||
name: "only rhs is nil", | ||
lhs: &GitCommit{}, | ||
expectedResult: false, | ||
}, | ||
{ | ||
name: "repoUrls differ", | ||
lhs: &GitCommit{ | ||
RepoURL: "foo", | ||
ID: "fake-commit-id", | ||
}, | ||
rhs: &GitCommit{ | ||
RepoURL: "bar", | ||
ID: "fake-commit-id", | ||
}, | ||
expectedResult: false, | ||
}, | ||
{ | ||
name: "commit IDs differ", | ||
lhs: &GitCommit{ | ||
RepoURL: "fake-url", | ||
ID: "foo", | ||
}, | ||
rhs: &GitCommit{ | ||
RepoURL: "fake-url", | ||
ID: "bar", | ||
}, | ||
expectedResult: false, | ||
}, | ||
{ | ||
name: "perfect match", | ||
lhs: &GitCommit{ | ||
RepoURL: "fake-url", | ||
ID: "fake-commit-id", | ||
}, | ||
rhs: &GitCommit{ | ||
RepoURL: "fake-url", | ||
ID: "fake-commit-id", | ||
}, | ||
expectedResult: true, | ||
}, | ||
} | ||
for _, testCase := range testCases { | ||
t.Run(testCase.name, func(t *testing.T) { | ||
require.Equal( | ||
t, | ||
testCase.expectedResult, | ||
testCase.lhs.Equals(testCase.rhs), | ||
) | ||
}) | ||
} | ||
} | ||
|
||
func TestFreightUpdateID(t *testing.T) { | ||
freight := Freight{ | ||
Commits: []GitCommit{ | ||
{ | ||
RepoURL: "fake-git-repo", | ||
ID: "fake-commit-id", | ||
}, | ||
}, | ||
Images: []Image{ | ||
{ | ||
RepoURL: "fake-image-repo", | ||
Tag: "fake-image-tag", | ||
}, | ||
}, | ||
Charts: []Chart{ | ||
{ | ||
RegistryURL: "fake-chart-registry", | ||
Name: "fake-chart", | ||
Version: "fake-chart-version", | ||
}, | ||
}, | ||
} | ||
freight.UpdateID() | ||
result := freight.ID | ||
// Doing this any number of times should yield the same ID | ||
for i := 0; i < 100; i++ { | ||
freight.UpdateID() | ||
require.Equal(t, result, freight.ID) | ||
} | ||
// Changing anything should change the result | ||
freight.Commits[0].ID = "a-different-fake-commit" | ||
freight.UpdateID() | ||
require.NotEqual(t, result, freight.ID) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.