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(api,cli): add CRUD v2 organization and region #6296

Merged
merged 4 commits into from
Sep 22, 2022
Merged
Show file tree
Hide file tree
Changes from 3 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
4 changes: 3 additions & 1 deletion cli/cdsctl/experimental.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ var experimentalCmd = cli.Command{

func experimentalCommands() []*cobra.Command {
return []*cobra.Command{
experimentalRbac(),
experimentalOrganization(),
experimentalRegion(),
experimentalProject(),
experimentalRbac(),
experimentalWorkerModel(),
}
}
Expand Down
99 changes: 99 additions & 0 deletions cli/cdsctl/experimental_organization.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package main

import (
"context"
"github.com/ovh/cds/sdk"
"github.com/spf13/cobra"

"github.com/ovh/cds/cli"
)

var experimentalOrganizationCmd = cli.Command{
Name: "organization",
Aliases: []string{"org", "orga"},
Short: "CDS Experimental organization commands",
}

func experimentalOrganization() *cobra.Command {
return cli.NewCommand(experimentalOrganizationCmd, nil, []*cobra.Command{
cli.NewCommand(organizationAddCmd, organizationAddFunc, nil, withAllCommandModifiers()...),
cli.NewGetCommand(organizationGetCmd, organizationGetFunc, nil, withAllCommandModifiers()...),
cli.NewListCommand(organizationListCmd, organizationListFunc, nil, withAllCommandModifiers()...),
cli.NewDeleteCommand(organizationDeleteCmd, organizationDeleteFunc, nil, withAllCommandModifiers()...),
})
}

var organizationAddCmd = cli.Command{
Name: "add",
Aliases: []string{"create"},
Short: "Create a new organization",
Example: "cdsctl organization add <organization_name>",
Ctx: []cli.Arg{},
Args: []cli.Arg{
{Name: "organizationIdentifier"},
},
}

func organizationAddFunc(v cli.Values) error {
orga := sdk.Organization{Name: v.GetString("organizationIdentifier")}
if err := client.OrganizationAdd(context.Background(), orga); err != nil {
return err
}
return nil
}

var organizationGetCmd = cli.Command{
Name: "show",
Aliases: []string{"get"},
Short: "Get an organization by its identifier",
Example: "cdsctl organization show <organization_identifier>",
Ctx: []cli.Arg{},
Args: []cli.Arg{
{Name: "organizationIdentifier"},
},
}

func organizationGetFunc(v cli.Values) (interface{}, error) {
orga, err := client.OrganizationGet(context.Background(), v.GetString("organizationIdentifier"))
if err != nil {
return orga, err
}
return orga, nil
}

var organizationListCmd = cli.Command{
Name: "list",
Aliases: []string{"ls"},
Short: "List all organizations",
Example: "cdsctl organization list",
Ctx: []cli.Arg{},
}

func organizationListFunc(_ cli.Values) (cli.ListResult, error) {
orgas, err := client.OrganizationList(context.Background())
if err != nil {
return nil, err
}
return cli.AsListResult(orgas), nil
}

var organizationDeleteCmd = cli.Command{
Name: "delete",
Aliases: []string{"remove", "rm"},
Short: "Remove organization",
Example: "cdsctl organization delete",
Ctx: []cli.Arg{},
Args: []cli.Arg{
{
Name: "organizationIdentifier",
},
},
}

func organizationDeleteFunc(v cli.Values) error {
err := client.OrganizationDelete(context.Background(), v.GetString("organizationIdentifier"))
if v.GetBool("force") && sdk.ErrorIs(err, sdk.ErrNotFound) {
return nil
}
return err
}
99 changes: 99 additions & 0 deletions cli/cdsctl/experimental_region.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package main

import (
"context"
"github.com/ovh/cds/sdk"
"github.com/spf13/cobra"

"github.com/ovh/cds/cli"
)

var experimentalRegionCmd = cli.Command{
Name: "region",
Aliases: []string{"org", "orga"},
Short: "CDS Experimental region commands",
}

func experimentalRegion() *cobra.Command {
return cli.NewCommand(experimentalRegionCmd, nil, []*cobra.Command{
cli.NewCommand(regionAddCmd, regionAddFunc, nil, withAllCommandModifiers()...),
cli.NewGetCommand(regionGetCmd, regionGetFunc, nil, withAllCommandModifiers()...),
cli.NewListCommand(regionListCmd, regionListFunc, nil, withAllCommandModifiers()...),
cli.NewDeleteCommand(regionDeleteCmd, regionDeleteFunc, nil, withAllCommandModifiers()...),
})
}

var regionAddCmd = cli.Command{
Name: "add",
Aliases: []string{"create"},
Short: "Create a new region",
Example: "cdsctl region add <region_name>",
Ctx: []cli.Arg{},
Args: []cli.Arg{
{Name: "regionIdentifier"},
},
}

func regionAddFunc(v cli.Values) error {
reg := sdk.Region{Name: v.GetString("regionIdentifier")}
if err := client.RegionAdd(context.Background(), reg); err != nil {
return err
}
return nil
}

var regionGetCmd = cli.Command{
Name: "show",
Aliases: []string{"get"},
Short: "Get an region by its identifier",
Example: "cdsctl region show <region_identifier>",
Ctx: []cli.Arg{},
Args: []cli.Arg{
{Name: "regionIdentifier"},
},
}

func regionGetFunc(v cli.Values) (interface{}, error) {
reg, err := client.RegionGet(context.Background(), v.GetString("regionIdentifier"))
if err != nil {
return reg, err
}
return reg, nil
}

var regionListCmd = cli.Command{
Name: "list",
Aliases: []string{"ls"},
Short: "List all regions",
Example: "cdsctl region list",
Ctx: []cli.Arg{},
}

func regionListFunc(_ cli.Values) (cli.ListResult, error) {
regions, err := client.RegionList(context.Background())
if err != nil {
return nil, err
}
return cli.AsListResult(regions), nil
}

var regionDeleteCmd = cli.Command{
Name: "delete",
Aliases: []string{"remove", "rm"},
Short: "Remove region",
Example: "cdsctl region delete",
Ctx: []cli.Arg{},
Args: []cli.Arg{
{
Name: "regionIdentifier",
},
},
}

func regionDeleteFunc(v cli.Values) error {
err := client.RegionDelete(context.Background(), v.GetString("regionIdentifier"))
if v.GetBool("force") && sdk.ErrorIs(err, sdk.ErrNotFound) {
return nil
}
return err
}
4 changes: 4 additions & 0 deletions engine/api/api_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,8 +440,12 @@ func (api *API) InitRouter() {

r.Handle("/v2/organization", nil, r.POSTv2(api.postOrganizationHandler), r.GETv2(api.getOrganizationsHandler))
r.Handle("/v2/organization/{organizationIdentifier}", nil, r.GETv2(api.getOrganizationHandler), r.DELETEv2(api.deleteOrganizationHandler))

r.Handle("/v2/rbac/import", nil, r.POSTv2(api.postImportRbacHandler))

r.Handle("/v2/region", nil, r.POSTv2(api.postRegionHandler), r.GETv2(api.getRegionsHandler))
r.Handle("/v2/region/{regionIdentifier}", nil, r.GETv2(api.getRegionHandler), r.DELETEv2(api.deleteRegionHandler))

r.Handle("/v2/repository/analyze", Scope(sdk.AuthConsumerScopeHooks), r.POSTv2(api.postRepositoryAnalysisHandler))
r.Handle("/v2/project/repositories", Scope(sdk.AuthConsumerScopeHooks), r.GETv2(api.getAllRepositoriesHandler))
r.Handle("/v2/project/repositories/{repositoryIdentifier}/hook", Scope(sdk.AuthConsumerScopeHooks), r.GETv2(api.getRepositoryHookHandler))
Expand Down
6 changes: 5 additions & 1 deletion engine/api/rbac/rule_global.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,13 @@ func hasGlobalRole(ctx context.Context, auth *sdk.AuthConsumer, _ cache.Store, d

// PermissionManage return nil if the current AuthConsumer have the ProjectRoleManage on current project KEY
func PermissionManage(ctx context.Context, auth *sdk.AuthConsumer, store cache.Store, db gorp.SqlExecutor, _ map[string]string) error {
return hasGlobalRole(ctx, auth, store, db, sdk.RoleManagePermission)
return hasGlobalRole(ctx, auth, store, db, sdk.GlobalRoleManagePermission)
}

func OrganizationManage(ctx context.Context, auth *sdk.AuthConsumer, store cache.Store, db gorp.SqlExecutor, _ map[string]string) error {
return hasGlobalRole(ctx, auth, store, db, sdk.GlobalRoleManageOrganization)
}

func RegionManage(ctx context.Context, auth *sdk.AuthConsumer, store cache.Store, db gorp.SqlExecutor, _ map[string]string) error {
return hasGlobalRole(ctx, auth, store, db, sdk.GlobalRoleManageRegion)
}
84 changes: 84 additions & 0 deletions engine/api/region/dao_region.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package region

import (
"context"

"github.com/go-gorp/gorp"
"github.com/rockbears/log"

"github.com/ovh/cds/engine/api/database/gorpmapping"
"github.com/ovh/cds/engine/gorpmapper"
"github.com/ovh/cds/sdk"
)

func Insert(ctx context.Context, db gorpmapper.SqlExecutorWithTx, region *sdk.Region) error {
region.ID = sdk.UUID()
dbData := &dbRegion{Region: *region}
if err := gorpmapping.InsertAndSign(ctx, db, dbData); err != nil {
return err
}
*region = dbData.Region
return nil
}

func Delete(db gorpmapper.SqlExecutorWithTx, regionID string) error {
_, err := db.Exec("DELETE FROM region WHERE id = $1", regionID)
return sdk.WrapError(err, "cannot delete region %s", regionID)
}

func getRegion(ctx context.Context, db gorp.SqlExecutor, query gorpmapping.Query) (*sdk.Region, error) {
var dbRegion dbRegion
found, err := gorpmapping.Get(ctx, db, query, &dbRegion)
if err != nil {
return nil, err
}
if !found {
return nil, sdk.WithStack(sdk.ErrNotFound)
}

isValid, err := gorpmapping.CheckSignature(dbRegion, dbRegion.Signature)
if err != nil {
return nil, err
}
if !isValid {
log.Error(ctx, "region %s / %s data corrupted", dbRegion.ID, dbRegion.Name)
return nil, sdk.WithStack(sdk.ErrNotFound)
}
return &dbRegion.Region, nil
}

func getAllRegions(ctx context.Context, db gorp.SqlExecutor, query gorpmapping.Query) ([]sdk.Region, error) {
var res []dbRegion
if err := gorpmapping.GetAll(ctx, db, query, &res); err != nil {
return nil, err
}

regions := make([]sdk.Region, 0, len(res))
for _, r := range res {
isValid, err := gorpmapping.CheckSignature(r, r.Signature)
if err != nil {
return nil, err
}
if !isValid {
log.Error(ctx, "region %d / %s data corrupted", r.ID, r.Name)
continue
}
regions = append(regions, r.Region)
}
return regions, nil
}

func LoadAllRegions(ctx context.Context, db gorp.SqlExecutor) ([]sdk.Region, error) {
query := gorpmapping.NewQuery(`SELECT region.* FROM region`)
return getAllRegions(ctx, db, query)
}

func LoadRegionByName(ctx context.Context, db gorp.SqlExecutor, name string) (*sdk.Region, error) {
query := gorpmapping.NewQuery(`SELECT region.* FROM region WHERE region.name = $1`).Args(name)
return getRegion(ctx, db, query)
}

func LoadRegionByID(ctx context.Context, db gorp.SqlExecutor, ID string) (*sdk.Region, error) {
query := gorpmapping.NewQuery(`SELECT region.* FROM region WHERE region.id = $1`).Args(ID)
return getRegion(ctx, db, query)
}
23 changes: 23 additions & 0 deletions engine/api/region/gorp_model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package region

import (
"github.com/ovh/cds/engine/api/database/gorpmapping"
"github.com/ovh/cds/engine/gorpmapper"
"github.com/ovh/cds/sdk"
)

func init() {
gorpmapping.Register(gorpmapping.New(dbRegion{}, "region", false, "id"))
}

type dbRegion struct {
sdk.Region
gorpmapper.SignedEntity
}

func (o dbRegion) Canonical() gorpmapper.CanonicalForms {
_ = []interface{}{o.ID, o.Name}
return []gorpmapper.CanonicalForm{
"{{.ID}}{{.Name}}",
}
}
Loading