Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: fully support project CRD #1388

Merged
merged 15 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions api/service/v1alpha1/service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -385,25 +385,20 @@ message DeletePromotionPolicyResponse {
/* explicitly empty */
}

message Project {
string name = 1;
google.protobuf.Timestamp create_time = 2;
}
Comment on lines -388 to -391
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This moved to types.proto where we have the protobuf definitions of anything that's also a CRD.


message CreateProjectRequest {
string name = 1;
}

message CreateProjectResponse {
Project project = 1;
github.com.akuity.kargo.pkg.api.v1alpha1.Project project = 1;
}

message ListProjectsRequest {
/* explicitly empty */
}

message ListProjectsResponse {
repeated Project projects = 1;
repeated github.com.akuity.kargo.pkg.api.v1alpha1.Project projects = 1;
}

message DeleteProjectRequest {
Expand Down
2 changes: 1 addition & 1 deletion api/v1alpha1/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package v1alpha1

const (
AliasLabelKey = "kargo.akuity.io/alias"
LabelProjectKey = "kargo.akuity.io/project"
FreightLabelKey = "kargo.akuity.io/freight"
ProjectLabelKey = "kargo.akuity.io/project"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed this symbol just for consistency with the others.

ShardLabelKey = "kargo.akuity.io/shard"
StageLabelKey = "kargo.akuity.io/stage"

Expand Down
31 changes: 31 additions & 0 deletions api/v1alpha1/project_helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package v1alpha1

import (
"context"

"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// GetProject returns a pointer to the cluster-scoped Project resource specified
// by the name argument. If no such resource is found, nil is returned instead.
func GetProject(
ctx context.Context,
c client.Client,
name string,
) (*Project, error) {
project := Project{}
if err := c.Get(
ctx, types.NamespacedName{
Name: name,
},
&project,
); err != nil {
if err = client.IgnoreNotFound(err); err == nil {
return nil, nil
}
return nil, errors.Wrapf(err, "error getting Project %q", name)
}
return &project, nil
}
58 changes: 58 additions & 0 deletions api/v1alpha1/project_helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package v1alpha1

import (
"context"
"testing"

"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
)

func TestGetProject(t *testing.T) {
scheme := k8sruntime.NewScheme()
require.NoError(t, SchemeBuilder.AddToScheme(scheme))

testCases := []struct {
name string
client client.Client
assertions func(*Project, error)
}{
{
name: "not found",
client: fake.NewClientBuilder().WithScheme(scheme).Build(),
assertions: func(project *Project, err error) {
require.NoError(t, err)
require.Nil(t, project)
},
},

{
name: "found",
client: fake.NewClientBuilder().WithScheme(scheme).WithObjects(
&Project{
ObjectMeta: metav1.ObjectMeta{
Name: "fake-project",
},
},
).Build(),
assertions: func(project *Project, err error) {
require.NoError(t, err)
require.Equal(t, "fake-project", project.Name)
},
},
}

for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
project, err := GetProject(
context.Background(),
testCase.client,
"fake-project",
)
testCase.assertions(project, err)
})
}
}
35 changes: 31 additions & 4 deletions api/v1alpha1/project_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,33 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type ProjectPhase string

const (
// ProjectPhaseInitializing denotes a Project that is not yet fully
// initialized.
ProjectPhaseInitializing ProjectPhase = "Initializing"
// ProjectPhaseInitializationFailed denotes a Project while failed to
// initialize properly.
ProjectPhaseInitializationFailed ProjectPhase = "InitializationFailed"
// ProjectPhaseReady denotes a Project that is fully initialized.
ProjectPhaseReady ProjectPhase = "Ready"
)

// IsTerminal returns true if the ProjectPhase is a terminal one.
func (p *ProjectPhase) IsTerminal() bool {
switch *p {
case ProjectPhaseInitializationFailed, ProjectPhaseReady:
return true
default:
return false
}
}

//+kubebuilder:object:root=true
//+kubebuilder:resource:scope=Cluster
//+kubebuilder:subresource:status
//+kubebuilder:printcolumn:name=Phase,type=string,JSONPath=`.status.phase`
//+kubebuilder:printcolumn:name=Age,type=date,JSONPath=`.metadata.creationTimestamp`

// Project is a resource type that reconciles to a specially labeled namespace
Expand All @@ -15,9 +39,7 @@ type Project struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
// Spec describes a Project.
//
//+kubebuilder:validation:Required
Spec *ProjectSpec `json:"spec"`
Spec *ProjectSpec `json:"spec,omitempty"`
// Status describes the Project's current status.
Status ProjectStatus `json:"status,omitempty"`
}
Expand All @@ -33,7 +55,12 @@ type ProjectSpec struct {

// ProjectStatus describes a Project's current status.
type ProjectStatus struct {
// TODO: Figure out the attributes of a ProjectStatus.
// Phase describes the Project's current phase.
Phase ProjectPhase `json:"phase,omitempty"`
// Message is a display message about the Project, including any errors
// preventing the Project from being reconciled. i.e. If the Phase field has a
// value of CreationFailed, this field can be expected to explain why.
Message string `json:"message,omitempty"`
}

//+kubebuilder:object:root=true
Expand Down
12 changes: 12 additions & 0 deletions api/v1alpha1/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,18 @@ message KustomizePromotionMechanism {
repeated KustomizeImageUpdate images = 1 [json_name = "images"];
}

message Project {
string api_version = 1 [json_name = "apiVersion"];
string kind = 2 [json_name = "kind"];
github.com.akuity.kargo.pkg.api.metav1.ObjectMeta metadata = 3 [json_name = "metadata"];
ProjectStatus status = 4 [json_name = "status"];
}

message ProjectStatus {
string phase = 1 [json_name = "phase"];
string message = 2 [json_name = "message"];
}

message Promotion {
string api_version = 1 [json_name = "apiVersion"];
string kind = 2 [json_name = "kind"];
Expand Down
15 changes: 13 additions & 2 deletions charts/kargo/crds/kargo.akuity.io_projects.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ spec:
scope: Cluster
versions:
- additionalPrinterColumns:
- jsonPath: .status.phase
name: Phase
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
Expand All @@ -41,9 +44,17 @@ spec:
type: object
status:
description: Status describes the Project's current status.
properties:
message:
description: Message is a display message about the Project, including
any errors preventing the Project from being reconciled. i.e. If
the Phase field has a value of CreationFailed, this field can be
expected to explain why.
type: string
phase:
description: Phase describes the Project's current phase.
type: string
type: object
required:
- spec
type: object
served: true
storage: true
Expand Down
5 changes: 1 addition & 4 deletions charts/kargo/templates/api/cluster-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,9 @@ rules:
resources:
- namespaces
verbs:
- create
- get
- list
- watch
- patch
- update
- delete
- apiGroups:
- ""
resources:
Expand Down Expand Up @@ -53,6 +49,7 @@ rules:
- apiGroups:
- kargo.akuity.io
resources:
- projects
- promotionpolicies
- stages
- warehouses
Expand Down
19 changes: 19 additions & 0 deletions charts/kargo/templates/management-controller/cluster-roles.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,31 @@ metadata:
{{- include "kargo.labels" . | nindent 4 }}
{{- include "kargo.managementController.labels" . | nindent 4 }}
rules:
- apiGroups:
- ""
resources:
- namespaces
verbs:
- create
- get
- list
- patch
- update
- watch
- apiGroups:
- kargo.akuity.io
resources:
- projects
verbs:
- delete
- get
- list
- watch
- apiGroups:
- kargo.akuity.io
resources:
- projects/status
verbs:
- patch
- update
{{- end }}
32 changes: 20 additions & 12 deletions charts/kargo/templates/webhooks-server/cluster-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,31 @@ metadata:
{{- include "kargo.webhooksServer.labels" . | nindent 4 }}
rules:
- apiGroups:
- ""
- ""
resources:
- namespaces
- namespaces
verbs:
- get
- list
- watch
- get
- list
- watch
- apiGroups:
- kargo.akuity.io
- kargo.akuity.io
resources:
- freights
- projects
- promotionpolicies
- stages
verbs:
- get
- list
- watch
- apiGroups:
- kargo.akuity.io
resources:
- freights
- promotionpolicies
- stages
- project/status
verbs:
- get
- list
- watch
- patch
- update
- apiGroups:
- authorization.k8s.io
resources:
Expand Down
15 changes: 15 additions & 0 deletions charts/kargo/templates/webhooks/webhooks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,21 @@ webhooks:
resources: ["freights"]
operations: ["CREATE", "UPDATE", "DELETE"]
failurePolicy: Fail
- name: project.kargo.akuity.io
admissionReviewVersions: ["v1"]
sideEffects: None
clientConfig:
service:
namespace: {{ .Release.Namespace }}
name: kargo-webhooks-server
path: /validate-kargo-akuity-io-v1alpha1-project
rules:
- scope: Cluster
apiGroups: ["kargo.akuity.io"]
apiVersions: ["v1alpha1"]
resources: ["projects"]
operations: ["CREATE"]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the moment, only need to validate creates.

failurePolicy: Fail
- name: promotion.kargo.akuity.io
admissionReviewVersions: ["v1"]
sideEffects: None
Expand Down
5 changes: 5 additions & 0 deletions cmd/controlplane/management_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

kargoapi "github.com/akuity/kargo/api/v1alpha1"
"github.com/akuity/kargo/internal/api/kubernetes"
"github.com/akuity/kargo/internal/controller/management/namespaces"
"github.com/akuity/kargo/internal/controller/management/projects"
"github.com/akuity/kargo/internal/os"
versionpkg "github.com/akuity/kargo/internal/version"
Expand Down Expand Up @@ -72,6 +73,10 @@ func newManagementControllerCommand() *cobra.Command {
}
}

if err := namespaces.SetupReconcilerWithManager(kargoMgr); err != nil {
return errors.Wrap(err, "error setting up Namespaces reconciler")
}

if err := projects.SetupReconcilerWithManager(kargoMgr); err != nil {
return errors.Wrap(err, "error setting up Projects reconciler")
}
Expand Down
Loading
Loading