Skip to content

Commit

Permalink
Merge branch 'master' into split-test-actions
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcelMue authored Jun 6, 2023
2 parents 4b5f386 + 02d809c commit ab08f3d
Show file tree
Hide file tree
Showing 32 changed files with 2,022 additions and 108 deletions.
3 changes: 3 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ resources:
- group: goharbor
kind: HarborCluster
version: v1beta1
- group: goharbor
kind: HarborProject
version: v1beta1
- group: goharbor
kind: HarborServerConfiguration
version: v1alpha1
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ Harbor deployment stack is controlled by a custom Harbor resource `HarborCluster
* Certification auto injection
* Manage Harbor resources with the declaration way
* Robot account
* Project
* and more
* [Auto-scaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) for each component.
* Backup/restore data (registry layer, chartmuseum data, databases content).
Expand Down Expand Up @@ -115,6 +114,7 @@ Harbor operator exposes the frontend service with ingress (CRD version: `v1beta1
* [Customize storage, database and cache services](./docs/installation/customize-storage-db-redis.md)
* [Customize images](./docs/customize-images.md)
* [Day2 configurations](docs/day2/day2-configurations.md)
* [Day2 manage Harbor projects](docs/day2/day2-harborprojects.md)
* [Upgrade Harbor cluster](./docs/LCM/upgrade-cluster.md)
* [Delete Harbor cluster](./docs/LCM/cluster-deletion.md)
* [Backup data](./docs/LCM/backup-data.md)
Expand Down
155 changes: 155 additions & 0 deletions apis/goharbor.io/v1beta1/harborproject_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package v1beta1

import (
goyaml "gopkg.in/yaml.v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8syaml "sigs.k8s.io/yaml"
)

// +genclient

// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.

// +kubebuilder:object:root=true
// +kubebuilder:storageversion
// +k8s:openapi-gen=true
// +resource:path=harborproject
// +kubebuilder:subresource:status
// +kubebuilder:resource:categories="goharbor",shortName="hp"
// +kubebuilder:printcolumn:name="ProjectName",type=string,JSONPath=`.spec.projectName`,description="Project name in Harbor"
// +kubebuilder:printcolumn:name="HarborServerConfig",type=string,JSONPath=`.spec.harborServerConfig`,description="HarborServerConfiguration name"
// +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.status`,description="HarborProject status"
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`,description="Timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC."
// HarborProject is the Schema for the harbors projects.
type HarborProject struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

Spec HarborProjectSpec `json:"spec,omitempty"`

Status HarborProjectStatus `json:"status,omitempty"`
}

// HarborProjectSpec defines the spec of HarborProject.
type HarborProjectSpec struct {
// The name of the harbor project. Has to match harbor's naming rules.
// +kubebuilder:validation:Required
// +kubebuilder:validation:Pattern="^[a-z0-9]+(?:[._-][a-z0-9]+)*$"
// +kubebuilder:validation:MaxLength=255
// +kubebuilder:validation:MinLength=1
ProjectName string `json:"projectName" yaml:"project_name"`
// The CVE allowlist for the project.
// +kubebuilder:validation:Optional
CveAllowList []string `json:"cveAllowList" yaml:"cve_allow_list_items"`
// The project's storage quota in human-readable format, like in Kubernetes memory requests/limits (Ti, Gi, Mi, Ki). The Harbor's default value is used if empty.
// +kubebuilder:validation:Optional
// +kubebuilder:validation:Pattern="^[1-9][0-9]*(Ti|Gi|Mi|Ki)$"
StorageQuota string `json:"storageQuota" yaml:"storage_quota"`
// HarborProjectMetadata related configurations.
// +kubebuilder:validation:Optional
HarborProjectMetadata *HarborProjectMetadata `json:"metadata" yaml:"metadata"`
// Group or user memberships of the project.
// +kubebuilder:validation:Optional
HarborProjectMemberships []*HarborProjectMember `json:"memberships" yaml:"memberships"`
// HarborServerConfig contains the name of a HarborServerConfig resource describing the harbor instance to manage.
// +kubebuilder:validation:Required
HarborServerConfig string `json:"harborServerConfig"`
}

// ToJSON converts project spec to json payload.
func (h HarborProjectSpec) ToJSON() ([]byte, error) {
data, err := goyaml.Marshal(h)
if err != nil {
return nil, err
}

// convert yaml to json
return k8syaml.YAMLToJSON(data)
}

// HarborProjectMetadata defines the project related metadata.
type HarborProjectMetadata struct {
// Whether content trust is enabled or not. If enabled, user can't pull unsigned images from this project.
// +kubebuilder:validation:Optional
EnableContentTrust *bool `json:"enableContentTrust,omitempty" yaml:"enable_content_trust,omitempty"`
// Whether cosign content trust is enabled or not. Similar to enableContentTrust, but using cosign.
// +kubebuilder:validation:Optional
EnableContentTrustCosign *bool `json:"enableContentTrustCosign,omitempty" yaml:"enable_content_trust_cosign,omitempty"`
// Whether to scan images automatically after pushing.
// +kubebuilder:validation:Optional
AutoScan *bool `json:"autoScan,omitempty" yaml:"auto_scan,omitempty"`
// If an image's vulnerablilities are higher than the severity defined here, the image can't be pulled. Can be either `none`, `low`, `medium`, `high` or `critical`.
// +kubebuilder:validation:Optional
// +kubebuilder:validation:Enum=none;low;medium;high;critical
Severity string `json:"severity,omitempty" yaml:"severity,omitempty"`
// Whether to prevent vulnerable images from running.
// +kubebuilder:validation:Optional
PreventVulnerable *bool `json:"preventVulnerable,omitempty" yaml:"prevent_vulnerable,omitempty"`
// The flag to indicate whether the project should be public or not.
// +kubebuilder:validation:Optional
Public *bool `json:"public,omitempty" yaml:"public,omitempty"`
// Whether this project reuses the system level CVE allowlist for itself. If this is set to `true`, the actual allowlist associated with this project will be ignored.
// +kubebuilder:validation:Optional
ReuseSysCveAllowlist *bool `json:"reuseSysCveAllowlist,omitempty" yaml:"reuse_sys_cve_allowlist,omitempty"`
}

// HarborProjectMember is a member of a HarborProject. Can be a user or group.
type HarborProjectMember struct {
// Type of the member, group or user
// +kubebuilder:validation:Enum="group";"user"
Type string `json:"type" yaml:"type"`
// Name of the member. Has to match with a existing user or group
Name string `json:"name" yaml:"name"`
// Role of the member in the Project. This controls the member's permissions on the project.
// +kubebuilder:validation:Enum="projectAdmin";"developer";"guest";"maintainer"
Role string `json:"role" yaml:"role"`
}

// HarborProjectStatusType defines the status type of project.
type HarborProjectStatusType string

const (
// HarborProjectPhaseReady represents ready status.
HarborProjectStatusReady HarborProjectStatusType = "Success"
// HarborProjectPhaseFail represents fail status.
HarborProjectStatusFail HarborProjectStatusType = "Fail"
// HarborProjectPhaseError represents unknown status.
HarborProjectStatusUnknown HarborProjectStatusType = "Unknown"
)

// HarborProjectStatus defines the status of HarborProject.
type HarborProjectStatus struct {
// Status represents harbor project status.
// +kubebuilder:validation:Optional
Status HarborProjectStatusType `json:"status,omitempty"`
// ProjectID represents ID of the managed project.
// +kubebuilder:validation:Optional
ProjectID int32 `json:"projectID,omitempty"`
// QuotaID is the ID of the project's quota. Used to be able to update it.
// +kubebuilder:validation:Optional
QuotaID int64 `json:"quotaID,omitempty"`
// MembershipHash provides a way to quickly notice changes in project membership.
// +kubebuilder:validation:Optional
MembershipHash string `json:"membershipHash,omitempty"`
// Reason represents status reason.
// +kubebuilder:validation:Optional
Reason string `json:"reason,omitempty"`
// Message provides human-readable message.
// +kubebuilder:validation:Optional
Message string `json:"message,omitempty"`
// LastApplyTime represents the last apply configuration time.
// +kubebuilder:validation:Optional
LastApplyTime *metav1.Time `json:"lastApplyTime,omitempty"`
}

// +kubebuilder:object:root=true
// HarborProjectList contains a list of HarborProjects.
type HarborProjectList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []HarborProject `json:"items"`
}

func init() { //nolint:gochecknoinits
SchemeBuilder.Register(&HarborProject{}, &HarborProjectList{})
}
73 changes: 73 additions & 0 deletions apis/goharbor.io/v1beta1/harborproject_webhook.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package v1beta1

import (
"context"

"github.com/pkg/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
runtime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field"
ctrl "sigs.k8s.io/controller-runtime"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook"
)

// log is for logging in this package.
var hplog = logf.Log.WithName("harborproject-resource")

func (hp *HarborProject) SetupWebhookWithManager(_ context.Context, mgr ctrl.Manager) error {
return ctrl.NewWebhookManagedBy(mgr).
For(hp).
Complete()
}

// +kubebuilder:webhook:verbs=create;update,path=/validate-goharbor-io-v1beta1-harborproject,mutating=false,failurePolicy=fail,groups=goharbor.io,resources=harborprojects,versions=v1beta1,name=vharborproject.kb.io,admissionReviewVersions={"v1beta1","v1"},sideEffects=None

var _ webhook.Validator = &HarborProject{}

// ValidateCreate implements webhook.Validator so a webhook will be registered for the type.
func (hp *HarborProject) ValidateCreate() error {
hplog.Info("validate create", "name", hp.Name)

return hp.Validate(nil)
}

// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type.
func (hp *HarborProject) ValidateUpdate(old runtime.Object) error {
hplog.Info("validate update", "name", hp.Name)

obj, ok := old.(*HarborProject)
if !ok {
return errors.Errorf("failed type assertion on kind: %s", old.GetObjectKind().GroupVersionKind().String())
}

return hp.Validate(obj)
}

// ValidateDelete implements webhook.Validator so a webhook will be registered for the type.
func (hp *HarborProject) ValidateDelete() error {
hplog.Info("validate delete", "name", hp.Name)

return nil
}

func (hp *HarborProject) Validate(old *HarborProject) error {
var allErrs field.ErrorList

if old != nil { // update harborproject resource
if hp.Spec.ProjectName != old.Spec.ProjectName {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("projectName"), hp.Spec.ProjectName, "field cannot be changed after initial creation"))
}

if hp.Spec.HarborServerConfig != old.Spec.HarborServerConfig {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("harborServerConfig"), hp.Spec.HarborServerConfig, "field cannot be changed after initial creation"))
}
}

if len(allErrs) == 0 {
return nil
}

return apierrors.NewInvalid(schema.GroupKind{Group: GroupVersion.Group, Kind: "HarborProject"}, hp.Name, allErrs)
}
Loading

0 comments on commit ab08f3d

Please sign in to comment.