Skip to content

Commit

Permalink
refactor: use v1 auth service to create tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
alespour authored and stuartcarnie committed Nov 2, 2020
1 parent 7552215 commit 0853370
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 333 deletions.
12 changes: 4 additions & 8 deletions cmd/influxd/upgrade/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import (
)

// upgradeDatabases creates databases, buckets, retention policies and shard info according to 1.x meta and copies data
func upgradeDatabases(ctx context.Context, v1 *influxDBv1, v2 *influxDBv2, v1opts *optionsV1, v2opts *optionsV2, orgID influxdb.ID, log *zap.Logger) (map[string][]string, error) {
db2BucketIds := make(map[string][]string)
func upgradeDatabases(ctx context.Context, v1 *influxDBv1, v2 *influxDBv2, v1opts *optionsV1, v2opts *optionsV2, orgID influxdb.ID, log *zap.Logger) (map[string][]influxdb.ID, error) {
db2BucketIds := make(map[string][]influxdb.ID)

targetDataPath := filepath.Join(v2opts.enginePath, "data")
targetWalPath := filepath.Join(v2opts.enginePath, "wal")
Expand Down Expand Up @@ -72,7 +72,7 @@ func upgradeDatabases(ctx context.Context, v1 *influxDBv1, v2 *influxDBv2, v1opt
}

// db to buckets IDs mapping
db2BucketIds[db.Name] = make([]string, 0, len(db.RetentionPolicies))
db2BucketIds[db.Name] = make([]influxdb.ID, 0, len(db.RetentionPolicies))

for _, rp := range db.RetentionPolicies {
sourcePath := filepath.Join(v1opts.dataDir, db.Name, rp.Name)
Expand All @@ -95,7 +95,7 @@ func upgradeDatabases(ctx context.Context, v1 *influxDBv1, v2 *influxDBv2, v1opt

}

db2BucketIds[db.Name] = append(db2BucketIds[db.Name], bucket.ID.String())
db2BucketIds[db.Name] = append(db2BucketIds[db.Name], bucket.ID)
if options.verbose {
log.Info("Creating database with retention policy",
zap.String("database", bucket.ID.String()))
Expand Down Expand Up @@ -176,9 +176,5 @@ func upgradeDatabases(ctx context.Context, v1 *influxDBv1, v2 *influxDBv2, v1opt
}
}

err = v2.close()
if err != nil {
return nil, fmt.Errorf("error closing v2: %w", err)
}
return db2BucketIds, nil
}
241 changes: 54 additions & 187 deletions cmd/influxd/upgrade/security.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
package upgrade

// Security upgrade implementation.
// Generates script for upgrading 1.x users into tokens in 2.x.
// Creates tokens representing v1 users.

import (
"context"
"errors"
"fmt"
"os"
"regexp"
"runtime"
"sort"
"strings"
"text/template"

platform "github.com/influxdata/influxdb/v2"
"github.com/influxdata/influxdb/v2/v1/services/meta"
"github.com/influxdata/influxql"
"go.uber.org/zap"
)

// generateSecurityScript creates security upgrade script with 1.x users mapped to 2.x tokens.
func generateSecurityScript(v1 *influxDBv1, targetOptions optionsV2, dbBuckets map[string][]string, log *zap.Logger) error {
// upgradeUsers creates tokens representing v1 users.
func upgradeUsers(ctx context.Context, v1 *influxDBv1, v2 *influxDBv2, targetOptions *optionsV2, dbBuckets map[string][]platform.ID, log *zap.Logger) error {
// check if there any 1.x users at all
v1meta := v1.meta
if len(v1meta.Users()) == 0 {
log.Info("There are no users in 1.x, no script will be created.")
log.Info("There are no users in 1.x, nothing to upgrade.")
return nil
}

Expand All @@ -36,128 +33,91 @@ func generateSecurityScript(v1 *influxDBv1, targetOptions optionsV2, dbBuckets m
return errors.New("upgrade: there were errors/warnings, please fix them and run the command again")
}

// create output
var output *os.File
var isFileOutput bool
if targetOptions.securityScriptPath == "" {
output = os.Stdout
} else {
file, err := os.OpenFile(targetOptions.securityScriptPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)
if err != nil {
return err
}
defer file.Close()
output = file
isFileOutput = true
}

// template data type
type dataObject struct {
AdminUsers []string
IgnoreUsers []string
UpgradeUsers []string
UserArgs map[string][]string
Exe string
TargetAdmin string
TargetOrg string
TargetToken string
IsFileOutput bool
InfluxExe string
}

// data
data := dataObject{
UserArgs: make(map[string][]string),
TargetAdmin: targetOptions.userName,
TargetOrg: targetOptions.orgName,
TargetToken: targetOptions.token,
IsFileOutput: isFileOutput,
InfluxExe: targetOptions.influx2CommandPath,
}

// fill data with users and their permissions
// upgrade users
for _, row := range helper.sortUserInfo(v1meta.Users()) {
username := row.Name
if row.Admin {
data.AdminUsers = append(data.AdminUsers, username)
log.Info("User is admin and will not be upgraded.", zap.String("username", username))
} else if len(row.Privileges) == 0 {
data.IgnoreUsers = append(data.IgnoreUsers, username)
log.Info("User has no privileges and will not be upgraded.", zap.String("username", username))
} else {
data.UpgradeUsers = append(data.UpgradeUsers, username)
dbList := make([]string, 0)
var dbList []string
for database := range row.Privileges {
dbList = append(dbList, database)
}
sort.Strings(dbList)
accessArgs := make([]string, 0)
var permissions []platform.Permission
for _, database := range dbList {
permission := row.Privileges[database]
for _, id := range dbBuckets[database] {
switch permission {
case influxql.ReadPrivilege:
accessArgs = append(accessArgs, fmt.Sprintf("--read-bucket=%s", id))
p, err := platform.NewPermissionAtID(id, platform.ReadAction, platform.BucketsResourceType, targetOptions.orgID)
if err != nil {
return err
}
permissions = append(permissions, *p)
case influxql.WritePrivilege:
accessArgs = append(accessArgs, fmt.Sprintf("--write-bucket=%s", id))
p, err := platform.NewPermissionAtID(id, platform.WriteAction, platform.BucketsResourceType, targetOptions.orgID)
if err != nil {
return err
}
permissions = append(permissions, *p)
case influxql.AllPrivileges:
accessArgs = append(accessArgs, fmt.Sprintf("--read-bucket=%s", id))
accessArgs = append(accessArgs, fmt.Sprintf("--write-bucket=%s", id))
p, err := platform.NewPermissionAtID(id, platform.ReadAction, platform.BucketsResourceType, targetOptions.orgID)
if err != nil {
return err
}
permissions = append(permissions, *p)
p, err = platform.NewPermissionAtID(id, platform.WriteAction, platform.BucketsResourceType, targetOptions.orgID)
if err != nil {
return err
}
permissions = append(permissions, *p)
}
}
}
if len(accessArgs) > 0 { // should always be true
data.UserArgs[username] = accessArgs
if len(permissions) > 0 {
auth := &platform.Authorization{
Description: username + "'s Token",
Permissions: permissions,
Token: username,
OrgID: targetOptions.orgID,
UserID: targetOptions.userID,
}
err := v2.authSvc.CreateAuthorization(ctx, auth)
if err != nil {
log.Error("Failed to create authorization.", zap.String("user", username), zap.Error(err))
continue
}
err = v2.authSvc.SetPasswordHash(ctx, auth.ID, row.Hash)
if err != nil {
log.Error("Failed to set user's password.", zap.String("user", username), zap.Error(err))
continue
}
log.Info("User upgraded.", zap.String("username", username))
} else {
log.Info("User has no privileges and will not be upgraded.", zap.String("username", username))
}
}
}

// load template
var tmpl string
if runtime.GOOS == "win" {
tmpl = securityScriptCmdTemplate
} else {
tmpl = securityScriptShTemplate
}
t, err := template.New("script").Funcs(template.FuncMap{
"shUserVar": func(name string) string {
return helper.shUserVar(name)
},
"userArgs": func(args []string) string {
return strings.Join(args, " ")
},
}).Parse(tmpl)
if err != nil {
return err
}

// generate the script
err = t.Execute(output, data)
if err != nil {
return err
}

if isFileOutput {
log.Info(fmt.Sprintf("Security upgrade script saved to %s.", targetOptions.securityScriptPath))
}

return nil
}

// securityScriptHelper is a helper used by `generate-security-script` command.
type securityScriptHelper struct {
shReg *regexp.Regexp
log *zap.Logger
log *zap.Logger
}

// newSecurityScriptHelper returns new security script helper instance for `generate-security-script` command.
func newSecurityScriptHelper(log *zap.Logger) *securityScriptHelper {
helper := &securityScriptHelper{
log: log,
}
helper.shReg = regexp.MustCompile("[^a-zA-Z0-9]+")

return helper
}
func (h *securityScriptHelper) checkDbBuckets(meta *meta.Client, databases map[string][]string) bool {
func (h *securityScriptHelper) checkDbBuckets(meta *meta.Client, databases map[string][]platform.ID) bool {
ok := true
for _, row := range meta.Users() {
for database := range row.Privileges {
Expand All @@ -181,96 +141,3 @@ func (h *securityScriptHelper) sortUserInfo(info []meta.UserInfo) []meta.UserInf
})
return info
}

func (h *securityScriptHelper) shUserVar(name string) string {
return "UPGRADE_USER_" + h.shReg.ReplaceAllString(name, "_")
}

// script templates

var securityScriptShTemplate = `#!/bin/sh
{{- range $u := $.UpgradeUsers}}
{{shUserVar $u}}=yes # user {{$u}}
{{- end}}
{{- range $u := $.AdminUsers}}
# user {{$u}} is 1.x admin and will not be upgraded automatically
{{- end}}
{{- range $u := $.IgnoreUsers}}
# user {{$u}} has no privileges and will be skipped
{{- end}}
#
# SCRIPT VARS
#
INFLUX={{$.InfluxExe}}
INFLUX_TOKEN={{$.TargetToken}}
{{- if $.IsFileOutput}}
LOG="${0%.*}.$(date +%Y%m%d-%H%M%S).log"
{{end}}
#
# USERS UPGRADES
#
{{range $u := $.UpgradeUsers}}
if [ "${{shUserVar $u}}" = "yes" ]; then
echo Creating authorization token for user {{$u}}...
env INFLUX_TOKEN=$INFLUX_TOKEN $INFLUX auth create --user={{$.TargetAdmin}} --org={{$.TargetOrg}} --description="{{$u}}" {{index $.UserArgs $u | userArgs}}
fi {{- if $.IsFileOutput}} 2>&1 | tee -a $LOG{{- end}}
{{- end}}
{{- if $.IsFileOutput}}
echo
echo Output saved to $LOG
{{- end}}
`

var securityScriptCmdTemplate = `@ECHO OFF
{{- range $u := $.UpgradeUsers}}
REM user {{$u}}
set {{shUserVar $u}}=yes
{{- end}}
{{- range $u := $.AdminUsers}}
REM user {{$u}} is 1.x admin and will not be upgraded automatically
{{- end}}
{{- range $u := $.IgnoreUsers}}
REM user {{$u}} has no privileges will be skipped
{{- end}}
REM
REM SCRIPT VARS
REM
set INFLUX="{{$.InfluxExe}}.exe"
set INFLUX_TOKEN={{$.TargetToken}}
{{- if $.IsFileOutput}}
set PATH=%PATH%;C:\WINDOWS\system32\wbem
for /f %%x in ('wmic os get localdatetime ^| findstr /b [0-9]') do @set X=%%x && set LOG=%~dpn0.%X:~0,8%-%X:~8,6%.log
{{end}}
REM
REM INDIVIDUAL USERS UPGRADES
REM
{{range $u := $.UpgradeUsers}}
IF /I "%{{shUserVar $u}}%" == "yes" (
echo Creating authorization token for user {{$u}}...
%INFLUX% auth create --user={{$.TargetAdmin}} --org={{$.TargetOrg}} --description="{{$u}}" {{index $.UserArgs $u | userArgs}}
) {{- if $.IsFileOutput}} >> %LOG% 2>&1 {{- end}}
{{- end}}
{{- if $.IsFileOutput}}
type %LOG%
echo.
echo Output saved to %LOG%
{{- end}}
`
Loading

0 comments on commit 0853370

Please sign in to comment.