mirror of
https://github.com/paralus/paralus.git
synced 2026-05-08 17:36:56 +00:00
Merge pull request #56 from RafaySystems/initialization
Initialization script
This commit is contained in:
@@ -3,6 +3,7 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/internal/dao"
|
||||
@@ -138,6 +139,14 @@ func (s *roleService) Create(ctx context.Context, role *rolev3.Role) (*rolev3.Ro
|
||||
return nil, fmt.Errorf("role '%v' already exists", role.GetMetadata().GetName())
|
||||
}
|
||||
|
||||
scope := role.GetSpec().GetScope()
|
||||
// since this is purely additional metadata at this point, we
|
||||
// can kinda treat it as optional, and so we are allowing empty
|
||||
// TODO: check if "" is valid
|
||||
if !contains([]string{"system", "organization", "project", ""}, strings.ToLower(scope)) {
|
||||
return nil, fmt.Errorf("unknown scope '%v'", scope)
|
||||
}
|
||||
|
||||
// convert v3 spec to internal models
|
||||
rle := models.Role{
|
||||
Name: role.GetMetadata().GetName(),
|
||||
@@ -148,7 +157,7 @@ func (s *roleService) Create(ctx context.Context, role *rolev3.Role) (*rolev3.Ro
|
||||
OrganizationId: organizationId,
|
||||
PartnerId: partnerId,
|
||||
IsGlobal: role.GetSpec().GetIsGlobal(),
|
||||
Scope: role.GetSpec().GetScope(), // TODO: validate scope is SYSTEM/ORG/PROJECT?
|
||||
Scope: strings.ToLower(scope),
|
||||
}
|
||||
entity, err := s.dao.Create(ctx, &rle)
|
||||
if err != nil {
|
||||
|
||||
@@ -71,7 +71,7 @@ func TestCreateRole(t *testing.T) {
|
||||
|
||||
role := &rolev3.Role{
|
||||
Metadata: &v3.Metadata{Partner: "partner-" + puuid, Organization: "org-" + ouuid, Name: "role-" + ruuid},
|
||||
Spec: &rolev3.RoleSpec{IsGlobal: true, Scope: "cluster"},
|
||||
Spec: &rolev3.RoleSpec{IsGlobal: true, Scope: "system"},
|
||||
}
|
||||
role, err := rs.Create(context.Background(), role)
|
||||
if err != nil {
|
||||
@@ -107,7 +107,7 @@ func TestCreateRoleWithPermissions(t *testing.T) {
|
||||
|
||||
role := &rolev3.Role{
|
||||
Metadata: &v3.Metadata{Partner: "partner-" + puuid, Organization: "org-" + ouuid, Name: "role-" + ruuid},
|
||||
Spec: &rolev3.RoleSpec{IsGlobal: true, Scope: "cluster", Rolepermissions: []string{"ops_star.all"}},
|
||||
Spec: &rolev3.RoleSpec{IsGlobal: true, Scope: "system", Rolepermissions: []string{"ops_star.all"}},
|
||||
}
|
||||
role, err := rs.Create(context.Background(), role)
|
||||
if err != nil {
|
||||
@@ -141,7 +141,7 @@ func TestCreateRoleDuplicate(t *testing.T) {
|
||||
|
||||
role := &rolev3.Role{
|
||||
Metadata: &v3.Metadata{Partner: "partner-" + puuid, Organization: "org-" + ouuid, Name: "role-" + ruuid},
|
||||
Spec: &rolev3.RoleSpec{IsGlobal: true, Scope: "cluster"},
|
||||
Spec: &rolev3.RoleSpec{IsGlobal: true, Scope: "system"},
|
||||
}
|
||||
_, err := rs.Create(context.Background(), role)
|
||||
if err == nil {
|
||||
@@ -168,7 +168,7 @@ func TestUpdateRole(t *testing.T) {
|
||||
mock.ExpectQuery(`SELECT "resourcerole"."id", "resourcerole"."name", .*FROM "authsrv_resourcerole" AS "resourcerole" WHERE .organization_id = '` + ouuid + `'. AND .partner_id = '` + puuid + `'. AND .name = 'role-` + ruuid + `'.`).
|
||||
WithArgs().WillReturnRows(sqlmock.NewRows([]string{"id", "name", "organization_id", "partner_id"}).AddRow(ruuid, "role-"+ruuid, ouuid, puuid))
|
||||
|
||||
mock.ExpectExec(`UPDATE "authsrv_resourcerole" AS "resourcerole" SET "name" = 'role-` + ruuid + `', .*"organization_id" = '` + ouuid + `', "partner_id" = '` + puuid + `', "is_global" = TRUE, "scope" = 'cluster' WHERE .id = '` + ruuid + `'.`).
|
||||
mock.ExpectExec(`UPDATE "authsrv_resourcerole" AS "resourcerole" SET "name" = 'role-` + ruuid + `', .*"organization_id" = '` + ouuid + `', "partner_id" = '` + puuid + `', "is_global" = TRUE, "scope" = 'system' WHERE .id = '` + ruuid + `'.`).
|
||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
mock.ExpectExec(`DELETE FROM "authsrv_resourcerolepermission" AS "resourcerolepermission" WHERE ."resource_role_id" = '` + ruuid + `'.`).
|
||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
@@ -180,7 +180,7 @@ func TestUpdateRole(t *testing.T) {
|
||||
|
||||
role := &rolev3.Role{
|
||||
Metadata: &v3.Metadata{Partner: "partner-" + puuid, Organization: "org-" + ouuid, Name: "role-" + ruuid},
|
||||
Spec: &rolev3.RoleSpec{IsGlobal: true, Scope: "cluster", Rolepermissions: []string{"ops_star.all"}},
|
||||
Spec: &rolev3.RoleSpec{IsGlobal: true, Scope: "system", Rolepermissions: []string{"ops_star.all"}},
|
||||
}
|
||||
role, err := rs.Update(context.Background(), role)
|
||||
if err != nil {
|
||||
|
||||
@@ -11,3 +11,12 @@ func unique(items []string) []string {
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func contains(s []string, str string) bool {
|
||||
for _, v := range s {
|
||||
if v == str {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
212
scripts/initialize/main.go
Normal file
212
scripts/initialize/main.go
Normal file
@@ -0,0 +1,212 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/RafaySystems/rcloud-base/internal/models"
|
||||
providers "github.com/RafaySystems/rcloud-base/internal/persistence/provider/kratos"
|
||||
"github.com/RafaySystems/rcloud-base/internal/persistence/provider/pg"
|
||||
"github.com/RafaySystems/rcloud-base/pkg/common"
|
||||
"github.com/RafaySystems/rcloud-base/pkg/enforcer"
|
||||
"github.com/RafaySystems/rcloud-base/pkg/service"
|
||||
commonv3 "github.com/RafaySystems/rcloud-base/proto/types/commonpb/v3"
|
||||
rolev3 "github.com/RafaySystems/rcloud-base/proto/types/rolepb/v3"
|
||||
systemv3 "github.com/RafaySystems/rcloud-base/proto/types/systempb/v3"
|
||||
userv3 "github.com/RafaySystems/rcloud-base/proto/types/userpb/v3"
|
||||
kclient "github.com/ory/kratos-client-go"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/dialect/pgdialect"
|
||||
"github.com/uptrace/bun/driver/pgdriver"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// This script will be run in an init container after we crate all the
|
||||
// permissions. It will take care of the initialization, namely:
|
||||
// - creating partner
|
||||
// - creating org
|
||||
// - creating roles in org
|
||||
//
|
||||
// We make use of service instead of just insserting to db as that way
|
||||
// all the dependent items will be taken care of automatically.
|
||||
|
||||
// Inorder to reset everything, we can do
|
||||
// truncate table authsrv_partner cascade;
|
||||
// truncate table casbin_rule;
|
||||
|
||||
const (
|
||||
dbAddrEnv = "DB_ADDR"
|
||||
dbNameEnv = "DB_NAME"
|
||||
dbUserEnv = "DB_USER"
|
||||
dbPasswordEnv = "DB_PASSWORD"
|
||||
kratosSchemeEnv = "KRATOS_SCHEME"
|
||||
kratosAddrEnv = "KRATOS_ADDR"
|
||||
)
|
||||
|
||||
func addResourcePermissions(dao pg.EntityDAO, basePath string) error {
|
||||
var items []models.ResourcePermission
|
||||
|
||||
files, err := ioutil.ReadDir(basePath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for _, file := range files {
|
||||
if !file.IsDir() { // probably not, but just in case
|
||||
content, err := ioutil.ReadFile(path.Join(basePath, file.Name()))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// It has ResourceRefId, but that does not seem to be used in the old implementation
|
||||
// Also, why do we need two items?
|
||||
var data models.ResourcePermission
|
||||
err = json.Unmarshal(content, &data)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
items = append(items, data)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Adding", len(items), "resource permissions")
|
||||
_, err = dao.Create(context.Background(), &items)
|
||||
return err
|
||||
}
|
||||
|
||||
func main() {
|
||||
partner := flag.String("partner", "", "Name of partner")
|
||||
partnerDesc := flag.String("partner-desc", "", "Description of partner")
|
||||
partnerHost := flag.String("partner-host", "", "Host of partner")
|
||||
|
||||
org := flag.String("org", "", "Name of org")
|
||||
orgDesc := flag.String("org-desc", "", "Description of org")
|
||||
|
||||
oae := flag.String("admin-email", "", "Email of org admin")
|
||||
oafn := flag.String("admin-first-name", "", "First name of org admin")
|
||||
oaln := flag.String("admin-last-name", "", "Last name of org admin")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if *partner == "" || *org == "" || *oae == "" || *oafn == "" || *oaln == "" || *partnerHost == "" {
|
||||
fmt.Println("Usage: initialize")
|
||||
flag.PrintDefaults()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
viper.SetDefault(dbAddrEnv, "localhost:5432")
|
||||
viper.SetDefault(dbNameEnv, "admindb")
|
||||
viper.SetDefault(dbUserEnv, "admindbuser")
|
||||
viper.SetDefault(dbPasswordEnv, "admindbpassword")
|
||||
viper.SetDefault(kratosSchemeEnv, "http")
|
||||
viper.SetDefault(kratosAddrEnv, "localhost:4433")
|
||||
|
||||
viper.BindEnv(dbAddrEnv)
|
||||
viper.BindEnv(dbNameEnv)
|
||||
viper.BindEnv(dbUserEnv)
|
||||
viper.BindEnv(dbPasswordEnv)
|
||||
viper.BindEnv(kratosSchemeEnv)
|
||||
viper.BindEnv(kratosAddrEnv)
|
||||
|
||||
dbAddr := viper.GetString(dbAddrEnv)
|
||||
dbName := viper.GetString(dbNameEnv)
|
||||
dbUser := viper.GetString(dbUserEnv)
|
||||
dbPassword := viper.GetString(dbPasswordEnv)
|
||||
kratosScheme := viper.GetString(kratosSchemeEnv)
|
||||
kratosAddr := viper.GetString(kratosAddrEnv)
|
||||
|
||||
content, err := ioutil.ReadFile(path.Join("scripts", "initialize", "roles.json"))
|
||||
if err != nil {
|
||||
log.Fatal("unable to read file: ", err)
|
||||
}
|
||||
|
||||
var data map[string]map[string][]string
|
||||
err = json.Unmarshal(content, &data)
|
||||
if err != nil {
|
||||
log.Fatal("unable to parse data file", err)
|
||||
}
|
||||
|
||||
dsn := "postgres://" + dbUser + ":" + dbPassword + "@" + dbAddr + "/" + dbName + "?sslmode=disable"
|
||||
sqldb := sql.OpenDB(pgdriver.NewConnector(pgdriver.WithDSN(dsn)))
|
||||
db := bun.NewDB(sqldb, pgdialect.New())
|
||||
dao := pg.NewEntityDAO(db)
|
||||
|
||||
kratosConfig := kclient.NewConfiguration()
|
||||
kratosUrl := kratosScheme + "://" + kratosAddr
|
||||
kratosConfig.Servers[0].URL = kratosUrl
|
||||
kc := kclient.NewAPIClient(kratosConfig)
|
||||
|
||||
// authz services
|
||||
gormDb, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
||||
if err != nil {
|
||||
log.Fatal("unable to create db connection", "error", err)
|
||||
}
|
||||
enforcer, err := enforcer.NewCasbinEnforcer(gormDb).Init()
|
||||
if err != nil {
|
||||
log.Fatal("unable to init enforcer", "error", err)
|
||||
}
|
||||
as := service.NewAuthzService(gormDb, enforcer)
|
||||
|
||||
ps := service.NewPartnerService(db)
|
||||
os := service.NewOrganizationService(db)
|
||||
rs := service.NewRoleService(db, as)
|
||||
us := service.NewUserService(providers.NewKratosAuthProvider(kc), db, as, nil, common.CliConfigDownloadData{})
|
||||
|
||||
err = dao.DeleteAll(context.Background(), &models.ResourcePermission{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = addResourcePermissions(dao, path.Join("scripts", "initialize", "permissions"))
|
||||
if err != nil {
|
||||
fmt.Println("Run from base directory")
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Create partner
|
||||
_, err = ps.Create(context.Background(), &systemv3.Partner{
|
||||
Metadata: &commonv3.Metadata{Name: *partner, Description: *partnerDesc},
|
||||
Spec: &systemv3.PartnerSpec{Host: *partnerHost},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal("unable to create partner", err)
|
||||
}
|
||||
_, err = os.Create(context.Background(), &systemv3.Organization{
|
||||
Metadata: &commonv3.Metadata{Name: *org, Partner: *partner, Description: *orgDesc},
|
||||
Spec: &systemv3.OrganizationSpec{Active: true},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal("unable to create organization", err)
|
||||
}
|
||||
|
||||
for scope := range data {
|
||||
for name := range data[scope] {
|
||||
perms := data[scope][name]
|
||||
fmt.Println(scope, name, len(perms))
|
||||
_, err := rs.Create(context.Background(), &rolev3.Role{
|
||||
Metadata: &commonv3.Metadata{Name: name, Partner: *partner, Organization: *org, Description: "..."},
|
||||
Spec: &rolev3.RoleSpec{IsGlobal: true, Scope: scope, Rolepermissions: perms},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal("unable to create rolepermission", scope, name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// should we directly interact with kratos and create a user with a password?
|
||||
_, err = us.Create(context.Background(), &userv3.User{
|
||||
Metadata: &commonv3.Metadata{Name: *oae, Partner: *partner, Organization: *org, Description: "..."},
|
||||
Spec: &userv3.UserSpec{FirstName: *oafn, LastName: *oaln, ProjectNamespaceRoles: []*userv3.ProjectNamespaceRole{{Role: "ADMIN"}}},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("err:", err)
|
||||
log.Fatal("unable to bind user to role", err)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user