diff --git a/controllers/job/init/cmd/preset/main.go b/controllers/job/init/cmd/preset/main.go index ef94948674a..f5a1766614e 100644 --- a/controllers/job/init/cmd/preset/main.go +++ b/controllers/job/init/cmd/preset/main.go @@ -19,9 +19,10 @@ import ( "errors" "os" + "gorm.io/gorm" + "github.com/labring/sealos/controllers/job/init/internal/util/controller" "github.com/labring/sealos/controllers/job/init/internal/util/database" - utilserror "github.com/labring/sealos/controllers/job/init/internal/util/errors" "github.com/labring/sealos/controllers/pkg/utils/logger" ) @@ -34,8 +35,8 @@ func main() { } logger.Info("preset admin user in kubernetes successfully") - if err := database.PresetAdminUser(ctx); err != nil { - if errors.Is(err, utilserror.ErrAdminExists) { + if err := database.PresetAdminUser(); err != nil { + if errors.Is(err, gorm.ErrDuplicatedKey) { logger.Info("admin user already exists in database") } else { logger.Error(err, "preset admin user in database failed") diff --git a/controllers/job/init/deploy/manifests/deploy.yaml b/controllers/job/init/deploy/manifests/deploy.yaml.tmpl similarity index 59% rename from controllers/job/init/deploy/manifests/deploy.yaml rename to controllers/job/init/deploy/manifests/deploy.yaml.tmpl index 5191e819ab7..c47e4e23e4f 100644 --- a/controllers/job/init/deploy/manifests/deploy.yaml +++ b/controllers/job/init/deploy/manifests/deploy.yaml.tmpl @@ -12,35 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -apiVersion: v1 -kind: ServiceAccount -metadata: - name: sealos-job-init-sa - namespace: sealos ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: sealos-job-init-user-editor-role-binding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: user-editor-role -subjects: - - kind: ServiceAccount - name: sealos-job-init-sa - namespace: sealos ---- apiVersion: batch/v1 kind: Job metadata: name: init-job - namespace: sealos + namespace: account-system spec: ttlSecondsAfterFinished: 86400 template: spec: - serviceAccountName: sealos-job-init-sa + serviceAccountName: account-controller-manager securityContext: runAsNonRoot: true containers: @@ -48,16 +29,11 @@ spec: image: ghcr.io/labring/sealos-job-init-controller:latest # get env from desktop-frontend-secret env: - - name: MONGO_URI - valueFrom: - secretKeyRef: - name: desktop-frontend-secret - key: mongodb_uri - name: PASSWORD_SALT - valueFrom: - secretKeyRef: - name: desktop-frontend-secret - key: password_salt + value: {{ .PASSWORD_SALT }} + envFrom: + - configMapRef: + name: account-manager-env securityContext: allowPrivilegeEscalation: false capabilities: diff --git a/controllers/job/init/internal/util/common/uuid.go b/controllers/job/init/internal/util/common/uuid.go index e29d149bebe..70161ca75bd 100644 --- a/controllers/job/init/internal/util/common/uuid.go +++ b/controllers/job/init/internal/util/common/uuid.go @@ -16,11 +16,11 @@ package common import "github.com/google/uuid" -var adminUID string +var adminUID uuid.UUID -func AdminUID() string { - if adminUID == "" { - adminUID = uuid.New().String() +func AdminUID() uuid.UUID { + if adminUID == uuid.Nil { + adminUID = uuid.New() } return adminUID } diff --git a/controllers/job/init/internal/util/controller/user.go b/controllers/job/init/internal/util/controller/user.go index 8f95409d676..a3cd1691cf6 100644 --- a/controllers/job/init/internal/util/controller/user.go +++ b/controllers/job/init/internal/util/controller/user.go @@ -57,9 +57,9 @@ func newAdminUser(ctx context.Context, c client.Client) (*userv1.User, error) { return nil, err } if u.Labels == nil { - u.SetLabels(map[string]string{"uid": common.AdminUID(), "updateTime": "T2301-01T00-00-00"}) + u.SetLabels(map[string]string{"uid": common.AdminUID().String(), "updateTime": "T2301-01T00-00-00"}) } else if u.Labels["uid"] == "" { - u.Labels["uid"] = common.AdminUID() + u.Labels["uid"] = common.AdminUID().String() u.Labels["updateTime"] = "T2301-01T00-00-00" } return u, nil diff --git a/controllers/job/init/internal/util/database/database.go b/controllers/job/init/internal/util/database/database.go deleted file mode 100644 index d1965550110..00000000000 --- a/controllers/job/init/internal/util/database/database.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright © 2023 sealos. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package database - -import ( - "context" - "os" - - "go.mongodb.org/mongo-driver/mongo" - mongoOptions "go.mongodb.org/mongo-driver/mongo/options" - "go.mongodb.org/mongo-driver/x/mongo/driver/connstring" -) - -var ( - mongoUserDatabase string - mongoUserCollection string - mongoURI string -) - -func init() { - mongoURI = os.Getenv("MONGO_URI") - mongoUserCollection = os.Getenv("MONGO_USER_COL") - if mongoUserCollection == "" { - mongoUserCollection = "user" - } - cs, _ := connstring.ParseAndValidate(mongoURI) - if cs.Database == "" { - mongoUserDatabase = "sealos-auth" - } else { - mongoUserDatabase = cs.Database - } -} - -func InitMongoDB(ctx context.Context) (*mongo.Client, error) { - client, err := mongo.Connect(ctx, mongoOptions.Client().ApplyURI(mongoURI)) - if err != nil { - return nil, err - } - if err := client.Ping(ctx, nil); err != nil { - return nil, err - } - return client, nil -} diff --git a/controllers/job/init/internal/util/database/types.go b/controllers/job/init/internal/util/database/types.go index d775a23fe9a..4e86a54a502 100644 --- a/controllers/job/init/internal/util/database/types.go +++ b/controllers/job/init/internal/util/database/types.go @@ -15,41 +15,20 @@ package database import ( - "context" - "errors" - - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" + "github.com/labring/sealos/controllers/pkg/utils/env" ) -// User struct in mongoDB. -type User struct { - UID string `bson:"uid" json:"uid"` - Name string `bson:"name" json:"name"` - PasswordUser string `bson:"password_user" json:"password_user"` - Password string `bson:"password" json:"password"` - CreatedTime string `bson:"created_time" json:"created_time"` - K8sUsers []K8sUser `bson:"k8s_users" json:"k8s_users"` -} - -type K8sUser struct { - Name string `bson:"name" json:"name"` -} - const ( DefaultAdminUserName = "admin" DefaultAdminPassword = "sealos2023" ) -func (u *User) Exist(ctx context.Context, collection *mongo.Collection) (bool, error) { - filter := &bson.M{"password_user": u.PasswordUser} - user := &User{} - err := collection.FindOne(ctx, filter).Decode(user) - if err != nil { - if errors.Is(err, mongo.ErrNoDocuments) { - return false, nil - } - return false, err - } - return true, nil -} +const ( + EnvAdminUserName = "ADMIN_USER_NAME" + EnvAdminPassword = "ADMIN_PASSWORD" +) + +var ( + adminPassword = hashPassword(env.GetEnvWithDefault(EnvAdminPassword, DefaultAdminPassword)) + adminUserName = env.GetEnvWithDefault(EnvAdminUserName, DefaultAdminUserName) +) diff --git a/controllers/job/init/internal/util/database/user.go b/controllers/job/init/internal/util/database/user.go index e8e3d2a647d..edd673b6017 100644 --- a/controllers/job/init/internal/util/database/user.go +++ b/controllers/job/init/internal/util/database/user.go @@ -15,75 +15,49 @@ package database import ( - "context" "fmt" - "time" + "os" "github.com/labring/sealos/controllers/job/init/internal/util/common" - "github.com/labring/sealos/controllers/job/init/internal/util/controller" - "github.com/labring/sealos/controllers/job/init/internal/util/errors" + + "github.com/labring/sealos/controllers/pkg/database" "github.com/labring/sealos/controllers/pkg/utils/logger" + gonanoid "github.com/matoous/go-nanoid/v2" + + "github.com/labring/sealos/controllers/pkg/database/cockroach" + "github.com/labring/sealos/controllers/pkg/types" ) -func PresetAdminUser(ctx context.Context) error { - //init mongodb database - client, err := InitMongoDB(ctx) +func PresetAdminUser() error { + var ck cockroach.Cockroach + v2Account, err := cockroach.NewCockRoach(os.Getenv(database.GlobalCockroachURI), os.Getenv(database.LocalCockroachURI)) if err != nil { - return err + return fmt.Errorf("failed to connect to cockroach: %v", err) } - defer func() { - if client == nil { - logger.Error(fmt.Errorf("mongodb client is nil"), "disconnect mongodb client failed") - return - } - err := client.Disconnect(ctx) + err := v2Account.Close() if err != nil { - logger.Error(err, "disconnect mongodb client failed") - return + logger.Warn("failed to close cockroach connection: %v", err) } }() - - collection := client.Database(mongoUserDatabase).Collection(mongoUserCollection) - - // create admin user - user, err := newAdminUser() - if err != nil { - return err - } - - // check if the user already exists - exist, err := user.Exist(ctx, collection) + userNanoID, err := gonanoid.New(10) if err != nil { - return err - } - if exist { - return errors.ErrAdminExists + return fmt.Errorf("failed to generate nano id: %v", err) } - - // insert root user - if _, err := collection.InsertOne(ctx, user); err != nil { - return err + if err = ck.CreateUser(&types.OauthProvider{ + UserUID: common.AdminUID(), + ProviderType: types.OauthProviderTypePassword, + ProviderID: adminPassword, + }, &types.RegionUserCr{ + CrName: adminUserName, + UserUID: common.AdminUID(), + }, &types.User{ + UID: common.AdminUID(), + ID: userNanoID, + Name: adminUserName, + Nickname: userNanoID, + }); err != nil { + return fmt.Errorf("failed to create user: %v", err) } return nil } - -func newAdminUser() (*User, error) { - return newUser(common.AdminUID(), DefaultAdminUserName, DefaultAdminUserName, hashPassword(DefaultAdminPassword), controller.DefaultAdminUserName), nil -} - -func newUser(uid, name, passwordUser, hashedPassword, k8sUser string) *User { - return &User{ - UID: uid, - Name: name, - PasswordUser: passwordUser, - Password: hashedPassword, - // to iso string - CreatedTime: time.Now().Format(time.RFC3339), - K8sUsers: []K8sUser{ - { - Name: k8sUser, - }, - }, - } -} diff --git a/controllers/job/init/internal/util/errors/errors.go b/controllers/job/init/internal/util/errors/errors.go index e37f3102da3..511878157e9 100644 --- a/controllers/job/init/internal/util/errors/errors.go +++ b/controllers/job/init/internal/util/errors/errors.go @@ -13,7 +13,3 @@ // limitations under the License. package errors - -import "fmt" - -var ErrAdminExists = fmt.Errorf("admin user already exists") diff --git a/controllers/pkg/database/cockroach/accountv2.go b/controllers/pkg/database/cockroach/accountv2.go index 191bcdf8b5d..b74052a4105 100644 --- a/controllers/pkg/database/cockroach/accountv2.go +++ b/controllers/pkg/database/cockroach/accountv2.go @@ -51,6 +51,21 @@ const ( EnvBaseBalance = "BASE_BALANCE" ) +func (g *Cockroach) CreateUser(oAuth *types.OauthProvider, regionUserCr *types.RegionUserCr, user *types.User) error { + return g.DB.Transaction(func(tx *gorm.DB) error { + if err := tx.FirstOrCreate(user).Error; err != nil { + return fmt.Errorf("failed to create user: %w", err) + } + if err := tx.FirstOrCreate(oAuth).Error; err != nil { + return fmt.Errorf("failed to create user oauth provider: %w", err) + } + if err := tx.FirstOrCreate(®ionUserCr).Error; err != nil { + return fmt.Errorf("failed to create user region cr: %w", err) + } + return nil + }) +} + func (g *Cockroach) GetUserCr(ops *types.UserQueryOpts) (*types.RegionUserCr, error) { if err := checkOps(ops); err != nil { return nil, err diff --git a/controllers/pkg/database/interface.go b/controllers/pkg/database/interface.go index 96429813500..872b99c895c 100644 --- a/controllers/pkg/database/interface.go +++ b/controllers/pkg/database/interface.go @@ -81,6 +81,7 @@ type Traffic interface { type AccountV2 interface { Close() error GetUserCr(user *types.UserQueryOpts) (*types.RegionUserCr, error) + CreateUser(oAuth *types.OauthProvider, regionUserCr *types.RegionUserCr, user *types.User) error GetAccount(user *types.UserQueryOpts) (*types.Account, error) GetUserOauthProvider(ops *types.UserQueryOpts) (*types.OauthProvider, error) AddBalance(user *types.UserQueryOpts, balance int64) error diff --git a/controllers/pkg/types/User.go b/controllers/pkg/types/User.go deleted file mode 100644 index 031c97f3d33..00000000000 --- a/controllers/pkg/types/User.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright © 2023 sealos. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package types diff --git a/controllers/pkg/types/global.go b/controllers/pkg/types/global.go index 3d8f51f8f00..fbb0db37f1e 100644 --- a/controllers/pkg/types/global.go +++ b/controllers/pkg/types/global.go @@ -76,8 +76,8 @@ type User struct { UID uuid.UUID `gorm:"type:uuid;default:gen_random_uuid();primary_key"` CreateAt time.Time `gorm:"type:timestamp(3) with time zone;default:current_timestamp();not null"` UpdateAt time.Time `gorm:"type:timestamp(3) with time zone;default:current_timestamp();not null"` - AvatarURI string `gorm:"column:avatarUri;type:text;not null"` - Nickname string `gorm:"type:text;not null"` + AvatarURI string `gorm:"column:avatarUri;type:text"` + Nickname string `gorm:"type:text"` ID string `gorm:"type:text;not null;unique"` Name string `gorm:"type:text;not null"` }