mirror of
https://github.com/argoproj/argo-cd
synced 2026-04-21 17:07:16 +00:00
* Generate swagger files * Add basic Swagger definitions * Add reposerver swagger file * Consolidate swagger files * Move swagger files to swagger-ui directory instead * Put swagger files in swagger-ui * Fix order of operations * Move back to swagger directory * Serve API server swagger files raw for now * Serve reposerver swagger files from API server * Move back to subdirectories, thanks @alexmt * Fix comment on application Rollback * Update two more comments * Fix comment in session.proto * Update generated code * Update generated swagger docs * Fix comment for delete actions in cluster and repository swagger * Set expected collisions and invoke mixins * Update generated code * Create swagger mixins from codegen * Move swagger.json location, thanks @jazminGonzalez-Rivero * Add ref cleanup for swagger combined * Make fewer temp files when generating swagger * Delete intermediate swagger files * Serve new file at /swagger.json * Set up UI server * Update package lock * Commit generated swagger.json files * Add install commands for swagger * Use ReDoc server instead of Swagger UI server * Update lockfile * Make URL paths more consistent * Update package lock * Separate out handlers for Swagger UI, JSON * Rm unnecessary CORS headers ...since we're serving from the app server * Simplify serving * Further simplify serving code * Update package lock * Factor out swagger serving into util * Add test for Swagger server * Use ServeSwaggerUI method to run tests * Update package lock * Don't generate swagger for reposerver * Reset to master Gopkg.lock and server/server.go * Merge in prev change to server/server.go * Redo changes to Gopkg.lock * Fix number of conflicts * Update generated swagger.json for server * Fix issue with project feature error
149 lines
5.4 KiB
Go
149 lines
5.4 KiB
Go
package project
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"github.com/argoproj/argo-cd/common"
|
|
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
|
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
|
"github.com/argoproj/argo-cd/util"
|
|
"github.com/argoproj/argo-cd/util/argo"
|
|
"github.com/argoproj/argo-cd/util/grpc"
|
|
"github.com/argoproj/argo-cd/util/rbac"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
)
|
|
|
|
// Server provides a Project service
|
|
type Server struct {
|
|
ns string
|
|
enf *rbac.Enforcer
|
|
appclientset appclientset.Interface
|
|
projectLock *util.KeyLock
|
|
}
|
|
|
|
// NewServer returns a new instance of the Project service
|
|
func NewServer(ns string, appclientset appclientset.Interface, enf *rbac.Enforcer, projectLock *util.KeyLock) *Server {
|
|
return &Server{enf: enf, appclientset: appclientset, ns: ns, projectLock: projectLock}
|
|
}
|
|
|
|
// Create a new project.
|
|
func (s *Server) Create(ctx context.Context, q *ProjectCreateRequest) (*v1alpha1.AppProject, error) {
|
|
if !s.enf.EnforceClaims(ctx.Value("claims"), "projects", "create", q.Project.Name) {
|
|
return nil, grpc.ErrPermissionDenied
|
|
}
|
|
if q.Project.Name == common.DefaultAppProjectName {
|
|
return nil, status.Errorf(codes.InvalidArgument, "name '%s' is reserved and cannot be used as a project name", q.Project.Name)
|
|
}
|
|
return s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Create(q.Project)
|
|
}
|
|
|
|
// List returns list of projects
|
|
func (s *Server) List(ctx context.Context, q *ProjectQuery) (*v1alpha1.AppProjectList, error) {
|
|
list, err := s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).List(metav1.ListOptions{})
|
|
list.Items = append(list.Items, v1alpha1.GetDefaultProject(s.ns))
|
|
if list != nil {
|
|
newItems := make([]v1alpha1.AppProject, 0)
|
|
for i := range list.Items {
|
|
project := list.Items[i]
|
|
if s.enf.EnforceClaims(ctx.Value("claims"), "projects", "get", project.Name) {
|
|
newItems = append(newItems, project)
|
|
}
|
|
}
|
|
list.Items = newItems
|
|
}
|
|
return list, err
|
|
}
|
|
|
|
// Get returns a project by name
|
|
func (s *Server) Get(ctx context.Context, q *ProjectQuery) (*v1alpha1.AppProject, error) {
|
|
if !s.enf.EnforceClaims(ctx.Value("claims"), "projects", "get", q.Name) {
|
|
return nil, grpc.ErrPermissionDenied
|
|
}
|
|
return s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Get(q.Name, metav1.GetOptions{})
|
|
}
|
|
|
|
func getRemovedDestination(oldProj, newProj *v1alpha1.AppProject) map[string]v1alpha1.ApplicationDestination {
|
|
oldDest := make(map[string]v1alpha1.ApplicationDestination)
|
|
newDest := make(map[string]v1alpha1.ApplicationDestination)
|
|
for i := range oldProj.Spec.Destinations {
|
|
dest := oldProj.Spec.Destinations[i]
|
|
oldDest[fmt.Sprintf("%s/%s", dest.Server, dest.Namespace)] = dest
|
|
}
|
|
for i := range newProj.Spec.Destinations {
|
|
dest := newProj.Spec.Destinations[i]
|
|
newDest[fmt.Sprintf("%s/%s", dest.Server, dest.Namespace)] = dest
|
|
}
|
|
|
|
removed := make(map[string]v1alpha1.ApplicationDestination, 0)
|
|
for key, dest := range oldDest {
|
|
if _, ok := newDest[key]; !ok {
|
|
removed[key] = dest
|
|
}
|
|
}
|
|
return removed
|
|
}
|
|
|
|
// Update updates a project
|
|
func (s *Server) Update(ctx context.Context, q *ProjectUpdateRequest) (*v1alpha1.AppProject, error) {
|
|
if q.Project.Name == common.DefaultAppProjectName {
|
|
return nil, grpc.ErrPermissionDenied
|
|
}
|
|
if !s.enf.EnforceClaims(ctx.Value("claims"), "projects", "update", q.Project.Name) {
|
|
return nil, grpc.ErrPermissionDenied
|
|
}
|
|
s.projectLock.Lock(q.Project.Name)
|
|
defer s.projectLock.Unlock(q.Project.Name)
|
|
|
|
oldProj, err := s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Get(q.Project.Name, metav1.GetOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
removed := getRemovedDestination(oldProj, q.Project)
|
|
|
|
appsList, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).List(metav1.ListOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
removedUsed := make([]v1alpha1.ApplicationDestination, 0)
|
|
for _, a := range argo.FilterByProjects(appsList.Items, []string{q.Project.Name}) {
|
|
if dest, ok := removed[fmt.Sprintf("%s/%s", a.Spec.Destination.Server, a.Spec.Destination.Namespace)]; ok {
|
|
removedUsed = append(removedUsed, dest)
|
|
}
|
|
}
|
|
if len(removedUsed) > 0 {
|
|
formattedRemovedUsedList := make([]string, len(removedUsed))
|
|
for i := 0; i < len(removedUsed); i++ {
|
|
formattedRemovedUsedList[i] = fmt.Sprintf("server: %s, namespace: %s", removedUsed[i].Server, removedUsed[i].Namespace)
|
|
}
|
|
return nil, status.Errorf(
|
|
codes.InvalidArgument, "following destinations are used by one or more application and cannot be removed: %s", strings.Join(formattedRemovedUsedList, ";"))
|
|
}
|
|
|
|
return s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Update(q.Project)
|
|
}
|
|
|
|
// Delete deletes a project
|
|
func (s *Server) Delete(ctx context.Context, q *ProjectQuery) (*EmptyResponse, error) {
|
|
if !s.enf.EnforceClaims(ctx.Value("claims"), "projects", "delete", q.Name) {
|
|
return nil, grpc.ErrPermissionDenied
|
|
}
|
|
|
|
s.projectLock.Lock(q.Name)
|
|
defer s.projectLock.Unlock(q.Name)
|
|
|
|
appsList, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).List(metav1.ListOptions{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
apps := argo.FilterByProjects(appsList.Items, []string{q.Name})
|
|
if len(apps) > 0 {
|
|
return nil, status.Errorf(codes.InvalidArgument, "project is referenced by %d applications", len(apps))
|
|
}
|
|
return &EmptyResponse{}, s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Delete(q.Name, &metav1.DeleteOptions{})
|
|
}
|