Files
Olares/cli/pkg/terminus/account.go

250 lines
7.0 KiB
Go

package terminus
import (
"context"
"fmt"
"net/mail"
"os"
"path"
"strings"
"time"
"github.com/beclab/Olares/cli/pkg/core/logger"
corev1 "k8s.io/api/core/v1"
"github.com/beclab/Olares/cli/pkg/common"
cc "github.com/beclab/Olares/cli/pkg/core/common"
"github.com/beclab/Olares/cli/pkg/core/connector"
"github.com/beclab/Olares/cli/pkg/core/task"
"github.com/beclab/Olares/cli/pkg/core/util"
accounttemplates "github.com/beclab/Olares/cli/pkg/terminus/templates"
"github.com/beclab/Olares/cli/pkg/utils"
"github.com/pkg/errors"
ctrl "sigs.k8s.io/controller-runtime"
)
type GetUserInfo struct {
common.KubeAction
}
func (s *GetUserInfo) Execute(runtime connector.Runtime) error {
var err error
s.KubeConf.Arg.User.DomainName, err = s.getDomainName()
if err != nil {
return err
}
logger.Infof("using Domain Name: %s", s.KubeConf.Arg.User.DomainName)
s.KubeConf.Arg.User.UserName, err = s.getUserName()
if err != nil {
return err
}
logger.Infof("using Olares Local Name: %s", s.KubeConf.Arg.User.UserName)
s.KubeConf.Arg.User.Email, err = s.getUserEmail()
if err != nil {
return err
}
logger.Infof("using Olares ID: %s", s.KubeConf.Arg.User.Email)
s.KubeConf.Arg.User.Password, s.KubeConf.Arg.User.EncryptedPassword, err = s.getUserPassword()
if err != nil {
return err
}
if s.KubeConf.Arg.User.Password != "" {
logger.Infof("using password: %s", s.KubeConf.Arg.User.Password)
} else {
logger.Infof("using already encrypted password")
}
return nil
}
func (s *GetUserInfo) getDomainName() (string, error) {
domainName := s.KubeConf.Arg.User.DomainName
if len(domainName) > 0 {
if !utils.IsValidDomain(domainName) {
return "", errors.New(fmt.Sprintf("invalid domain name \"%s\", please reset", domainName))
}
return domainName, nil
}
reader, err := utils.GetBufIOReaderOfTerminalInput()
if err != nil {
return "", errors.Wrap(err, "failed to get terminal input reader")
}
LOOP:
fmt.Printf("\nEnter the domain name ( %s by default ): ", cc.DefaultDomainName)
domainName, err = reader.ReadString('\n')
if err != nil && err.Error() != "EOF" {
return domainName, errors.Wrap(errors.WithStack(err), "read domain name failed")
}
domainName = strings.TrimSpace(domainName)
if domainName == "" {
return cc.DefaultDomainName, nil
}
if !utils.IsValidDomain(domainName) {
fmt.Printf("\ninvalid domain name, please try again")
goto LOOP
}
return domainName, nil
}
func (s *GetUserInfo) getUserName() (string, error) {
userName := s.KubeConf.Arg.User.UserName
if strings.Contains(userName, "@") {
userName = strings.Split(userName, "@")[0]
}
userName = strings.TrimSpace(userName)
if len(userName) > 0 {
if err := utils.ValidateUserName(userName); err != nil {
return "", fmt.Errorf("invalid username \"%s\": %s, please reset", userName, err.Error())
}
return userName, nil
}
reader, err := utils.GetBufIOReaderOfTerminalInput()
if err != nil {
return "", errors.Wrap(err, "failed to get terminal input reader")
}
LOOP:
fmt.Printf("\nEnter the Olares ID (which you registered in the LarePass app): ")
userName, err = reader.ReadString('\n')
if err != nil && err.Error() != "EOF" {
return "", errors.Wrap(errors.WithStack(err), "read username failed")
}
if strings.Contains(userName, "@") {
userName = strings.Split(userName, "@")[0]
}
userName = strings.TrimSpace(userName)
if err := utils.ValidateUserName(userName); err != nil {
fmt.Printf("\ninvalid username: %s, please try again", err.Error())
goto LOOP
}
return userName, nil
}
func (s *GetUserInfo) getUserEmail() (string, error) {
userEmail := strings.TrimSpace(os.Getenv("TERMINUS_OS_EMAIL"))
if len(userEmail) == 0 {
return s.KubeConf.Arg.User.UserName + "@" + s.KubeConf.Arg.User.DomainName, nil
}
if _, err := mail.ParseAddress(userEmail); err != nil {
return "", fmt.Errorf("invalid email address \"%s\" set in env: %s, please reset", userEmail, err.Error())
}
return userEmail, nil
}
func (s *GetUserInfo) getUserPassword() (string, string, error) {
// currently only used in the installation flow by LarePass -> Olaresd,
// when this env var is passed in, it is already encrypted
// make this one priority over the password set in the arg specailly
// to ensure the larepass installation flow works as expected
encryptedPassword := strings.TrimSpace(os.Getenv(common.EnvLegacyEncryptedOSPassword))
if len(encryptedPassword) != 32 && len(encryptedPassword) != 0 {
return "", "", fmt.Errorf("invalid password \"%s\" set in env: length should be equal 32, please reset", encryptedPassword)
}
if len(encryptedPassword) == 0 {
if s.KubeConf.Arg.User.Password != "" {
return s.KubeConf.Arg.User.Password, utils.EncryptPassword(s.KubeConf.Arg.User.Password), nil
} else {
return utils.GenerateEncryptedPassword(8)
}
}
return "", encryptedPassword, nil
}
type SetAccountValues struct {
common.KubeAction
}
func (p *SetAccountValues) Execute(runtime connector.Runtime) error {
var accountFile = path.Join(runtime.GetInstallerDir(), "wizard", "config", "account", accounttemplates.AccountValues.Name())
var data = util.Data{
"UserName": p.KubeConf.Arg.User.UserName,
"Password": p.KubeConf.Arg.User.EncryptedPassword,
"Email": p.KubeConf.Arg.User.Email,
"DomainName": p.KubeConf.Arg.User.DomainName,
}
accountStr, err := util.Render(accounttemplates.AccountValues, data)
if err != nil {
return errors.Wrap(errors.WithStack(err), "render account template failed")
}
if err := util.WriteFile(accountFile, []byte(accountStr), cc.FileMode0644); err != nil {
return errors.Wrap(errors.WithStack(err), fmt.Sprintf("write account %s failed", accountFile))
}
return nil
}
type InstallAccount struct {
common.KubeAction
}
func (t *InstallAccount) Execute(runtime connector.Runtime) error {
config, err := ctrl.GetConfig()
if err != nil {
return err
}
ns := corev1.NamespaceDefault
actionConfig, settings, err := utils.InitConfig(config, ns)
if err != nil {
return err
}
var ctx, cancel = context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
var accountPath = path.Join(runtime.GetInstallerDir(), "wizard", "config", "account")
if !util.IsExist(accountPath) {
return fmt.Errorf("account not exists")
}
vals := make(map[string]interface{})
if si := runtime.GetSystemInfo(); si.GetNATGateway() != "" {
vals["nat_gateway_ip"] = si.GetNATGateway()
}
if err := utils.UpgradeCharts(ctx, actionConfig, settings, common.ChartNameAccount, accountPath, "", ns, vals, false); err != nil {
return err
}
return nil
}
type InstallAccountModule struct {
common.KubeModule
}
func (m *InstallAccountModule) Init() {
logger.InfoInstallationProgress("Installing account ...")
m.Name = "InstallAccount"
getUserInfo := &task.LocalTask{
Name: "GetUserInfo",
Action: new(GetUserInfo),
}
setAccountValues := &task.LocalTask{
Name: "SetAccountValues",
Action: &SetAccountValues{},
Retry: 1,
}
installAccount := &task.LocalTask{
Name: "InstallAccount",
Action: &InstallAccount{},
Retry: 1,
}
m.Tasks = []task.Interface{
getUserInfo,
setAccountValues,
installAccount,
}
}