Merge pull request #2818 from owncloud/unify-commands-and-service-options

unify configuration and commands
This commit is contained in:
Willy Kloucek
2022-01-07 13:49:23 +01:00
committed by GitHub
307 changed files with 5365 additions and 5131 deletions

View File

@@ -16,10 +16,11 @@ func AddAccount(cfg *config.Config) *cli.Command {
PasswordProfile: &accounts.PasswordProfile{},
}
return &cli.Command{
Name: "add",
Usage: "Create a new account",
Aliases: []string{"create", "a"},
Flags: flagset.AddAccountWithConfig(cfg, a),
Name: "add",
Usage: "create a new account",
Category: "account management",
Aliases: []string{"create", "a"},
Flags: flagset.AddAccountWithConfig(cfg, a),
Before: func(c *cli.Context) error {
// Write value of username to the flags beneath, as preferred name
// and on-premises-sam-account-name is probably confusing for users.
@@ -41,7 +42,7 @@ func AddAccount(cfg *config.Config) *cli.Command {
},
Action: func(c *cli.Context) error {
accSvcID := cfg.GRPC.Namespace + "." + cfg.Server.Name
accSvcID := cfg.GRPC.Namespace + "." + cfg.Service.Name
accSvc := accounts.NewAccountsService(accSvcID, grpc.NewClient())
_, err := accSvc.CreateAccount(c.Context, &accounts.CreateAccountRequest{
Account: a,

View File

@@ -0,0 +1,53 @@
package command
import (
"fmt"
"net/http"
"github.com/owncloud/ocis/accounts/pkg/config"
"github.com/owncloud/ocis/accounts/pkg/config/parser"
"github.com/owncloud/ocis/accounts/pkg/logging"
"github.com/urfave/cli/v2"
)
// Health is the entrypoint for the health command.
func Health(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "health",
Usage: "check health status",
Category: "info",
Before: func(c *cli.Context) error {
return parser.ParseConfig(cfg)
},
Action: func(c *cli.Context) error {
logger := logging.Configure(cfg.Service.Name, cfg.Log)
resp, err := http.Get(
fmt.Sprintf(
"http://%s/healthz",
cfg.Debug.Addr,
),
)
if err != nil {
logger.Fatal().
Err(err).
Msg("Failed to request health check")
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
logger.Fatal().
Int("code", resp.StatusCode).
Msg("Health seems to be in bad state")
}
logger.Debug().
Int("code", resp.StatusCode).
Msg("Health got a good state")
return nil
},
}
}

View File

@@ -18,11 +18,12 @@ import (
func InspectAccount(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "inspect",
Usage: "Show detailed data on an existing account",
Usage: "show detailed data on an existing account",
Category: "account management",
ArgsUsage: "id",
Flags: flagset.InspectAccountWithConfig(cfg),
Action: func(c *cli.Context) error {
accServiceID := cfg.GRPC.Namespace + "." + cfg.Server.Name
accServiceID := cfg.GRPC.Namespace + "." + cfg.Service.Name
if c.NArg() != 1 {
fmt.Println("Please provide a user-id")
os.Exit(1)

View File

@@ -17,12 +17,13 @@ import (
// ListAccounts command lists all accounts
func ListAccounts(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "list",
Usage: "List existing accounts",
Aliases: []string{"ls"},
Flags: flagset.ListAccountsWithConfig(cfg),
Name: "list",
Usage: "list existing accounts",
Category: "account management",
Aliases: []string{"ls"},
Flags: flagset.ListAccountsWithConfig(cfg),
Action: func(c *cli.Context) error {
accSvcID := cfg.GRPC.Namespace + "." + cfg.Server.Name
accSvcID := cfg.GRPC.Namespace + "." + cfg.Service.Name
accSvc := accounts.NewAccountsService(accSvcID, grpc.NewClient())
resp, err := accSvc.ListAccounts(c.Context, &accounts.ListAccountsRequest{})

View File

@@ -14,9 +14,10 @@ import (
// RebuildIndex rebuilds the entire configured index.
func RebuildIndex(cdf *config.Config) *cli.Command {
return &cli.Command{
Name: "rebuildIndex",
Usage: "Rebuilds the service's index, i.e. deleting and then re-adding all existing documents",
Aliases: []string{"rebuild", "ri"},
Name: "rebuildIndex",
Usage: "rebuilds the service's index, i.e. deleting and then re-adding all existing documents",
Category: "account management",
Aliases: []string{"rebuild", "ri"},
Action: func(ctx *cli.Context) error {
idxSvcID := "com.owncloud.api.accounts"
idxSvc := index.NewIndexService(idxSvcID, grpc.NewClient())

View File

@@ -16,12 +16,13 @@ import (
func RemoveAccount(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "remove",
Usage: "Removes an existing account",
Usage: "removes an existing account",
Category: "account management",
ArgsUsage: "id",
Aliases: []string{"rm"},
Flags: flagset.RemoveAccountWithConfig(cfg),
Action: func(c *cli.Context) error {
accServiceID := cfg.GRPC.Namespace + "." + cfg.Server.Name
accServiceID := cfg.GRPC.Namespace + "." + cfg.Service.Name
if c.NArg() != 1 {
fmt.Println("Please provide a user-id")
os.Exit(1)

View File

@@ -4,84 +4,49 @@ import (
"context"
"os"
"github.com/owncloud/ocis/ocis-pkg/shared"
"github.com/owncloud/ocis/accounts/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/clihelper"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/version"
"github.com/thejerf/suture/v4"
"github.com/urfave/cli/v2"
)
// GetCommands provides all commands for this service
func GetCommands(cfg *config.Config) cli.Commands {
return []*cli.Command{
// start this service
Server(cfg),
// interaction with this service
AddAccount(cfg),
UpdateAccount(cfg),
ListAccounts(cfg),
InspectAccount(cfg),
RemoveAccount(cfg),
RebuildIndex(cfg),
// infos about this service
Health(cfg),
Version(cfg),
}
}
// Execute is the entry point for the ocis-accounts command.
func Execute(cfg *config.Config) error {
app := &cli.App{
app := clihelper.DefaultApp(&cli.App{
Name: "ocis-accounts",
Version: version.String,
Usage: "Provide accounts and groups for oCIS",
Compiled: version.Compiled(),
Authors: []*cli.Author{
{
Name: "ownCloud GmbH",
Email: "support@owncloud.com",
},
},
Before: func(c *cli.Context) error {
cfg.Server.Version = version.String
return ParseConfig(c, cfg)
},
Commands: []*cli.Command{
Server(cfg),
AddAccount(cfg),
UpdateAccount(cfg),
ListAccounts(cfg),
InspectAccount(cfg),
RemoveAccount(cfg),
PrintVersion(cfg),
RebuildIndex(cfg),
},
}
Commands: GetCommands(cfg),
})
cli.HelpFlag = &cli.BoolFlag{
Name: "help,h",
Usage: "Show the help",
}
cli.VersionFlag = &cli.BoolFlag{
Name: "version,v",
Usage: "Print the version",
}
return app.Run(os.Args)
}
// ParseConfig loads accounts configuration from known paths.
func ParseConfig(c *cli.Context, cfg *config.Config) error {
conf, err := ociscfg.BindSourcesToStructs("accounts", cfg)
if err != nil {
return err
}
// provide with defaults for shared logging, since we need a valid destination address for BindEnv.
if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
cfg.Log = &shared.Log{
Level: cfg.Commons.Log.Level,
Pretty: cfg.Commons.Log.Pretty,
Color: cfg.Commons.Log.Color,
File: cfg.Commons.Log.File,
}
} else if cfg.Log == nil && cfg.Commons == nil {
cfg.Log = &shared.Log{}
}
// load all env variables relevant to the config in the current context.
conf.LoadOSEnv(config.GetEnv(cfg), false)
bindings := config.StructMappings(cfg)
return ociscfg.BindEnv(conf, bindings)
}
// SutureService allows for the accounts command to be embedded and supervised by a suture supervisor tree.
type SutureService struct {
cfg *config.Config

View File

@@ -2,41 +2,33 @@ package command
import (
"context"
"strings"
"github.com/owncloud/ocis/ocis-pkg/log"
"fmt"
"github.com/oklog/run"
"github.com/owncloud/ocis/accounts/pkg/config"
"github.com/owncloud/ocis/accounts/pkg/config/parser"
"github.com/owncloud/ocis/accounts/pkg/logging"
"github.com/owncloud/ocis/accounts/pkg/metrics"
"github.com/owncloud/ocis/accounts/pkg/server/debug"
"github.com/owncloud/ocis/accounts/pkg/server/grpc"
"github.com/owncloud/ocis/accounts/pkg/server/http"
svc "github.com/owncloud/ocis/accounts/pkg/service/v0"
"github.com/owncloud/ocis/accounts/pkg/tracing"
"github.com/owncloud/ocis/ocis-pkg/version"
"github.com/urfave/cli/v2"
)
// Server is the entry point for the server command.
func Server(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "server",
Usage: "Start ocis accounts service",
Description: "uses an LDAP server as the storage backend",
Before: func(ctx *cli.Context) error {
if cfg.HTTP.Root != "/" {
cfg.HTTP.Root = strings.TrimSuffix(cfg.HTTP.Root, "/")
}
cfg.Repo.Backend = strings.ToLower(cfg.Repo.Backend)
if err := ParseConfig(ctx, cfg); err != nil {
return err
}
return nil
Name: "server",
Usage: fmt.Sprintf("start %s extension without runtime (unsupervised mode)", cfg.Service.Name),
Category: "server",
Before: func(c *cli.Context) error {
return parser.ParseConfig(cfg)
},
Action: func(c *cli.Context) error {
logger := log.LoggerFromConfig("accounts", *cfg.Log)
logger := logging.Configure(cfg.Service.Name, cfg.Log)
err := tracing.Configure(cfg)
if err != nil {
return err
@@ -47,7 +39,7 @@ func Server(cfg *config.Config) *cli.Command {
defer cancel()
mtrcs.BuildInfo.WithLabelValues(cfg.Server.Version).Set(1)
mtrcs.BuildInfo.WithLabelValues(version.String).Set(1)
handler, err := svc.New(svc.Logger(logger), svc.Config(cfg))
if err != nil {
@@ -58,7 +50,7 @@ func Server(cfg *config.Config) *cli.Command {
httpServer := http.Server(
http.Config(cfg),
http.Logger(logger),
http.Name(cfg.Server.Name),
http.Name(cfg.Service.Name),
http.Context(ctx),
http.Metrics(mtrcs),
http.Handler(handler),
@@ -72,7 +64,7 @@ func Server(cfg *config.Config) *cli.Command {
grpcServer := grpc.Server(
grpc.Config(cfg),
grpc.Logger(logger),
grpc.Name(cfg.Server.Name),
grpc.Name(cfg.Service.Name),
grpc.Context(ctx),
grpc.Metrics(mtrcs),
grpc.Handler(handler),
@@ -83,6 +75,18 @@ func Server(cfg *config.Config) *cli.Command {
cancel()
})
// prepare a debug server and add it to the group run.
debugServer, err := debug.Server(debug.Logger(logger), debug.Context(ctx), debug.Config(cfg))
if err != nil {
logger.Error().Err(err).Str("server", "debug").Msg("Failed to initialize server")
return err
}
gr.Add(debugServer.ListenAndServe, func(_ error) {
_ = debugServer.Shutdown(ctx)
cancel()
})
return gr.Run()
},
}

View File

@@ -21,6 +21,7 @@ func UpdateAccount(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "update",
Usage: "Make changes to an existing account",
Category: "account management",
ArgsUsage: "id",
Flags: flagset.UpdateAccountWithConfig(cfg, a),
Before: func(c *cli.Context) error {
@@ -40,7 +41,7 @@ func UpdateAccount(cfg *config.Config) *cli.Command {
},
Action: func(c *cli.Context) error {
a.Id = c.Args().First()
accSvcID := cfg.GRPC.Namespace + "." + cfg.Server.Name
accSvcID := cfg.GRPC.Namespace + "." + cfg.Service.Name
accSvc := accounts.NewAccountsService(accSvcID, grpc.NewClient())
_, err := accSvc.UpdateAccount(c.Context, &accounts.UpdateAccountRequest{
Account: a,

View File

@@ -5,27 +5,33 @@ import (
"os"
"github.com/owncloud/ocis/ocis-pkg/registry"
"github.com/owncloud/ocis/ocis-pkg/version"
tw "github.com/olekukonko/tablewriter"
"github.com/owncloud/ocis/accounts/pkg/config"
"github.com/urfave/cli/v2"
)
// PrintVersion prints the service versions of all running instances.
func PrintVersion(cfg *config.Config) *cli.Command {
// Version prints the service versions of all running instances.
func Version(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "version",
Usage: "Print the versions of the running instances",
Name: "version",
Usage: "print the version of this binary and the running extension instances",
Category: "info",
Action: func(c *cli.Context) error {
fmt.Println("Version: " + version.String)
fmt.Printf("Compiled: %s\n", version.Compiled())
fmt.Println("")
reg := registry.GetRegistry()
services, err := reg.GetService(cfg.GRPC.Namespace + "." + cfg.Server.Name)
services, err := reg.GetService(cfg.GRPC.Namespace + "." + cfg.Service.Name)
if err != nil {
fmt.Println(fmt.Errorf("could not get accounts services from the registry: %v", err))
fmt.Println(fmt.Errorf("could not get %s services from the registry: %v", cfg.Service.Name, err))
return err
}
if len(services) == 0 {
fmt.Println("No running accounts service found.")
fmt.Println("No running " + cfg.Service.Name + " service found.")
return nil
}

View File

@@ -1,221 +1,86 @@
// Package config should be moved to internal
package config
import (
"context"
"path"
"github.com/owncloud/ocis/ocis-pkg/shared"
"github.com/owncloud/ocis/ocis-pkg/config/defaults"
)
// LDAP defines the available ldap configuration.
type LDAP struct {
Hostname string `ocisConfig:"hostname"`
Port int `ocisConfig:"port"`
BaseDN string `ocisConfig:"base_dn"`
UserFilter string `ocisConfig:"user_filter"`
GroupFilter string `ocisConfig:"group_filter"`
BindDN string `ocisConfig:"bind_dn"`
BindPassword string `ocisConfig:"bind_password"`
IDP string `ocisConfig:"idp"`
Schema LDAPSchema `ocisConfig:"schema"`
}
// Config combines all available configuration parts.
type Config struct {
*shared.Commons
// LDAPSchema defines the available ldap schema configuration.
type LDAPSchema struct {
AccountID string `ocisConfig:"account_id"`
Identities string `ocisConfig:"identities"`
Username string `ocisConfig:"username"`
DisplayName string `ocisConfig:"display_name"`
Mail string `ocisConfig:"mail"`
Groups string `ocisConfig:"groups"`
}
Service Service
// CORS defines the available cors configuration.
type CORS struct {
AllowedOrigins []string `ocisConfig:"allowed_origins"`
AllowedMethods []string `ocisConfig:"allowed_methods"`
AllowedHeaders []string `ocisConfig:"allowed_headers"`
AllowCredentials bool `ocisConfig:"allowed_credentials"`
}
Tracing Tracing `ocisConfig:"tracing"`
Log *Log `ocisConfig:"log"`
Debug Debug `ocisConfig:"debug"`
// HTTP defines the available http configuration.
type HTTP struct {
Addr string `ocisConfig:"addr"`
Namespace string `ocisConfig:"namespace"`
Root string `ocisConfig:"root"`
CacheTTL int `ocisConfig:"cache_ttl"`
CORS CORS `ocisConfig:"cors"`
}
HTTP HTTP `ocisConfig:"http"`
GRPC GRPC `ocisConfig:"grpc"`
// GRPC defines the available grpc configuration.
type GRPC struct {
Addr string `ocisConfig:"addr"`
Namespace string `ocisConfig:"namespace"`
}
TokenManager TokenManager `ocisConfig:"token_manager"`
// Server configures a server.
type Server struct {
Version string `ocisConfig:"version"`
Name string `ocisConfig:"name"`
HashDifficulty int `ocisConfig:"hash_difficulty"`
DemoUsersAndGroups bool `ocisConfig:"demo_users_and_groups"`
Asset Asset `ocisConfig:"asset"`
Repo Repo `ocisConfig:"repo"`
Index Index `ocisConfig:"index"`
ServiceUser ServiceUser `ocisConfig:"service_user"`
HashDifficulty int `ocisConfig:"hash_difficulty" env:"ACCOUNTS_HASH_DIFFICULTY"`
DemoUsersAndGroups bool `ocisConfig:"demo_users_and_groups" env:"ACCOUNTS_DEMO_USERS_AND_GROUPS"`
Context context.Context
}
// Asset defines the available asset configuration.
type Asset struct {
Path string `ocisConfig:"path"`
Path string `ocisConfig:"path" env:"ACCOUNTS_ASSET_PATH"`
}
// TokenManager is the config for using the reva token manager
type TokenManager struct {
JWTSecret string `ocisConfig:"jwt_secret"`
JWTSecret string `ocisConfig:"jwt_secret" env:"OCIS_JWT_SECRET;ACCOUNTS_JWT_SECRET"`
}
// Repo defines which storage implementation is to be used.
type Repo struct {
Backend string `ocisConfig:"backend"`
Backend string `ocisConfig:"backend" env:"ACCOUNTS_STORAGE_BACKEND"`
Disk Disk `ocisConfig:"disk"`
CS3 CS3 `ocisConfig:"cs3"`
}
// Disk is the local disk implementation of the storage.
type Disk struct {
Path string `ocisConfig:"path"`
Path string `ocisConfig:"path" env:"ACCOUNTS_STORAGE_DISK_PATH"`
}
// CS3 is the cs3 implementation of the storage.
type CS3 struct {
ProviderAddr string `ocisConfig:"provider_addr"`
JWTSecret string `ocisConfig:"jwt_secret"`
ProviderAddr string `ocisConfig:"provider_addr" env:"ACCOUNTS_STORAGE_CS3_PROVIDER_ADDR"`
JWTSecret string `ocisConfig:"jwt_secret" env:"ACCOUNTS_STORAGE_CS3_JWT_SECRET"`
}
// ServiceUser defines the user required for EOS.
type ServiceUser struct {
UUID string `ocisConfig:"uuid"`
Username string `ocisConfig:"username"`
UID int64 `ocisConfig:"uid"`
GID int64 `ocisConfig:"gid"`
UUID string `ocisConfig:"uuid" env:"ACCOUNTS_SERVICE_USER_UUID"`
Username string `ocisConfig:"username" env:"ACCOUNTS_SERVICE_USER_USERNAME"`
UID int64 `ocisConfig:"uid" env:"ACCOUNTS_SERVICE_USER_UID"`
GID int64 `ocisConfig:"gid" env:"ACCOUNTS_SERVICE_USER_GID"`
}
// Index defines config for indexes.
type Index struct {
UID Bound `ocisConfig:"uid"`
GID Bound `ocisConfig:"gid"`
UID UIDBound `ocisConfig:"uid"`
GID GIDBound `ocisConfig:"gid"`
}
// Bound defines a lower and upper bound.
type Bound struct {
Lower int64 `ocisConfig:"lower"`
Upper int64 `ocisConfig:"upper"`
// GIDBound defines a lower and upper bound.
type GIDBound struct {
Lower int64 `ocisConfig:"lower" env:"ACCOUNTS_GID_INDEX_LOWER_BOUND"`
Upper int64 `ocisConfig:"upper" env:"ACCOUNTS_GID_INDEX_UPPER_BOUND"`
}
// Tracing defines the available tracing configuration.
type Tracing struct {
Enabled bool `ocisConfig:"enabled"`
Type string `ocisConfig:"type"`
Endpoint string `ocisConfig:"endpoint"`
Collector string `ocisConfig:"collector"`
Service string `ocisConfig:"service"`
}
// Config merges all Account config parameters.
type Config struct {
*shared.Commons
LDAP LDAP `ocisConfig:"ldap"`
HTTP HTTP `ocisConfig:"http"`
GRPC GRPC `ocisConfig:"grpc"`
Server Server `ocisConfig:"server"`
Asset Asset `ocisConfig:"asset"`
Log *shared.Log `ocisConfig:"log"`
TokenManager TokenManager `ocisConfig:"token_manager"`
Repo Repo `ocisConfig:"repo"`
Index Index `ocisConfig:"index"`
ServiceUser ServiceUser `ocisConfig:"service_user"`
Tracing Tracing `ocisConfig:"tracing"`
Context context.Context
Supervised bool
}
// New returns a new config.
func New() *Config {
return &Config{
Log: &shared.Log{},
}
}
func DefaultConfig() *Config {
return &Config{
LDAP: LDAP{},
HTTP: HTTP{
Addr: "127.0.0.1:9181",
Namespace: "com.owncloud.web",
Root: "/",
CacheTTL: 604800, // 7 days
CORS: CORS{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Authorization", "Origin", "Content-Type", "Accept", "X-Requested-With"},
AllowCredentials: true,
},
},
GRPC: GRPC{
Addr: "127.0.0.1:9180",
Namespace: "com.owncloud.api",
},
Server: Server{
Name: "accounts",
HashDifficulty: 11,
DemoUsersAndGroups: true,
},
Asset: Asset{},
TokenManager: TokenManager{
JWTSecret: "Pive-Fumkiu4",
},
Repo: Repo{
Backend: "CS3",
Disk: Disk{
Path: path.Join(defaults.BaseDataPath(), "accounts"),
},
CS3: CS3{
ProviderAddr: "localhost:9215",
JWTSecret: "Pive-Fumkiu4",
},
},
Index: Index{
UID: Bound{
Lower: 0,
Upper: 1000,
},
GID: Bound{
Lower: 0,
Upper: 1000,
},
},
ServiceUser: ServiceUser{
UUID: "95cb8724-03b2-11eb-a0a6-c33ef8ef53ad",
Username: "",
UID: 0,
GID: 0,
},
Tracing: Tracing{
Type: "jaeger",
Service: "accounts",
},
}
}
// GetEnv fetches a list of known env variables for this extension. It is to be used by gookit, as it provides a list
// with all the environment variables an extension supports.
func GetEnv(cfg *Config) []string {
var r = make([]string, len(structMappings(cfg)))
for i := range structMappings(cfg) {
r = append(r, structMappings(cfg)[i].EnvVars...)
}
return r
// UIDBound defines a lower and upper bound.
type UIDBound struct {
Lower int64 `ocisConfig:"lower" env:"ACCOUNTS_UID_INDEX_LOWER_BOUND"`
Upper int64 `ocisConfig:"upper" env:"ACCOUNTS_UID_INDEX_UPPER_BOUND"`
}

View File

@@ -0,0 +1,9 @@
package config
// Debug defines the available debug configuration.
type Debug struct {
Addr string `ocisConfig:"addr" env:"ACCOUNTS_DEBUG_ADDR"`
Token string `ocisConfig:"token" env:"ACCOUNTS_DEBUG_TOKEN"`
Pprof bool `ocisConfig:"pprof" env:"ACCOUNTS_DEBUG_PPROF"`
Zpages bool `ocisConfig:"zpages" env:"ACCOUNTS_DEBUG_ZPAGES"`
}

View File

@@ -0,0 +1,69 @@
package config
import (
"path"
"github.com/owncloud/ocis/ocis-pkg/config/defaults"
)
func DefaultConfig() *Config {
return &Config{
Debug: Debug{
Addr: "127.0.0.1:9182",
Token: "",
Pprof: false,
Zpages: false,
},
HTTP: HTTP{
Addr: "127.0.0.1:9181",
Namespace: "com.owncloud.web",
Root: "/",
CacheTTL: 604800, // 7 days
CORS: CORS{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Authorization", "Origin", "Content-Type", "Accept", "X-Requested-With"},
AllowCredentials: true,
},
},
GRPC: GRPC{
Addr: "127.0.0.1:9180",
Namespace: "com.owncloud.api",
},
Service: Service{
Name: "accounts",
},
Asset: Asset{},
TokenManager: TokenManager{
JWTSecret: "Pive-Fumkiu4",
},
HashDifficulty: 11,
DemoUsersAndGroups: true,
Repo: Repo{
Backend: "CS3",
Disk: Disk{
Path: path.Join(defaults.BaseDataPath(), "accounts"),
},
CS3: CS3{
ProviderAddr: "localhost:9215",
JWTSecret: "Pive-Fumkiu4",
},
},
Index: Index{
UID: UIDBound{
Lower: 0,
Upper: 1000,
},
GID: GIDBound{
Lower: 0,
Upper: 1000,
},
},
ServiceUser: ServiceUser{
UUID: "95cb8724-03b2-11eb-a0a6-c33ef8ef53ad",
Username: "",
UID: 0,
GID: 0,
},
}
}

View File

@@ -0,0 +1,7 @@
package config
// GRPC defines the available grpc configuration.
type GRPC struct {
Addr string `ocisConfig:"addr" env:"ACCOUNTS_GRPC_ADDR"`
Namespace string
}

View File

@@ -0,0 +1,18 @@
package config
// HTTP defines the available http configuration.
type HTTP struct {
Addr string `ocisConfig:"addr" env:"ACCOUNTS_HTTP_ADDR"`
Namespace string
Root string `ocisConfig:"root" env:"ACCOUNTS_HTTP_ROOT"`
CacheTTL int `ocisConfig:"cache_ttl" env:"ACCOUNTS_CACHE_TTL"`
CORS CORS `ocisConfig:"cors"`
}
// CORS defines the available cors configuration.
type CORS struct {
AllowedOrigins []string `ocisConfig:"allowed_origins"`
AllowedMethods []string `ocisConfig:"allowed_methods"`
AllowedHeaders []string `ocisConfig:"allowed_headers"`
AllowCredentials bool `ocisConfig:"allowed_credentials"`
}

View File

@@ -0,0 +1,9 @@
package config
// Log defines the available log configuration.
type Log struct {
Level string `mapstructure:"level" env:"OCIS_LOG_LEVEL;ACCOUNTS_LOG_LEVEL"`
Pretty bool `mapstructure:"pretty" env:"OCIS_LOG_PRETTY;ACCOUNTS_LOG_PRETTY"`
Color bool `mapstructure:"color" env:"OCIS_LOG_COLOR;ACCOUNTS_LOG_COLOR"`
File string `mapstructure:"file" env:"OCIS_LOG_FILE;ACCOUNTS_LOG_FILE"`
}

View File

@@ -1,140 +0,0 @@
package config
import "github.com/owncloud/ocis/ocis-pkg/shared"
// StructMappings binds a set of environment variables to a destination on cfg. Iterating over this set and editing the
// Destination value of a binding will alter the original value, as it is a pointer to its memory address. This lets
// us propagate changes easier.
func StructMappings(cfg *Config) []shared.EnvBinding {
return structMappings(cfg)
}
// structMappings binds a set of environment variables to a destination on cfg.
func structMappings(cfg *Config) []shared.EnvBinding {
return []shared.EnvBinding{
{
EnvVars: []string{"OCIS_LOG_FILE", "ACCOUNTS_LOG_FILE"},
Destination: &cfg.Log.File,
},
{
EnvVars: []string{"OCIS_LOG_COLOR", "ACCOUNTS_LOG_COLOR"},
Destination: &cfg.Log.Color,
},
{
EnvVars: []string{"OCIS_LOG_PRETTY", "ACCOUNTS_LOG_PRETTY"},
Destination: &cfg.Log.Pretty,
},
{
EnvVars: []string{"OCIS_TRACING_ENABLED", "ACCOUNTS_TRACING_ENABLED"},
Destination: &cfg.Tracing.Enabled,
},
{
EnvVars: []string{"OCIS_TRACING_TYPE", "ACCOUNTS_TRACING_TYPE"},
Destination: &cfg.Tracing.Type,
},
{
EnvVars: []string{"OCIS_TRACING_ENDPOINT", "ACCOUNTS_TRACING_ENDPOINT"},
Destination: &cfg.Tracing.Endpoint,
},
{
EnvVars: []string{"OCIS_TRACING_COLLECTOR", "ACCOUNTS_TRACING_COLLECTOR"},
Destination: &cfg.Tracing.Collector,
},
{
EnvVars: []string{"ACCOUNTS_TRACING_SERVICE"},
Destination: &cfg.Tracing.Service,
},
{
EnvVars: []string{"ACCOUNTS_HTTP_NAMESPACE"},
Destination: &cfg.HTTP.Namespace,
},
{
EnvVars: []string{"ACCOUNTS_HTTP_ADDR"},
Destination: &cfg.HTTP.Addr,
},
{
EnvVars: []string{"ACCOUNTS_HTTP_ROOT"},
Destination: &cfg.HTTP.Root,
},
{
EnvVars: []string{"ACCOUNTS_CACHE_TTL"},
Destination: &cfg.HTTP.CacheTTL,
},
{
EnvVars: []string{"ACCOUNTS_GRPC_NAMESPACE"},
Destination: &cfg.GRPC.Namespace,
},
{
EnvVars: []string{"ACCOUNTS_GRPC_ADDR"},
Destination: &cfg.GRPC.Addr,
},
{
EnvVars: []string{"ACCOUNTS_NAME"},
Destination: &cfg.Server.Name,
},
{
EnvVars: []string{"ACCOUNTS_HASH_DIFFICULTY"},
Destination: &cfg.Server.HashDifficulty,
},
{
EnvVars: []string{"ACCOUNTS_DEMO_USERS_AND_GROUPS"},
Destination: &cfg.Server.DemoUsersAndGroups,
},
{
EnvVars: []string{"ACCOUNTS_ASSET_PATH"},
Destination: &cfg.Asset.Path,
},
{
EnvVars: []string{"OCIS_JWT_SECRET", "ACCOUNTS_JWT_SECRET"},
Destination: &cfg.TokenManager.JWTSecret,
},
{
EnvVars: []string{"ACCOUNTS_STORAGE_BACKEND"},
Destination: &cfg.Repo.Backend,
},
{
EnvVars: []string{"ACCOUNTS_STORAGE_DISK_PATH"},
Destination: &cfg.Repo.Disk.Path,
},
{
EnvVars: []string{"ACCOUNTS_STORAGE_CS3_PROVIDER_ADDR"},
Destination: &cfg.Repo.CS3.ProviderAddr,
},
{
EnvVars: []string{"OCIS_JWT_SECRET", "ACCOUNTS_STORAGE_CS3_JWT_SECRET"},
Destination: &cfg.Repo.CS3.JWTSecret,
},
{
EnvVars: []string{"ACCOUNTS_SERVICE_USER_UUID"},
Destination: &cfg.ServiceUser.UUID,
},
{
EnvVars: []string{"ACCOUNTS_SERVICE_USER_USERNAME"},
Destination: &cfg.ServiceUser.Username,
},
{
EnvVars: []string{"ACCOUNTS_SERVICE_USER_UID"},
Destination: &cfg.ServiceUser.UID,
},
{
EnvVars: []string{"ACCOUNTS_SERVICE_USER_GID"},
Destination: &cfg.ServiceUser.GID,
},
{
EnvVars: []string{"ACCOUNTS_UID_INDEX_LOWER_BOUND"},
Destination: &cfg.Index.UID.Lower,
},
{
EnvVars: []string{"ACCOUNTS_GID_INDEX_LOWER_BOUND"},
Destination: &cfg.Index.GID.Lower,
},
{
EnvVars: []string{"ACCOUNTS_UID_INDEX_UPPER_BOUND"},
Destination: &cfg.Index.UID.Upper,
},
{
EnvVars: []string{"ACCOUNTS_GID_INDEX_UPPER_BOUND"},
Destination: &cfg.Index.GID.Upper,
},
}
}

View File

@@ -0,0 +1,47 @@
package parser
import (
"errors"
"strings"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/accounts/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/config/envdecode"
)
// ParseConfig loads accounts configuration from known paths.
func ParseConfig(cfg *config.Config) error {
_, err := ociscfg.BindSourcesToStructs(cfg.Service.Name, cfg)
if err != nil {
return err
}
// provide with defaults for shared logging, since we need a valid destination address for BindEnv.
if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
cfg.Log = &config.Log{
Level: cfg.Commons.Log.Level,
Pretty: cfg.Commons.Log.Pretty,
Color: cfg.Commons.Log.Color,
File: cfg.Commons.Log.File,
}
} else if cfg.Log == nil && cfg.Commons == nil {
cfg.Log = &config.Log{}
}
// load all env variables relevant to the config in the current context.
if err := envdecode.Decode(cfg); err != nil {
// no environment variable set for this config is an expected "error"
if !errors.Is(err, envdecode.ErrNoTargetFieldsAreSet) {
return err
}
}
// sanitize config
if cfg.HTTP.Root != "/" {
cfg.HTTP.Root = strings.TrimSuffix(cfg.HTTP.Root, "/")
}
cfg.Repo.Backend = strings.ToLower(cfg.Repo.Backend)
return nil
}

View File

@@ -0,0 +1,6 @@
package config
// Service defines the available service configuration.
type Service struct {
Name string
}

View File

@@ -0,0 +1,9 @@
package config
// Tracing defines the available tracing configuration.
type Tracing struct {
Enabled bool `ocisConfig:"enabled" env:"OCIS_TRACING_ENABLED;ACCOUNTS_TRACING_ENABLED"`
Type string `ocisConfig:"type" env:"OCIS_TRACING_TYPE;ACCOUNTS_TRACING_TYPE"`
Endpoint string `ocisConfig:"endpoint" env:"OCIS_TRACING_ENDPOINT;ACCOUNTS_TRACING_ENDPOINT"`
Collector string `ocisConfig:"collector" env:"OCIS_TRACING_COLLECTOR;ACCOUNTS_TRACING_COLLECTOR"`
}

View File

@@ -23,10 +23,10 @@ func UpdateAccountWithConfig(cfg *config.Config, a *accounts.Account) []cli.Flag
},
&cli.StringFlag{
Name: "name",
Value: flags.OverrideDefaultString(cfg.Server.Name, "accounts"),
Value: flags.OverrideDefaultString(cfg.Service.Name, "accounts"),
Usage: "service name",
EnvVars: []string{"ACCOUNTS_NAME"},
Destination: &cfg.Server.Name,
Destination: &cfg.Service.Name,
},
&cli.BoolFlag{
Name: "enabled",
@@ -107,10 +107,10 @@ func AddAccountWithConfig(cfg *config.Config, a *accounts.Account) []cli.Flag {
},
&cli.StringFlag{
Name: "name",
Value: flags.OverrideDefaultString(cfg.Server.Name, "accounts"),
Value: flags.OverrideDefaultString(cfg.Service.Name, "accounts"),
Usage: "service name",
EnvVars: []string{"ACCOUNTS_NAME"},
Destination: &cfg.Server.Name,
Destination: &cfg.Service.Name,
},
&cli.BoolFlag{
Name: "enabled",
@@ -191,10 +191,10 @@ func ListAccountsWithConfig(cfg *config.Config) []cli.Flag {
},
&cli.StringFlag{
Name: "name",
Value: flags.OverrideDefaultString(cfg.Server.Name, "accounts"),
Value: flags.OverrideDefaultString(cfg.Service.Name, "accounts"),
Usage: "service name",
EnvVars: []string{"ACCOUNTS_NAME"},
Destination: &cfg.Server.Name,
Destination: &cfg.Service.Name,
},
}
}
@@ -211,10 +211,10 @@ func RemoveAccountWithConfig(cfg *config.Config) []cli.Flag {
},
&cli.StringFlag{
Name: "name",
Value: flags.OverrideDefaultString(cfg.Server.Name, "accounts"),
Value: flags.OverrideDefaultString(cfg.Service.Name, "accounts"),
Usage: "service name",
EnvVars: []string{"ACCOUNTS_NAME"},
Destination: &cfg.Server.Name,
Destination: &cfg.Service.Name,
},
}
}
@@ -231,10 +231,10 @@ func InspectAccountWithConfig(cfg *config.Config) []cli.Flag {
},
&cli.StringFlag{
Name: "name",
Value: flags.OverrideDefaultString(cfg.Server.Name, "accounts"),
Value: flags.OverrideDefaultString(cfg.Service.Name, "accounts"),
Usage: "service name",
EnvVars: []string{"ACCOUNTS_NAME"},
Destination: &cfg.Server.Name,
Destination: &cfg.Service.Name,
},
}
}

View File

@@ -0,0 +1,17 @@
package logging
import (
"github.com/owncloud/ocis/accounts/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
)
// LoggerFromConfig initializes a service-specific logger instance.
func Configure(name string, cfg *config.Log) log.Logger {
return log.NewLogger(
log.Name(name),
log.Level(cfg.Level),
log.Pretty(cfg.Pretty),
log.Color(cfg.Color),
log.File(cfg.File),
)
}

View File

@@ -13,9 +13,9 @@ import (
mgrpcc "github.com/asim/go-micro/plugins/client/grpc/v4"
empty "github.com/golang/protobuf/ptypes/empty"
"github.com/owncloud/ocis/accounts/pkg/config"
"github.com/owncloud/ocis/accounts/pkg/logging"
"github.com/owncloud/ocis/accounts/pkg/proto/v0"
svc "github.com/owncloud/ocis/accounts/pkg/service/v0"
oclog "github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/service/grpc"
settings "github.com/owncloud/ocis/settings/pkg/proto/v0"
"github.com/stretchr/testify/assert"
@@ -78,14 +78,21 @@ func init() {
grpc.Address("localhost:9180"),
)
cfg := config.New()
cfg := config.DefaultConfig()
cfg.Repo.Backend = "disk"
cfg.Repo.Disk.Path = dataPath
cfg.Server.DemoUsersAndGroups = true
cfg.DemoUsersAndGroups = true
cfg.Log = &config.Log{}
var hdlr *svc.Service
var err error
if hdlr, err = svc.New(svc.Logger(oclog.LoggerFromConfig("accounts", *cfg.Log)), svc.Config(cfg), svc.RoleService(buildRoleServiceMock())); err != nil {
hdlr, err = svc.New(
svc.Logger(logging.Configure(cfg.Service.Name, cfg.Log)),
svc.Config(cfg),
svc.RoleService(buildRoleServiceMock()),
)
if err != nil {
log.Fatalf("Could not create new service")
}
@@ -493,7 +500,7 @@ func TestUpdateAccount(t *testing.T) {
GidNumber: 30001,
Mail: "एलिस@उदाहरण.com",
},
merrors.BadRequest(".", "preferred_name 'अद्भुत-एलिस' must be at least the local part of an email"),
merrors.BadRequest("com.owncloud.api.accounts", "preferred_name 'अद्भुत-एलिस' must be at least the local part of an email"),
},
{
"Update user with empty data values",
@@ -505,7 +512,7 @@ func TestUpdateAccount(t *testing.T) {
GidNumber: 0,
Mail: "",
},
merrors.BadRequest(".", "preferred_name '' must be at least the local part of an email"),
merrors.BadRequest("com.owncloud.api.accounts", "preferred_name '' must be at least the local part of an email"),
},
{
"Update user with strange data",
@@ -517,7 +524,7 @@ func TestUpdateAccount(t *testing.T) {
GidNumber: 1000,
Mail: "1.2@3.c_@",
},
merrors.BadRequest(".", "mail '1.2@3.c_@' must be a valid email"),
merrors.BadRequest("com.owncloud.api.accounts", "mail '1.2@3.c_@' must be a valid email"),
},
}

View File

@@ -0,0 +1,50 @@
package debug
import (
"context"
"github.com/owncloud/ocis/accounts/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
)
// Option defines a single option function.
type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
Logger log.Logger
Context context.Context
Config *config.Config
}
// newOptions initializes the available default options.
func newOptions(opts ...Option) Options {
opt := Options{}
for _, o := range opts {
o(&opt)
}
return opt
}
// Logger provides a function to set the logger option.
func Logger(val log.Logger) Option {
return func(o *Options) {
o.Logger = val
}
}
// Context provides a function to set the context option.
func Context(val context.Context) Option {
return func(o *Options) {
o.Context = val
}
}
// Config provides a function to set the config option.
func Config(val *config.Config) Option {
return func(o *Options) {
o.Config = val
}
}

View File

@@ -0,0 +1,63 @@
package debug
import (
"io"
"net/http"
"github.com/owncloud/ocis/accounts/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/service/debug"
"github.com/owncloud/ocis/ocis-pkg/version"
)
// Server initializes the debug service and server.
func Server(opts ...Option) (*http.Server, error) {
options := newOptions(opts...)
return debug.NewService(
debug.Logger(options.Logger),
debug.Name(options.Config.Service.Name),
debug.Version(version.String),
debug.Address(options.Config.Debug.Addr),
debug.Token(options.Config.Debug.Token),
debug.Pprof(options.Config.Debug.Pprof),
debug.Zpages(options.Config.Debug.Zpages),
debug.Health(health(options.Config)),
debug.Ready(ready(options.Config)),
debug.CorsAllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins),
debug.CorsAllowedMethods(options.Config.HTTP.CORS.AllowedMethods),
debug.CorsAllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders),
debug.CorsAllowCredentials(options.Config.HTTP.CORS.AllowCredentials),
), nil
}
// health implements the health check.
func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// TODO: check if services are up and running
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.
if err != nil {
panic(err)
}
}
}
// ready implements the ready check.
func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// TODO: check if services are up and running
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.
if err != nil {
panic(err)
}
}
}

View File

@@ -3,6 +3,7 @@ package grpc
import (
"github.com/owncloud/ocis/accounts/pkg/proto/v0"
"github.com/owncloud/ocis/ocis-pkg/service/grpc"
"github.com/owncloud/ocis/ocis-pkg/version"
)
// Server initializes a new go-micro service ready to run
@@ -11,13 +12,13 @@ func Server(opts ...Option) grpc.Service {
handler := options.Handler
service := grpc.NewService(
grpc.Name(options.Config.Server.Name),
grpc.Name(options.Config.Service.Name),
grpc.Context(options.Context),
grpc.Address(options.Config.GRPC.Addr),
grpc.Namespace(options.Config.GRPC.Namespace),
grpc.Logger(options.Logger),
grpc.Flags(options.Flags...),
grpc.Version(options.Config.Server.Version),
grpc.Version(version.String),
)
if err := proto.RegisterAccountsServiceHandler(service.Server(), handler); err != nil {

View File

@@ -21,7 +21,7 @@ func Server(opts ...Option) http.Service {
service := http.NewService(
http.Logger(options.Logger),
http.Name(options.Name),
http.Version(options.Config.Server.Version),
http.Version(version.String),
http.Address(options.Config.HTTP.Addr),
http.Namespace(options.Config.HTTP.Namespace),
http.Context(options.Context),

View File

@@ -381,7 +381,7 @@ func (s Service) CreateAccount(ctx context.Context, in *proto.CreateAccountReque
if out.PasswordProfile != nil {
if out.PasswordProfile.Password != "" {
// encrypt password
hashed, err := bcrypt.GenerateFromPassword([]byte(in.Account.PasswordProfile.Password), s.Config.Server.HashDifficulty)
hashed, err := bcrypt.GenerateFromPassword([]byte(in.Account.PasswordProfile.Password), s.Config.HashDifficulty)
if err != nil {
s.log.Error().Err(err).Str("id", id).Msg("could not hash password")
return merrors.InternalServerError(s.id, "could not hash password: %v", err.Error())
@@ -572,7 +572,7 @@ func (s Service) UpdateAccount(ctx context.Context, in *proto.UpdateAccountReque
}
if in.Account.PasswordProfile.Password != "" {
// encrypt password
hashed, err := bcrypt.GenerateFromPassword([]byte(in.Account.PasswordProfile.Password), s.Config.Server.HashDifficulty)
hashed, err := bcrypt.GenerateFromPassword([]byte(in.Account.PasswordProfile.Password), s.Config.HashDifficulty)
if err != nil {
in.Account.PasswordProfile.Password = ""
s.log.Error().Err(err).Str("id", id).Msg("could not hash password")

View File

@@ -31,8 +31,7 @@ var (
)
func init() {
cfg := config.New()
cfg.Server.Name = "accounts"
cfg := config.DefaultConfig()
cfg.Repo.Backend = "disk"
cfg.Repo.Disk.Path = dataPath
logger := olog.NewLogger(olog.Color(true), olog.Pretty(true))

View File

@@ -8,8 +8,6 @@ import (
"strings"
"time"
"github.com/owncloud/ocis/ocis-pkg/shared"
"github.com/pkg/errors"
"github.com/owncloud/ocis/ocis-pkg/service/grpc"
@@ -57,7 +55,7 @@ func New(opts ...Option) (s *Service, err error) {
}
s = &Service{
id: cfg.GRPC.Namespace + "." + cfg.Server.Name,
id: cfg.GRPC.Namespace + "." + cfg.Service.Name,
log: logger,
Config: cfg,
RoleService: roleService,
@@ -81,11 +79,11 @@ func New(opts ...Option) (s *Service, err error) {
return nil, err
}
if err = s.createDefaultAccounts(cfg.Server.DemoUsersAndGroups); err != nil {
if err = s.createDefaultAccounts(cfg.DemoUsersAndGroups); err != nil {
return nil, err
}
if err = s.createDefaultGroups(cfg.Server.DemoUsersAndGroups); err != nil {
if err = s.createDefaultGroups(cfg.DemoUsersAndGroups); err != nil {
return nil, err
}
return
@@ -112,7 +110,7 @@ func configFromSvc(cfg *config.Config) (*idxcfg.Config, error) {
c := idxcfg.New()
if cfg.Log == nil {
cfg.Log = &shared.Log{}
cfg.Log = &config.Log{}
}
defer func(cfg *config.Config) {

View File

@@ -14,7 +14,7 @@ var (
func Configure(cfg *config.Config) error {
var err error
if cfg.Tracing.Enabled {
if TraceProvider, err = pkgtrace.GetTraceProvider(cfg.Tracing.Endpoint, cfg.Tracing.Collector, "accounts", cfg.Tracing.Type); err != nil {
if TraceProvider, err = pkgtrace.GetTraceProvider(cfg.Tracing.Endpoint, cfg.Tracing.Collector, cfg.Service.Name, cfg.Tracing.Type); err != nil {
return err
}
}

View File

@@ -0,0 +1,7 @@
Change: Unify configuration and commands
We've unified the configuration and commands of all non storage services. This also
includes the change, that environment variables are now defined on the config struct
as tags instead in a separate mapping.
https://github.com/owncloud/ocis/pull/2818

View File

@@ -33,7 +33,7 @@ services:
- "certs:/certs"
labels:
- "traefik.enable=${TRAEFIK_DASHBOARD:-false}"
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$apr1$4vqie50r$YQAmQdtmz5n9rEALhxJ4l.}" # defaults to admin:admin
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$$apr1$$4vqie50r$$YQAmQdtmz5n9rEALhxJ4l.}" # defaults to admin:admin
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.rule=Host(`${TRAEFIK_DOMAIN:-traefik.owncloud.test}`)"
- "traefik.http.routers.traefik.middlewares=traefik-auth"

View File

@@ -32,7 +32,7 @@ services:
- "certs:/certs"
labels:
- "traefik.enable=${TRAEFIK_DASHBOARD:-false}"
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$apr1$4vqie50r$YQAmQdtmz5n9rEALhxJ4l.}" # defaults to admin:admin
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$$apr1$$4vqie50r$$YQAmQdtmz5n9rEALhxJ4l.}" # defaults to admin:admin
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.rule=Host(`${TRAEFIK_DOMAIN:-traefik.owncloud.test}`)"
- "traefik.http.routers.traefik.middlewares=traefik-auth"

View File

@@ -33,7 +33,7 @@ services:
- "certs:/certs"
labels:
- "traefik.enable=${TRAEFIK_DASHBOARD:-false}"
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$apr1$4vqie50r$YQAmQdtmz5n9rEALhxJ4l.}" # defaults to admin:admin
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$$apr1$$4vqie50r$$YQAmQdtmz5n9rEALhxJ4l.}" # defaults to admin:admin
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.rule=Host(`${TRAEFIK_DOMAIN:-traefik.owncloud.test}`)"
- "traefik.http.routers.traefik.middlewares=traefik-auth"

View File

@@ -32,7 +32,7 @@ services:
- "certs:/certs"
labels:
- "traefik.enable=${TRAEFIK_DASHBOARD:-false}"
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$apr1$4vqie50r$YQAmQdtmz5n9rEALhxJ4l.}" # defaults to admin:admin
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$$apr1$$4vqie50r$$YQAmQdtmz5n9rEALhxJ4l.}" # defaults to admin:admin
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.rule=Host(`${TRAEFIK_DOMAIN:-traefik.owncloud.test}`)"
- "traefik.http.routers.traefik.middlewares=traefik-auth"

View File

@@ -32,7 +32,7 @@ services:
- "certs:/certs"
labels:
- "traefik.enable=${TRAEFIK_DASHBOARD:-false}"
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$apr1$4vqie50r$YQAmQdtmz5n9rEALhxJ4l.}" # defaults to admin:admin
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$$apr1$$4vqie50r$$YQAmQdtmz5n9rEALhxJ4l.}" # defaults to admin:admin
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.rule=Host(`${TRAEFIK_DOMAIN:-traefik.owncloud.test}`)"
- "traefik.http.routers.traefik.middlewares=traefik-auth"

View File

@@ -32,7 +32,7 @@ services:
- "certs:/certs"
labels:
- "traefik.enable=${TRAEFIK_DASHBOARD:-false}"
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$apr1$4vqie50r$YQAmQdtmz5n9rEALhxJ4l.}" # defaults to admin:admin
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$$apr1$$4vqie50r$$YQAmQdtmz5n9rEALhxJ4l.}" # defaults to admin:admin
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.rule=Host(`${TRAEFIK_DOMAIN:-traefik.owncloud.test}`)"
- "traefik.http.routers.traefik.middlewares=traefik-auth"

View File

@@ -36,7 +36,7 @@ services:
- "certs:/certs"
labels:
- "traefik.enable=${TRAEFIK_DASHBOARD:-false}"
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$apr1$4vqie50r$YQAmQdtmz5n9rEALhxJ4l.}" # defaults to admin:admin
- "traefik.http.middlewares.traefik-auth.basicauth.users=${TRAEFIK_BASIC_AUTH_USERS:-admin:$$apr1$$4vqie50r$$YQAmQdtmz5n9rEALhxJ4l.}" # defaults to admin:admin
- "traefik.http.routers.traefik.entrypoints=https"
- "traefik.http.routers.traefik.rule=Host(`${TRAEFIK_DOMAIN:-traefik.owncloud.test}`)"
- "traefik.http.routers.traefik.middlewares=traefik-auth"

View File

@@ -19,7 +19,7 @@ In order to simplify deployments and development the configuration model from oC
## In-depth configuration
Since we include a set of predefined extensions within the single binary, configuring an extension can be done in a variety of ways. Since we work with complex types, having as many cli per config value scales poorly, so we limited the options to config files and environment variables, leaving cli flags for common values, such as logging (`--log-level`, `--log-pretty`, `--log-file` or `--log-color`).
Since we include a set of predefined extensions within the single binary, configuring an extension can be done in a variety of ways. Since we work with complex types, having as many cli per config value scales poorly, so we limited the options to config files and environment variables.
The hierarchy is clear enough, leaving us with:

View File

@@ -8,7 +8,7 @@ import (
)
func main() {
if err := command.Execute(config.New()); err != nil {
if err := command.Execute(config.DefaultConfig()); err != nil {
os.Exit(1)
}
}

View File

@@ -5,19 +5,22 @@ import (
"net/http"
"github.com/owncloud/ocis/glauth/pkg/config"
"github.com/owncloud/ocis/glauth/pkg/config/parser"
"github.com/owncloud/ocis/glauth/pkg/logging"
"github.com/urfave/cli/v2"
)
// Health is the entrypoint for the health command.
func Health(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "health",
Usage: "Check health status",
Name: "health",
Usage: "check health status",
Category: "info",
Before: func(c *cli.Context) error {
return ParseConfig(c, cfg)
return parser.ParseConfig(cfg)
},
Action: func(c *cli.Context) error {
logger := NewLogger(cfg)
logger := logging.Configure(cfg.Service.Name, cfg.Log)
resp, err := http.Get(
fmt.Sprintf(
@@ -34,7 +37,7 @@ func Health(cfg *config.Config) *cli.Command {
defer resp.Body.Close()
if resp.StatusCode != 200 {
if resp.StatusCode != http.StatusOK {
logger.Fatal().
Int("code", resp.StatusCode).
Msg("Health seems to be in bad state")

View File

@@ -5,81 +5,42 @@ import (
"os"
"github.com/owncloud/ocis/glauth/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/clihelper"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
oclog "github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/shared"
"github.com/owncloud/ocis/ocis-pkg/version"
"github.com/thejerf/suture/v4"
"github.com/urfave/cli/v2"
)
// GetCommands provides all commands for this service
func GetCommands(cfg *config.Config) cli.Commands {
return []*cli.Command{
// start this service
Server(cfg),
// interaction with this service
// infos about this service
Health(cfg),
Version(cfg),
}
}
// Execute is the entry point for the ocis-glauth command.
func Execute(cfg *config.Config) error {
app := &cli.App{
app := clihelper.DefaultApp(&cli.App{
Name: "ocis-glauth",
Version: version.String,
Usage: "Serve GLAuth API for oCIS",
Compiled: version.Compiled(),
Authors: []*cli.Author{
{
Name: "ownCloud GmbH",
Email: "support@owncloud.com",
},
},
Before: func(c *cli.Context) error {
cfg.Version = version.String
return nil
},
Commands: []*cli.Command{
Server(cfg),
Health(cfg),
},
}
Commands: GetCommands(cfg),
})
cli.HelpFlag = &cli.BoolFlag{
Name: "help,h",
Usage: "Show the help",
}
cli.VersionFlag = &cli.BoolFlag{
Name: "version,v",
Usage: "Print the version",
}
return app.Run(os.Args)
}
// NewLogger initializes a service-specific logger instance.
func NewLogger(cfg *config.Config) log.Logger {
return oclog.LoggerFromConfig("glauth", *cfg.Log)
}
// ParseConfig loads glauth configuration from known paths.
func ParseConfig(c *cli.Context, cfg *config.Config) error {
conf, err := ociscfg.BindSourcesToStructs("glauth", cfg)
if err != nil {
return err
}
// provide with defaults for shared logging, since we need a valid destination address for BindEnv.
if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
cfg.Log = &shared.Log{
Level: cfg.Commons.Log.Level,
Pretty: cfg.Commons.Log.Pretty,
Color: cfg.Commons.Log.Color,
File: cfg.Commons.Log.File,
}
} else if cfg.Log == nil && cfg.Commons == nil {
cfg.Log = &shared.Log{}
}
// load all env variables relevant to the config in the current context.
conf.LoadOSEnv(config.GetEnv(cfg), false)
bindings := config.StructMappings(cfg)
return ociscfg.BindEnv(conf, bindings)
}
// SutureService allows for the glauth command to be embedded and supervised by a suture supervisor tree.
type SutureService struct {
cfg *config.Config

View File

@@ -2,41 +2,37 @@ package command
import (
"context"
"strings"
"fmt"
glauthcfg "github.com/glauth/glauth/v2/pkg/config"
"github.com/oklog/run"
accounts "github.com/owncloud/ocis/accounts/pkg/proto/v0"
"github.com/owncloud/ocis/glauth/pkg/config"
"github.com/owncloud/ocis/glauth/pkg/config/parser"
"github.com/owncloud/ocis/glauth/pkg/logging"
"github.com/owncloud/ocis/glauth/pkg/metrics"
"github.com/owncloud/ocis/glauth/pkg/server/debug"
"github.com/owncloud/ocis/glauth/pkg/server/glauth"
"github.com/owncloud/ocis/glauth/pkg/tracing"
pkgcrypto "github.com/owncloud/ocis/ocis-pkg/crypto"
"github.com/owncloud/ocis/ocis-pkg/service/grpc"
"github.com/owncloud/ocis/ocis-pkg/version"
"github.com/urfave/cli/v2"
)
// Server is the entrypoint for the server command.
func Server(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "server",
Usage: "Start integrated server",
Before: func(ctx *cli.Context) error {
if cfg.HTTP.Root != "/" {
cfg.HTTP.Root = strings.TrimSuffix(cfg.HTTP.Root, "/")
}
if err := ParseConfig(ctx, cfg); err != nil {
return err
}
return nil
Name: "server",
Usage: fmt.Sprintf("start %s extension without runtime (unsupervised mode)", cfg.Service.Name),
Category: "server",
Before: func(c *cli.Context) error {
return parser.ParseConfig(cfg)
},
Action: func(c *cli.Context) error {
logger := NewLogger(cfg)
if err := tracing.Configure(cfg); err != nil {
logger := logging.Configure(cfg.Service.Name, cfg.Log)
err := tracing.Configure(cfg)
if err != nil {
return err
}
@@ -51,7 +47,7 @@ func Server(cfg *config.Config) *cli.Command {
defer cancel()
metrics.BuildInfo.WithLabelValues(cfg.Version).Set(1)
metrics.BuildInfo.WithLabelValues(version.String).Set(1)
{

View File

@@ -0,0 +1,50 @@
package command
import (
"fmt"
"os"
"github.com/owncloud/ocis/ocis-pkg/registry"
"github.com/owncloud/ocis/ocis-pkg/version"
tw "github.com/olekukonko/tablewriter"
"github.com/owncloud/ocis/glauth/pkg/config"
"github.com/urfave/cli/v2"
)
// Version prints the service versions of all running instances.
func Version(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "version",
Usage: "print the version of this binary and the running extension instances",
Category: "info",
Action: func(c *cli.Context) error {
fmt.Println("Version: " + version.String)
fmt.Printf("Compiled: %s\n", version.Compiled())
fmt.Println("")
reg := registry.GetRegistry()
services, err := reg.GetService(cfg.Ldap.Namespace + "." + cfg.Service.Name)
if err != nil {
fmt.Println(fmt.Errorf("could not get %s services from the registry: %v", cfg.Service.Name, err))
return err
}
if len(services) == 0 {
fmt.Println("No running " + cfg.Service.Name + " service found.")
return nil
}
table := tw.NewWriter(os.Stdout)
table.SetHeader([]string{"Version", "Address", "Id"})
table.SetAutoFormatHeaders(false)
for _, s := range services {
for _, n := range s.Nodes {
table.Append([]string{s.Version, n.Address, n.Id})
}
}
table.Render()
return nil
},
}
}

View File

@@ -2,49 +2,29 @@ package config
import (
"context"
"path"
"github.com/owncloud/ocis/ocis-pkg/shared"
"github.com/owncloud/ocis/ocis-pkg/config/defaults"
)
// Debug defines the available debug configuration.
type Debug struct {
Addr string `ocisConfig:"addr"`
Token string `ocisConfig:"token"`
Pprof bool `ocisConfig:"pprof"`
Zpages bool `ocisConfig:"zpages"`
}
// Config combines all available configuration parts.
type Config struct {
*shared.Commons
// HTTP defines the available http configuration.
type HTTP struct {
Addr string `ocisConfig:"addr"`
Namespace string `ocisConfig:"namespace"`
Root string `ocisConfig:"root"`
}
Service Service
// Tracing defines the available tracing configuration.
type Tracing struct {
Enabled bool `ocisConfig:"enabled"`
Type string `ocisConfig:"type"`
Endpoint string `ocisConfig:"endpoint"`
Collector string `ocisConfig:"collector"`
Service string `ocisConfig:"service"`
}
Tracing Tracing `ocisConfig:"tracing"`
Log *Log `ocisConfig:"log"`
Debug Debug `ocisConfig:"debug"`
// Ldap defined the available LDAP configuration.
type Ldap struct {
Enabled bool `ocisConfig:"enabled"`
Addr string `ocisConfig:"addr"`
}
Ldap Ldap `ocisConfig:"ldap"`
Ldaps Ldaps `ocisConfig:"ldaps"`
// Ldaps defined the available LDAPS configuration.
type Ldaps struct {
Addr string `ocisConfig:"addr"`
Enabled bool `ocisConfig:"enabled"`
Cert string `ocisConfig:"cert"`
Key string `ocisConfig:"key"`
Backend Backend `ocisConfig:"backend"`
Fallback FallbackBackend `ocisConfig:"fallback"`
RoleBundleUUID string `ocisConfig:"role_bundle_uuid" env:"GLAUTH_ROLE_BUNDLE_ID"`
Context context.Context
}
// Backend defined the available backend configuration.
@@ -59,71 +39,14 @@ type Backend struct {
UseGraphAPI bool `ocisConfig:"use_graph_api"`
}
// Config combines all available configuration parts.
type Config struct {
*shared.Commons
File string `ocisConfig:"file"`
Log *shared.Log `ocisConfig:"log"`
Debug Debug `ocisConfig:"debug"`
HTTP HTTP `ocisConfig:"http"`
Tracing Tracing `ocisConfig:"tracing"`
Ldap Ldap `ocisConfig:"ldap"`
Ldaps Ldaps `ocisConfig:"ldaps"`
Backend Backend `ocisConfig:"backend"`
Fallback Backend `ocisConfig:"fallback"`
Version string `ocisConfig:"version"`
RoleBundleUUID string `ocisConfig:"role_bundle_uuid"`
Context context.Context
Supervised bool
}
// New initializes a new configuration with or without defaults.
func New() *Config {
return &Config{}
}
func DefaultConfig() *Config {
return &Config{
Debug: Debug{
Addr: "127.0.0.1:9129",
},
HTTP: HTTP{},
Tracing: Tracing{
Type: "jaeger",
Service: "glauth",
},
Ldap: Ldap{
Enabled: true,
Addr: "127.0.0.1:9125",
},
Ldaps: Ldaps{
Addr: "127.0.0.1:9126",
Enabled: true,
Cert: path.Join(defaults.BaseDataPath(), "ldap", "ldap.crt"),
Key: path.Join(defaults.BaseDataPath(), "ldap", "ldap.key"),
},
Backend: Backend{
Datastore: "accounts",
BaseDN: "dc=ocis,dc=test",
Insecure: false,
NameFormat: "cn",
GroupFormat: "ou",
Servers: nil,
SSHKeyAttr: "sshPublicKey",
UseGraphAPI: true,
},
Fallback: Backend{
Datastore: "",
BaseDN: "dc=ocis,dc=test",
Insecure: false,
NameFormat: "cn",
GroupFormat: "ou",
Servers: nil,
SSHKeyAttr: "sshPublicKey",
UseGraphAPI: true,
},
RoleBundleUUID: "71881883-1768-46bd-a24d-a356a2afdf7f", // BundleUUIDRoleAdmin
}
// FallbackBackend defined the available fallback backend configuration.
type FallbackBackend struct {
Datastore string `ocisConfig:"datastore"`
BaseDN string `ocisConfig:"base_dn"`
Insecure bool `ocisConfig:"insecure"`
NameFormat string `ocisConfig:"name_format"`
GroupFormat string `ocisConfig:"group_format"`
Servers []string `ocisConfig:"servers"`
SSHKeyAttr string `ocisConfig:"ssh_key_attr"`
UseGraphAPI bool `ocisConfig:"use_graph_api"`
}

View File

@@ -0,0 +1,9 @@
package config
// Debug defines the available debug configuration.
type Debug struct {
Addr string `ocisConfig:"addr" env:"GLAUTH_DEBUG_ADDR"`
Token string `ocisConfig:"token" env:"GLAUTH_DEBUG_TOKEN"`
Pprof bool `ocisConfig:"pprof" env:"GLAUTH_DEBUG_PPROF"`
Zpages bool `ocisConfig:"zpages" env:"GLAUTH_DEBUG_ZPAGES"`
}

View File

@@ -0,0 +1,57 @@
package config
import (
"path"
"github.com/owncloud/ocis/ocis-pkg/config/defaults"
)
func DefaultConfig() *Config {
return &Config{
Debug: Debug{
Addr: "127.0.0.1:9129",
},
Tracing: Tracing{
Enabled: false,
Type: "jaeger",
Endpoint: "",
Collector: "",
},
Service: Service{
Name: "glauth",
},
Ldap: Ldap{
Enabled: true,
Addr: "127.0.0.1:9125",
Namespace: "com.owncloud.ldap",
},
Ldaps: Ldaps{
Enabled: true,
Addr: "127.0.0.1:9126",
Namespace: "com.owncloud.ldaps",
Cert: path.Join(defaults.BaseDataPath(), "ldap", "ldap.crt"),
Key: path.Join(defaults.BaseDataPath(), "ldap", "ldap.key"),
},
Backend: Backend{
Datastore: "accounts",
BaseDN: "dc=ocis,dc=test",
Insecure: false,
NameFormat: "cn",
GroupFormat: "ou",
Servers: nil,
SSHKeyAttr: "sshPublicKey",
UseGraphAPI: true,
},
Fallback: FallbackBackend{
Datastore: "",
BaseDN: "dc=ocis,dc=test",
Insecure: false,
NameFormat: "cn",
GroupFormat: "ou",
Servers: nil,
SSHKeyAttr: "sshPublicKey",
UseGraphAPI: true,
},
RoleBundleUUID: "71881883-1768-46bd-a24d-a356a2afdf7f", // BundleUUIDRoleAdmin
}
}

View File

@@ -0,0 +1,8 @@
package config
// Ldap defines the available LDAP configuration.
type Ldap struct {
Enabled bool `ocisConfig:"enabled" env:"GLAUTH_LDAP_ENABLED"`
Addr string `ocisConfig:"addr" env:"GLAUTH_LDAP_ADDR"`
Namespace string
}

View File

@@ -0,0 +1,10 @@
package config
// Ldaps defined the available LDAPS configuration.
type Ldaps struct {
Enabled bool `ocisConfig:"enabled" env:"GLAUTH_LDAPS_ENABLED"`
Addr string `ocisConfig:"addr" env:"GLAUTH_LDAPS_ADDR"`
Namespace string
Cert string `ocisConfig:"cert" env:"GLAUTH_LDAPS_CERT"`
Key string `ocisConfig:"key" env:"GLAUTH_LDAPS_KEY"`
}

9
glauth/pkg/config/log.go Normal file
View File

@@ -0,0 +1,9 @@
package config
// Log defines the available log configuration.
type Log struct {
Level string `mapstructure:"level" env:"OCIS_LOG_LEVEL;GLAUTH_LOG_LEVEL"`
Pretty bool `mapstructure:"pretty" env:"OCIS_LOG_PRETTY;GLAUTH_LOG_PRETTY"`
Color bool `mapstructure:"color" env:"OCIS_LOG_COLOR;GLAUTH_LOG_COLOR"`
File string `mapstructure:"file" env:"OCIS_LOG_FILE;GLAUTH_LOG_FILE"`
}

View File

@@ -1,167 +0,0 @@
package config
import "github.com/owncloud/ocis/ocis-pkg/shared"
// GetEnv fetches a list of known env variables for this extension. It is to be used by gookit, as it provides a list
// with all the environment variables an extension supports.
func GetEnv(cfg *Config) []string {
var r = make([]string, len(structMappings(cfg)))
for i := range structMappings(cfg) {
r = append(r, structMappings(cfg)[i].EnvVars...)
}
return r
}
// StructMappings binds a set of environment variables to a destination on cfg. Iterating over this set and editing the
// Destination value of a binding will alter the original value, as it is a pointer to its memory address. This lets
// us propagate changes easier.
func StructMappings(cfg *Config) []shared.EnvBinding {
return structMappings(cfg)
}
// structMappings binds a set of environment variables to a destination on cfg.
func structMappings(cfg *Config) []shared.EnvBinding {
return []shared.EnvBinding{
{
EnvVars: []string{"OCIS_LOG_LEVEL", "GLAUTH_LOG_LEVEL"},
Destination: &cfg.Log.Level,
},
{
EnvVars: []string{"OCIS_LOG_PRETTY", "GLAUTH_LOG_PRETTY"},
Destination: &cfg.Log.Pretty,
},
{
EnvVars: []string{"OCIS_LOG_COLOR", "GLAUTH_LOG_COLOR"},
Destination: &cfg.Log.Color,
},
{
EnvVars: []string{"OCIS_LOG_FILE", "GLAUTH_LOG_FILE"},
Destination: &cfg.Log.File,
},
{
EnvVars: []string{"GLAUTH_CONFIG_FILE"},
Destination: &cfg.File,
},
{
EnvVars: []string{"OCIS_TRACING_ENABLED", "GLAUTH_TRACING_ENABLED"},
Destination: &cfg.Tracing.Enabled,
},
{
EnvVars: []string{"OCIS_TRACING_TYPE", "GLAUTH_TRACING_TYPE"},
Destination: &cfg.Tracing.Type,
},
{
EnvVars: []string{"OCIS_TRACING_ENDPOINT", "GLAUTH_TRACING_ENDPOINT"},
Destination: &cfg.Tracing.Endpoint,
},
{
EnvVars: []string{"OCIS_TRACING_COLLECTOR", "GLAUTH_TRACING_COLLECTOR"},
Destination: &cfg.Tracing.Collector,
},
{
EnvVars: []string{"GLAUTH_TRACING_SERVICE"},
Destination: &cfg.Tracing.Service,
},
{
EnvVars: []string{"GLAUTH_DEBUG_ADDR"},
Destination: &cfg.Debug.Addr,
},
{
EnvVars: []string{"GLAUTH_DEBUG_TOKEN"},
Destination: &cfg.Debug.Token,
},
{
EnvVars: []string{"GLAUTH_DEBUG_PPROF"},
Destination: &cfg.Debug.Pprof,
},
{
EnvVars: []string{"GLAUTH_DEBUG_ZPAGES"},
Destination: &cfg.Debug.Zpages,
},
{
EnvVars: []string{"GLAUTH_ROLE_BUNDLE_ID"},
Destination: &cfg.RoleBundleUUID,
},
{
EnvVars: []string{"GLAUTH_LDAP_ADDR"},
Destination: &cfg.Ldap.Addr,
},
{
EnvVars: []string{"GLAUTH_LDAP_ENABLED"},
Destination: &cfg.Ldap.Enabled,
},
{
EnvVars: []string{"GLAUTH_LDAPS_ADDR"},
Destination: &cfg.Ldaps.Addr,
},
{
EnvVars: []string{"GLAUTH_LDAPS_ENABLED"},
Destination: &cfg.Ldaps.Enabled,
},
{
EnvVars: []string{"GLAUTH_LDAPS_CERT"},
Destination: &cfg.Ldaps.Cert,
},
{
EnvVars: []string{"GLAUTH_LDAPS_KEY"},
Destination: &cfg.Ldaps.Key,
},
{
EnvVars: []string{"GLAUTH_BACKEND_BASEDN"},
Destination: &cfg.Backend.BaseDN,
},
{
EnvVars: []string{"GLAUTH_BACKEND_NAME_FORMAT"},
Destination: &cfg.Backend.NameFormat,
},
{
EnvVars: []string{"GLAUTH_BACKEND_GROUP_FORMAT"},
Destination: &cfg.Backend.GroupFormat,
},
{
EnvVars: []string{"GLAUTH_BACKEND_SSH_KEY_ATTR"},
Destination: &cfg.Backend.SSHKeyAttr,
},
{
EnvVars: []string{"GLAUTH_BACKEND_DATASTORE"},
Destination: &cfg.Backend.Datastore,
},
{
EnvVars: []string{"GLAUTH_BACKEND_INSECURE"},
Destination: &cfg.Backend.Insecure,
},
{
EnvVars: []string{"GLAUTH_BACKEND_USE_GRAPHAPI"},
Destination: &cfg.Backend.UseGraphAPI,
},
{
EnvVars: []string{"GLAUTH_FALLBACK_BASEDN"},
Destination: &cfg.Fallback.BaseDN,
},
{
EnvVars: []string{"GLAUTH_FALLBACK_NAME_FORMAT"},
Destination: &cfg.Fallback.NameFormat,
},
{
EnvVars: []string{"GLAUTH_FALLBACK_GROUP_FORMAT"},
Destination: &cfg.Fallback.GroupFormat,
},
{
EnvVars: []string{"GLAUTH_FALLBACK_SSH_KEY_ATTR"},
Destination: &cfg.Fallback.SSHKeyAttr,
},
{
EnvVars: []string{"GLAUTH_FALLBACK_DATASTORE"},
Destination: &cfg.Fallback.Datastore,
},
{
EnvVars: []string{"GLAUTH_FALLBACK_INSECURE"},
Destination: &cfg.Fallback.Insecure,
},
{
EnvVars: []string{"GLAUTH_FALLBACK_USE_GRAPHAPI"},
Destination: &cfg.Fallback.UseGraphAPI,
},
}
}

View File

@@ -0,0 +1,42 @@
package parser
import (
"errors"
"github.com/owncloud/ocis/glauth/pkg/config"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/config/envdecode"
)
// ParseConfig loads accounts configuration from known paths.
func ParseConfig(cfg *config.Config) error {
_, err := ociscfg.BindSourcesToStructs(cfg.Service.Name, cfg)
if err != nil {
return err
}
// provide with defaults for shared logging, since we need a valid destination address for BindEnv.
if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
cfg.Log = &config.Log{
Level: cfg.Commons.Log.Level,
Pretty: cfg.Commons.Log.Pretty,
Color: cfg.Commons.Log.Color,
File: cfg.Commons.Log.File,
}
} else if cfg.Log == nil && cfg.Commons == nil {
cfg.Log = &config.Log{}
}
// load all env variables relevant to the config in the current context.
if err := envdecode.Decode(cfg); err != nil {
// no environment variable set for this config is an expected "error"
if !errors.Is(err, envdecode.ErrNoTargetFieldsAreSet) {
return err
}
}
// sanitize config
return nil
}

View File

@@ -0,0 +1,6 @@
package config
// Service defines the available service configuration.
type Service struct {
Name string
}

View File

@@ -0,0 +1,9 @@
package config
// Tracing defines the available tracing configuration.
type Tracing struct {
Enabled bool `ocisConfig:"enabled" env:"OCIS_TRACING_ENABLED;GLAUTH_TRACING_ENABLED"`
Type string `ocisConfig:"type" env:"OCIS_TRACING_TYPE;GLAUTH_TRACING_TYPE"`
Endpoint string `ocisConfig:"endpoint" env:"OCIS_TRACING_ENDPOINT;GLAUTH_TRACING_ENDPOINT"`
Collector string `ocisConfig:"collector" env:"OCIS_TRACING_COLLECTOR;GLAUTH_TRACING_COLLECTOR"`
}

View File

@@ -0,0 +1,17 @@
package logging
import (
"github.com/owncloud/ocis/glauth/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
)
// LoggerFromConfig initializes a service-specific logger instance.
func Configure(name string, cfg *config.Log) log.Logger {
return log.NewLogger(
log.Name(name),
log.Level(cfg.Level),
log.Pretty(cfg.Pretty),
log.Color(cfg.Color),
log.File(cfg.File),
)
}

View File

@@ -15,7 +15,7 @@ func Server(opts ...Option) (*http.Server, error) {
return debug.NewService(
debug.Logger(options.Logger),
debug.Name("glauth"),
debug.Name(options.Config.Service.Name),
debug.Version(version.String),
debug.Address(options.Config.Debug.Addr),
debug.Token(options.Config.Debug.Token),
@@ -32,7 +32,7 @@ func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// TODO(tboerger): check if services are up and running
// TODO: check if services are up and running
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.
@@ -48,7 +48,7 @@ func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// TODO(tboerger): check if services are up and running
// TODO: check if services are up and running
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.

View File

@@ -14,7 +14,7 @@ var (
func Configure(cfg *config.Config) error {
var err error
if cfg.Tracing.Enabled {
if TraceProvider, err = pkgtrace.GetTraceProvider(cfg.Tracing.Endpoint, cfg.Tracing.Collector, "glauth", cfg.Tracing.Type); err != nil {
if TraceProvider, err = pkgtrace.GetTraceProvider(cfg.Tracing.Endpoint, cfg.Tracing.Collector, cfg.Service.Name, cfg.Tracing.Type); err != nil {
return err
}
}

View File

@@ -5,19 +5,22 @@ import (
"net/http"
"github.com/owncloud/ocis/graph-explorer/pkg/config"
"github.com/owncloud/ocis/graph-explorer/pkg/config/parser"
"github.com/owncloud/ocis/graph-explorer/pkg/logging"
"github.com/urfave/cli/v2"
)
// Health is the entrypoint for the health command.
func Health(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "health",
Usage: "Check health status",
Name: "health",
Usage: "check health status",
Category: "info",
Before: func(c *cli.Context) error {
return ParseConfig(c, cfg)
return parser.ParseConfig(cfg)
},
Action: func(c *cli.Context) error {
logger := NewLogger(cfg)
logger := logging.Configure(cfg.Service.Name, cfg.Log)
resp, err := http.Get(
fmt.Sprintf(
@@ -34,7 +37,7 @@ func Health(cfg *config.Config) *cli.Command {
defer resp.Body.Close()
if resp.StatusCode != 200 {
if resp.StatusCode != http.StatusOK {
logger.Fatal().
Int("code", resp.StatusCode).
Msg("Health seems to be in bad state")

View File

@@ -5,70 +5,42 @@ import (
"os"
"github.com/owncloud/ocis/graph-explorer/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/clihelper"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/version"
"github.com/thejerf/suture/v4"
"github.com/urfave/cli/v2"
)
// GetCommands provides all commands for this service
func GetCommands(cfg *config.Config) cli.Commands {
return []*cli.Command{
// start this service
Server(cfg),
// interaction with this service
// infos about this service
Health(cfg),
Version(cfg),
}
}
// Execute is the entry point for the graph-explorer command.
func Execute(cfg *config.Config) error {
app := &cli.App{
app := clihelper.DefaultApp(&cli.App{
Name: "graph-explorer",
Version: version.String,
Usage: "Serve Graph-Explorer for oCIS",
Compiled: version.Compiled(),
Authors: []*cli.Author{
{
Name: "ownCloud GmbH",
Email: "support@owncloud.com",
},
},
Before: func(c *cli.Context) error {
cfg.Server.Version = version.String
return ParseConfig(c, cfg)
},
Commands: []*cli.Command{
Server(cfg),
Health(cfg),
},
}
Commands: GetCommands(cfg),
})
cli.HelpFlag = &cli.BoolFlag{
Name: "help,h",
Usage: "Show the help",
}
cli.VersionFlag = &cli.BoolFlag{
Name: "version,v",
Usage: "Print the version",
}
return app.Run(os.Args)
}
// NewLogger initializes a service-specific logger instance.
func NewLogger(cfg *config.Config) log.Logger {
return log.NewLogger(
log.Name("graph-explorer"),
log.Level(cfg.Log.Level),
log.Pretty(cfg.Log.Pretty),
log.Color(cfg.Log.Color),
log.File(cfg.Log.File),
)
}
// ParseConfig loads graph configuration from known paths.
func ParseConfig(c *cli.Context, cfg *config.Config) error {
conf, err := ociscfg.BindSourcesToStructs("graph-explorer", cfg)
if err != nil {
return err
}
conf.LoadOSEnv(config.GetEnv(), false)
bindings := config.StructMappings(cfg)
return ociscfg.BindEnv(conf, bindings)
}
// SutureService allows for the graph-explorer command to be embedded and supervised by a suture supervisor tree.
type SutureService struct {
cfg *config.Config
@@ -76,7 +48,7 @@ type SutureService struct {
// NewSutureService creates a new graph-explorer.SutureService
func NewSutureService(cfg *ociscfg.Config) suture.Service {
cfg.GraphExplorer.Log = cfg.Log
cfg.GraphExplorer.Commons = cfg.Commons
return SutureService{
cfg: cfg.GraphExplorer,
}

View File

@@ -2,33 +2,35 @@ package command
import (
"context"
"strings"
"fmt"
"github.com/oklog/run"
"github.com/owncloud/ocis/graph-explorer/pkg/config"
"github.com/owncloud/ocis/graph-explorer/pkg/config/parser"
"github.com/owncloud/ocis/graph-explorer/pkg/logging"
"github.com/owncloud/ocis/graph-explorer/pkg/metrics"
"github.com/owncloud/ocis/graph-explorer/pkg/server/debug"
"github.com/owncloud/ocis/graph-explorer/pkg/server/http"
"github.com/owncloud/ocis/graph-explorer/pkg/tracing"
"github.com/owncloud/ocis/ocis-pkg/version"
"github.com/urfave/cli/v2"
)
// Server is the entrypoint for the server command.
func Server(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "server",
Usage: "Start integrated server",
Name: "server",
Usage: fmt.Sprintf("start %s extension without runtime (unsupervised mode)", cfg.Service.Name),
Category: "server",
Before: func(ctx *cli.Context) error {
if cfg.HTTP.Root != "/" {
cfg.HTTP.Root = strings.TrimSuffix(cfg.HTTP.Root, "/")
}
return ParseConfig(ctx, cfg)
return parser.ParseConfig(cfg)
},
Action: func(c *cli.Context) error {
logger := NewLogger(cfg)
tracing.Configure(cfg)
logger := logging.Configure(cfg.Service.Name, cfg.Log)
err := tracing.Configure(cfg)
if err != nil {
return err
}
var (
gr = run.Group{}
ctx, cancel = func() (context.Context, context.CancelFunc) {
@@ -42,7 +44,7 @@ func Server(cfg *config.Config) *cli.Command {
defer cancel()
mtrcs.BuildInfo.WithLabelValues(cfg.Server.Version).Set(1)
mtrcs.BuildInfo.WithLabelValues(version.String).Set(1)
{
server, err := http.Server(

View File

@@ -0,0 +1,50 @@
package command
import (
"fmt"
"os"
"github.com/owncloud/ocis/ocis-pkg/registry"
"github.com/owncloud/ocis/ocis-pkg/version"
tw "github.com/olekukonko/tablewriter"
"github.com/owncloud/ocis/graph-explorer/pkg/config"
"github.com/urfave/cli/v2"
)
// Version prints the service versions of all running instances.
func Version(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "version",
Usage: "print the version of this binary and the running extension instances",
Category: "info",
Action: func(c *cli.Context) error {
fmt.Println("Version: " + version.String)
fmt.Printf("Compiled: %s\n", version.Compiled())
fmt.Println("")
reg := registry.GetRegistry()
services, err := reg.GetService(cfg.HTTP.Namespace + "." + cfg.Service.Name)
if err != nil {
fmt.Println(fmt.Errorf("could not get %s services from the registry: %v", cfg.Service.Name, err))
return err
}
if len(services) == 0 {
fmt.Println("No running " + cfg.Service.Name + " service found.")
return nil
}
table := tw.NewWriter(os.Stdout)
table.SetHeader([]string{"Version", "Address", "Id"})
table.SetAutoFormatHeaders(false)
for _, s := range services {
for _, n := range s.Nodes {
table.Append([]string{s.Version, n.Address, n.Id})
}
}
table.Render()
return nil
},
}
}

View File

@@ -6,101 +6,27 @@ import (
"github.com/owncloud/ocis/ocis-pkg/shared"
)
// Debug defines the available debug configuration.
type Debug struct {
Addr string `ocisConfig:"addr"`
Token string `ocisConfig:"token"`
Pprof bool `ocisConfig:"pprof"`
Zpages bool `ocisConfig:"zpages"`
}
// Config combines all available configuration parts.
type Config struct {
*shared.Commons
// HTTP defines the available http configuration.
type HTTP struct {
Addr string `ocisConfig:"addr"`
Root string `ocisConfig:"root"`
Namespace string `ocisConfig:"namespace"`
}
Service Service
// Server configures a server.
type Server struct {
Version string `ocisConfig:"version"`
Name string `ocisConfig:"name"`
}
Tracing Tracing `ocisConfig:"tracing"`
Log *Log `ocisConfig:"log"`
Debug Debug `ocisConfig:"debug"`
// Tracing defines the available tracing configuration.
type Tracing struct {
Enabled bool `ocisConfig:"enabled"`
Type string `ocisConfig:"type"`
Endpoint string `ocisConfig:"endpoint"`
Collector string `ocisConfig:"collector"`
Service string `ocisConfig:"service"`
HTTP HTTP `ocisConfig:"http"`
GraphExplorer GraphExplorer `ocisConfig:"graph_explorer"`
Context context.Context
}
// GraphExplorer defines the available graph-explorer configuration.
type GraphExplorer struct {
ClientID string `ocisConfig:"client_id"`
Issuer string `ocisConfig:"issuer"`
GraphURLBase string `ocisConfig:"graph_url_base"`
GraphURLPath string `ocisConfig:"graph_url_path"`
}
// Config combines all available configuration parts.
type Config struct {
File string `ocisConfig:"file"`
Log shared.Log `ocisConfig:"log"`
Debug Debug `ocisConfig:"debug"`
HTTP HTTP `ocisConfig:"http"`
Server Server `ocisConfig:"server"`
Tracing Tracing `ocisConfig:"tracing"`
GraphExplorer GraphExplorer `ocisConfig:"graph_explorer"`
Context context.Context
Supervised bool
}
// New initializes a new configuration with or without defaults.
func New() *Config {
return &Config{}
}
// DefaultConfig provides with a working version of a config.
func DefaultConfig() *Config {
return &Config{
Log: shared.Log{},
Debug: Debug{
Addr: "127.0.0.1:9136",
Token: "",
Pprof: false,
Zpages: false,
},
HTTP: HTTP{
Addr: "127.0.0.1:9135",
Root: "/graph-explorer",
Namespace: "com.owncloud.web",
},
Server: Server{},
Tracing: Tracing{
Type: "jaeger",
Endpoint: "",
Collector: "",
Service: "graph-explorer",
},
GraphExplorer: GraphExplorer{
ClientID: "ocis-explorer.js",
Issuer: "https://localhost:9200",
GraphURLBase: "https://localhost:9200",
GraphURLPath: "/graph",
},
}
}
// GetEnv fetches a list of known env variables for this extension. It is to be used by gookit, as it provides a list
// with all the environment variables an extension supports.
func GetEnv() []string {
var r = make([]string, len(structMappings(&Config{})))
for i := range structMappings(&Config{}) {
r = append(r, structMappings(&Config{})[i].EnvVars...)
}
return r
ClientID string `ocisConfig:"client_id" env:"GRAPH_EXPLORER_CLIENT_ID"`
Issuer string `ocisConfig:"issuer" env:"OCIS_URL;GRAPH_EXPLORER_ISSUER"`
GraphURLBase string `ocisConfig:"graph_url_base" env:"OCIS_URL;GRAPH_EXPLORER_GRAPH_URL_BASE"`
GraphURLPath string `ocisConfig:"graph_url_path" env:"GRAPH_EXPLORER_GRAPH_URL_PATH"`
}

View File

@@ -0,0 +1,9 @@
package config
// Debug defines the available debug configuration.
type Debug struct {
Addr string `ocisConfig:"addr" env:"GRAPH_EXPLORER_DEBUG_ADDR"`
Token string `ocisConfig:"token" env:"GRAPH_EXPLORER_DEBUG_TOKEN"`
Pprof bool `ocisConfig:"pprof" env:"GRAPH_EXPLORER_DEBUG_PPROF"`
Zpages bool `ocisConfig:"zpages" env:"GRAPH_EXPLORER_DEBUG_ZPAGES"`
}

View File

@@ -0,0 +1,32 @@
package config
func DefaultConfig() *Config {
return &Config{
Debug: Debug{
Addr: "127.0.0.1:9136",
Token: "",
Pprof: false,
Zpages: false,
},
HTTP: HTTP{
Addr: "127.0.0.1:9135",
Root: "/graph-explorer",
Namespace: "com.owncloud.web",
},
Service: Service{
Name: "graph-explorer",
},
Tracing: Tracing{
Enabled: false,
Type: "jaeger",
Endpoint: "",
Collector: "",
},
GraphExplorer: GraphExplorer{
ClientID: "ocis-explorer.js",
Issuer: "https://localhost:9200",
GraphURLBase: "https://localhost:9200",
GraphURLPath: "/graph",
},
}
}

View File

@@ -0,0 +1,16 @@
package config
// HTTP defines the available http configuration.
type HTTP struct {
Addr string `ocisConfig:"addr" env:"GRAPH_EXPLORER_HTTP_ADDR"`
Root string `ocisConfig:"root" env:"GRAPH_EXPLORER_HTTP_ROOT"`
Namespace string
}
// CORS defines the available cors configuration.
type CORS struct {
AllowedOrigins []string `ocisConfig:"allowed_origins"`
AllowedMethods []string `ocisConfig:"allowed_methods"`
AllowedHeaders []string `ocisConfig:"allowed_headers"`
AllowCredentials bool `ocisConfig:"allowed_credentials"`
}

View File

@@ -0,0 +1,9 @@
package config
// Log defines the available log configuration.
type Log struct {
Level string `mapstructure:"level" env:"OCIS_LOG_LEVEL;GRAPH_EXPLORER_LOG_LEVEL"`
Pretty bool `mapstructure:"pretty" env:"OCIS_LOG_PRETTY;GRAPH_EXPLORER_LOG_PRETTY"`
Color bool `mapstructure:"color" env:"OCIS_LOG_COLOR;GRAPH_EXPLORER_LOG_COLOR"`
File string `mapstructure:"file" env:"OCIS_LOG_FILE;GRAPH_EXPLORER_LOG_FILE"`
}

View File

@@ -1,96 +0,0 @@
package config
import "github.com/owncloud/ocis/ocis-pkg/shared"
// StructMappings binds a set of environment variables to a destination on cfg. Iterating over this set and editing the
// Destination value of a binding will alter the original value, as it is a pointer to its memory address. This lets
// us propagate changes easier.
func StructMappings(cfg *Config) []shared.EnvBinding {
return structMappings(cfg)
}
// structMappings binds a set of environment variables to a destination on cfg.
func structMappings(cfg *Config) []shared.EnvBinding {
return []shared.EnvBinding{
{
EnvVars: []string{"OCIS_LOG_LEVEL", "GRAPH_EXPLORER_LOG_LEVEL"},
Destination: &cfg.Log.Level,
},
{
EnvVars: []string{"OCIS_LOG_PRETTY", "GRAPH_EXPLORER_LOG_PRETTY"},
Destination: &cfg.Log.Pretty,
},
{
EnvVars: []string{"OCIS_LOG_COLOR", "GRAPH_EXPLORER_LOG_COLOR"},
Destination: &cfg.Log.Color,
},
{
EnvVars: []string{"OCIS_LOG_FILE", "GRAPH_EXPLORER_LOG_FILE"},
Destination: &cfg.Log.File,
},
{
EnvVars: []string{"OCIS_TRACING_ENABLED", "GRAPH_EXPLORER_TRACING_ENABLED"},
Destination: &cfg.Tracing.Enabled,
},
{
EnvVars: []string{"OCIS_TRACING_TYPE", "GRAPH_EXPLORER_TRACING_TYPE"},
Destination: &cfg.Tracing.Type,
},
{
EnvVars: []string{"OCIS_TRACING_ENDPOINT", "GRAPH_EXPLORER_TRACING_ENDPOINT"},
Destination: &cfg.Tracing.Endpoint,
},
{
EnvVars: []string{"OCIS_TRACING_COLLECTOR", "GRAPH_EXPLORER_TRACING_COLLECTOR"},
Destination: &cfg.Tracing.Collector,
},
{
EnvVars: []string{"GRAPH_EXPLORER_TRACING_SERVICE"},
Destination: &cfg.Tracing.Service,
},
{
EnvVars: []string{"GRAPH_EXPLORER_DEBUG_ADDR"},
Destination: &cfg.Debug.Addr,
},
{
EnvVars: []string{"GRAPH_EXPLORER_DEBUG_TOKEN"},
Destination: &cfg.Debug.Token,
},
{
EnvVars: []string{"GRAPH_EXPLORER_DEBUG_PPROF"},
Destination: &cfg.Debug.Pprof,
},
{
EnvVars: []string{"GRAPH_EXPLORER_DEBUG_ZPAGES"},
Destination: &cfg.Debug.Zpages,
},
{
EnvVars: []string{"GRAPH_EXPLORER_HTTP_ADDR"},
Destination: &cfg.HTTP.Addr,
},
{
EnvVars: []string{"GRAPH_EXPLORER_HTTP_ROOT"},
Destination: &cfg.HTTP.Root,
},
{
EnvVars: []string{"GRAPH_EXPLORER_NAMESPACE"},
Destination: &cfg.HTTP.Namespace,
},
{
EnvVars: []string{"OCIS_URL", "GRAPH_EXPLORER_ISSUER"},
Destination: &cfg.GraphExplorer.Issuer,
},
{
EnvVars: []string{"GRAPH_EXPLORER_CLIENT_ID"},
Destination: &cfg.GraphExplorer.ClientID,
},
{
EnvVars: []string{"OCIS_URL", "GRAPH_EXPLORER_GRAPH_URL_BASE"},
Destination: &cfg.GraphExplorer.GraphURLBase,
},
{
EnvVars: []string{"GRAPH_EXPLORER_GRAPH_URL_PATH"},
Destination: &cfg.GraphExplorer.GraphURLPath,
},
}
}

View File

@@ -0,0 +1,46 @@
package parser
import (
"errors"
"strings"
"github.com/owncloud/ocis/graph-explorer/pkg/config"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/config/envdecode"
)
// ParseConfig loads accounts configuration from known paths.
func ParseConfig(cfg *config.Config) error {
_, err := ociscfg.BindSourcesToStructs(cfg.Service.Name, cfg)
if err != nil {
return err
}
// provide with defaults for shared logging, since we need a valid destination address for BindEnv.
if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
cfg.Log = &config.Log{
Level: cfg.Commons.Log.Level,
Pretty: cfg.Commons.Log.Pretty,
Color: cfg.Commons.Log.Color,
File: cfg.Commons.Log.File,
}
} else if cfg.Log == nil && cfg.Commons == nil {
cfg.Log = &config.Log{}
}
// load all env variables relevant to the config in the current context.
if err := envdecode.Decode(cfg); err != nil {
// no environment variable set for this config is an expected "error"
if !errors.Is(err, envdecode.ErrNoTargetFieldsAreSet) {
return err
}
}
// sanitize config
if cfg.HTTP.Root != "/" {
cfg.HTTP.Root = strings.TrimSuffix(cfg.HTTP.Root, "/")
}
return nil
}

View File

@@ -0,0 +1,6 @@
package config
// Service defines the available service configuration.
type Service struct {
Name string
}

View File

@@ -0,0 +1,9 @@
package config
// Tracing defines the available tracing configuration.
type Tracing struct {
Enabled bool `ocisConfig:"enabled" env:"OCIS_TRACING_ENABLED;GRAPH_EXPLORER_TRACING_ENABLED"`
Type string `ocisConfig:"type" env:"OCIS_TRACING_TYPE;GRAPH_EXPLORER_TRACING_TYPE"`
Endpoint string `ocisConfig:"endpoint" env:"OCIS_TRACING_ENDPOINT;GRAPH_EXPLORER_TRACING_ENDPOINT"`
Collector string `ocisConfig:"collector" env:"OCIS_TRACING_COLLECTOR;GRAPH_EXPLORER_TRACING_COLLECTOR"`
}

View File

@@ -0,0 +1,17 @@
package logging
import (
"github.com/owncloud/ocis/graph-explorer/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
)
// LoggerFromConfig initializes a service-specific logger instance.
func Configure(name string, cfg *config.Log) log.Logger {
return log.NewLogger(
log.Name(name),
log.Level(cfg.Level),
log.Pretty(cfg.Pretty),
log.Color(cfg.Color),
log.File(cfg.File),
)
}

View File

@@ -15,7 +15,7 @@ func Server(opts ...Option) (*http.Server, error) {
return debug.NewService(
debug.Logger(options.Logger),
debug.Name("graph-explorer"),
debug.Name(options.Config.Service.Name),
debug.Version(version.String),
debug.Address(options.Config.Debug.Addr),
debug.Token(options.Config.Debug.Token),
@@ -32,9 +32,11 @@ func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// TODO(tboerger): check if services are up and running
// TODO: check if services are up and running
if _, err := io.WriteString(w, http.StatusText(http.StatusOK)); err != nil {
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.
if err != nil {
panic(err)
}
}
@@ -46,9 +48,11 @@ func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// TODO(tboerger): check if services are up and running
// TODO: check if services are up and running
if _, err := io.WriteString(w, http.StatusText(http.StatusOK)); err != nil {
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.
if err != nil {
panic(err)
}
}

View File

@@ -14,7 +14,7 @@ var (
func Configure(cfg *config.Config) error {
var err error
if cfg.Tracing.Enabled {
if TraceProvider, err = pkgtrace.GetTraceProvider(cfg.Tracing.Endpoint, cfg.Tracing.Collector, "graph-explorer", cfg.Tracing.Type); err != nil {
if TraceProvider, err = pkgtrace.GetTraceProvider(cfg.Tracing.Endpoint, cfg.Tracing.Collector, cfg.Service.Name, cfg.Tracing.Type); err != nil {
return err
}
}

View File

@@ -8,7 +8,7 @@ import (
)
func main() {
if err := command.Execute(config.New()); err != nil {
if err := command.Execute(config.DefaultConfig()); err != nil {
os.Exit(1)
}
}

View File

@@ -5,19 +5,22 @@ import (
"net/http"
"github.com/owncloud/ocis/graph/pkg/config"
"github.com/owncloud/ocis/graph/pkg/config/parser"
"github.com/owncloud/ocis/graph/pkg/logging"
"github.com/urfave/cli/v2"
)
// Health is the entrypoint for the health command.
func Health(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "health",
Usage: "Check health status",
Name: "health",
Usage: "check health status",
Category: "info",
Before: func(c *cli.Context) error {
return ParseConfig(c, cfg)
return parser.ParseConfig(cfg)
},
Action: func(c *cli.Context) error {
logger := NewLogger(cfg)
logger := logging.Configure(cfg.Service.Name, cfg.Log)
resp, err := http.Get(
fmt.Sprintf(
@@ -34,7 +37,7 @@ func Health(cfg *config.Config) *cli.Command {
defer resp.Body.Close()
if resp.StatusCode != 200 {
if resp.StatusCode != http.StatusOK {
logger.Fatal().
Int("code", resp.StatusCode).
Msg("Health seems to be in bad state")

View File

@@ -4,86 +4,43 @@ import (
"context"
"os"
"github.com/owncloud/ocis/ocis-pkg/shared"
"github.com/owncloud/ocis/ocis-pkg/clihelper"
"github.com/thejerf/suture/v4"
"github.com/owncloud/ocis/graph/pkg/config"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/version"
"github.com/urfave/cli/v2"
)
// GetCommands provides all commands for this service
func GetCommands(cfg *config.Config) cli.Commands {
return []*cli.Command{
// start this service
Server(cfg),
// interaction with this service
// infos about this service
Health(cfg),
Version(cfg),
}
}
// Execute is the entry point for the ocis-graph command.
func Execute(cfg *config.Config) error {
app := &cli.App{
app := clihelper.DefaultApp(&cli.App{
Name: "ocis-graph",
Version: version.String,
Usage: "Serve Graph API for oCIS",
Compiled: version.Compiled(),
Authors: []*cli.Author{
{
Name: "ownCloud GmbH",
Email: "support@owncloud.com",
},
},
Before: func(c *cli.Context) error {
cfg.Server.Version = version.String
return ParseConfig(c, cfg)
},
Commands: []*cli.Command{
Server(cfg),
Health(cfg),
},
}
Commands: GetCommands(cfg),
})
cli.HelpFlag = &cli.BoolFlag{
Name: "help,h",
Usage: "Show the help",
}
cli.VersionFlag = &cli.BoolFlag{
Name: "version,v",
Usage: "Print the version",
}
return app.Run(os.Args)
}
// NewLogger initializes a service-specific logger instance.
func NewLogger(cfg *config.Config) log.Logger {
return log.NewLogger(
log.Name("graph"),
log.Level(cfg.Log.Level),
log.Pretty(cfg.Log.Pretty),
log.Color(cfg.Log.Color),
log.File(cfg.Log.File),
)
}
// ParseConfig loads graph configuration from known paths.
func ParseConfig(c *cli.Context, cfg *config.Config) error {
conf, err := ociscfg.BindSourcesToStructs("graph", cfg)
if err != nil {
return err
}
// provide with defaults for shared logging, since we need a valid destination address for BindEnv.
if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
cfg.Log = &shared.Log{
Level: cfg.Commons.Log.Level,
Pretty: cfg.Commons.Log.Pretty,
Color: cfg.Commons.Log.Color,
File: cfg.Commons.Log.File,
}
} else if cfg.Log == nil && cfg.Commons == nil {
cfg.Log = &shared.Log{}
}
conf.LoadOSEnv(config.GetEnv(cfg), false)
bindings := config.StructMappings(cfg)
return ociscfg.BindEnv(conf, bindings)
}
// SutureService allows for the graph command to be embedded and supervised by a suture supervisor tree.
type SutureService struct {
cfg *config.Config

View File

@@ -2,37 +2,33 @@ package command
import (
"context"
"strings"
"fmt"
"github.com/oklog/run"
"github.com/owncloud/ocis/graph/pkg/config"
"github.com/owncloud/ocis/graph/pkg/config/parser"
"github.com/owncloud/ocis/graph/pkg/logging"
"github.com/owncloud/ocis/graph/pkg/metrics"
"github.com/owncloud/ocis/graph/pkg/server/debug"
"github.com/owncloud/ocis/graph/pkg/server/http"
"github.com/owncloud/ocis/graph/pkg/tracing"
"github.com/owncloud/ocis/ocis-pkg/version"
"github.com/urfave/cli/v2"
)
// Server is the entrypoint for the server command.
func Server(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "server",
Usage: "Start integrated server",
Before: func(ctx *cli.Context) error {
if cfg.HTTP.Root != "/" {
cfg.HTTP.Root = strings.TrimSuffix(cfg.HTTP.Root, "/")
}
if err := ParseConfig(ctx, cfg); err != nil {
return err
}
return nil
Name: "server",
Usage: fmt.Sprintf("start %s extension without runtime (unsupervised mode)", cfg.Service.Name),
Category: "server",
Before: func(c *cli.Context) error {
return parser.ParseConfig(cfg)
},
Action: func(c *cli.Context) error {
logger := NewLogger(cfg)
if err := tracing.Configure(cfg); err != nil {
logger := logging.Configure(cfg.Service.Name, cfg.Log)
err := tracing.Configure(cfg)
if err != nil {
return err
}
@@ -47,7 +43,7 @@ func Server(cfg *config.Config) *cli.Command {
defer cancel()
mtrcs.BuildInfo.WithLabelValues(cfg.Server.Version).Set(1)
mtrcs.BuildInfo.WithLabelValues(version.String).Set(1)
{
server, err := http.Server(

View File

@@ -0,0 +1,50 @@
package command
import (
"fmt"
"os"
"github.com/owncloud/ocis/ocis-pkg/registry"
"github.com/owncloud/ocis/ocis-pkg/version"
tw "github.com/olekukonko/tablewriter"
"github.com/owncloud/ocis/graph/pkg/config"
"github.com/urfave/cli/v2"
)
// Version prints the service versions of all running instances.
func Version(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "version",
Usage: "print the version of this binary and the running extension instances",
Category: "info",
Action: func(c *cli.Context) error {
fmt.Println("Version: " + version.String)
fmt.Printf("Compiled: %s\n", version.Compiled())
fmt.Println("")
reg := registry.GetRegistry()
services, err := reg.GetService(cfg.HTTP.Namespace + "." + cfg.Service.Name)
if err != nil {
fmt.Println(fmt.Errorf("could not get %s services from the registry: %v", cfg.Service.Name, err))
return err
}
if len(services) == 0 {
fmt.Println("No running " + cfg.Service.Name + " service found.")
return nil
}
table := tw.NewWriter(os.Stdout)
table.SetHeader([]string{"Version", "Address", "Id"})
table.SetAutoFormatHeaders(false)
for _, s := range services {
for _, n := range s.Nodes {
table.Append([]string{s.Version, n.Address, n.Id})
}
}
table.Render()
return nil
},
}
}

View File

@@ -6,150 +6,54 @@ import (
"github.com/owncloud/ocis/ocis-pkg/shared"
)
// Debug defines the available debug configuration.
type Debug struct {
Addr string `ocisConfig:"addr"`
Token string `ocisConfig:"token"`
Pprof bool `ocisConfig:"pprof"`
Zpages bool `ocisConfig:"zpages"`
}
// HTTP defines the available http configuration.
type HTTP struct {
Addr string `ocisConfig:"addr"`
Namespace string `ocisConfig:"namespace"`
Root string `ocisConfig:"root"`
}
// Server configures a server.
type Server struct {
Version string `ocisConfig:"version"`
Name string `ocisConfig:"name"`
}
// Tracing defines the available tracing configuration.
type Tracing struct {
Enabled bool `ocisConfig:"enabled"`
Type string `ocisConfig:"type"`
Endpoint string `ocisConfig:"endpoint"`
Collector string `ocisConfig:"collector"`
Service string `ocisConfig:"service"`
}
// Reva defines all available REVA configuration.
type Reva struct {
Address string `ocisConfig:"address"`
}
// TokenManager is the config for using the reva token manager
type TokenManager struct {
JWTSecret string `ocisConfig:"jwt_secret"`
}
type Spaces struct {
WebDavBase string `ocisConfig:"webdav_base"`
WebDavPath string `ocisConfig:"webdav_path"`
DefaultQuota string `ocisConfig:"default_quota"`
}
type LDAP struct {
URI string `ocisConfig:"uri"`
BindDN string `ocisConfig:"bind_dn"`
BindPassword string `ocisConfig:"bind_password"`
UserBaseDN string `ocisConfig:"user_base_dn"`
UserSearchScope string `ocisConfig:"user_search_scope"`
UserFilter string `ocisConfig:"user_filter"`
UserEmailAttribute string `ocisConfig:"user_mail_attribute"`
UserDisplayNameAttribute string `ocisConfig:"user_displayname_attribute"`
UserNameAttribute string `ocisConfig:"user_name_attribute"`
UserIDAttribute string `ocisConfig:"user_id_attribute"`
GroupBaseDN string `ocisConfig:"group_base_dn"`
GroupSearchScope string `ocisConfig:"group_search_scope"`
GroupFilter string `ocisConfig:"group_filter"`
GroupNameAttribute string `ocisConfig:"group_name_attribute"`
GroupIDAttribute string `ocisConfig:"group_id_attribute"`
}
type Identity struct {
Backend string `ocisConfig:"backend"`
LDAP LDAP `ocisConfig:"ldap"`
}
// Config combines all available configuration parts.
type Config struct {
*shared.Commons
File string `ocisConfig:"file"`
Log *shared.Log `ocisConfig:"log"`
Debug Debug `ocisConfig:"debug"`
HTTP HTTP `ocisConfig:"http"`
Server Server `ocisConfig:"server"`
Tracing Tracing `ocisConfig:"tracing"`
Service Service
Tracing Tracing `ocisConfig:"tracing"`
Log *Log `ocisConfig:"log"`
Debug Debug `ocisConfig:"debug"`
HTTP HTTP `ocisConfig:"http"`
Reva Reva `ocisConfig:"reva"`
TokenManager TokenManager `ocisConfig:"token_manager"`
Spaces Spaces `ocisConfig:"spaces"`
Identity Identity `ocisConfig:"identity"`
Context context.Context
Supervised bool
Spaces Spaces `ocisConfig:"spaces"`
Identity Identity `ocisConfig:"identity"`
Context context.Context
}
// New initializes a new configuration with or without defaults.
func New() *Config {
return &Config{}
type Spaces struct {
WebDavBase string `ocisConfig:"webdav_base" env:"OCIS_URL;GRAPH_SPACES_WEBDAV_BASE"`
WebDavPath string `ocisConfig:"webdav_path" env:"GRAPH_SPACES_WEBDAV_PATH"`
DefaultQuota string `ocisConfig:"default_quota" env:"GRAPH_SPACES_DEFAULT_QUOTA"`
}
func DefaultConfig() *Config {
return &Config{
Debug: Debug{
Addr: "127.0.0.1:9124",
Token: "",
},
HTTP: HTTP{
Addr: "127.0.0.1:9120",
Namespace: "com.owncloud.web",
Root: "/graph",
},
Server: Server{},
Tracing: Tracing{
Enabled: false,
Type: "jaeger",
Service: "graph",
},
Reva: Reva{
Address: "127.0.0.1:9142",
},
TokenManager: TokenManager{
JWTSecret: "Pive-Fumkiu4",
},
Spaces: Spaces{
WebDavBase: "https://localhost:9200",
WebDavPath: "/dav/spaces/",
DefaultQuota: "1000000000",
},
Identity: Identity{
Backend: "cs3",
LDAP: LDAP{
URI: "ldap://localhost:9125",
BindDN: "",
BindPassword: "",
UserBaseDN: "ou=users,dc=ocis,dc=test",
UserSearchScope: "sub",
UserFilter: "(objectClass=posixaccount)",
UserEmailAttribute: "mail",
UserDisplayNameAttribute: "displayName",
UserNameAttribute: "uid",
// FIXME: switch this to some more widely available attribute by default
// ideally this needs to be constant for the lifetime of a users
UserIDAttribute: "ownclouduuid",
GroupBaseDN: "ou=groups,dc=ocis,dc=test",
GroupSearchScope: "sub",
GroupFilter: "(objectclass=groupOfNames)",
GroupNameAttribute: "cn",
GroupIDAttribute: "cn",
},
},
}
type LDAP struct {
URI string `ocisConfig:"uri" env:"GRAPH_LDAP_URI"`
BindDN string `ocisConfig:"bind_dn" env:"GRAPH_LDAP_BIND_DN"`
BindPassword string `ocisConfig:"bind_password" env:"GRAPH_LDAP_BIND_PASSWORD"`
UserBaseDN string `ocisConfig:"user_base_dn" env:"GRAPH_LDAP_USER_BASE_DN"`
UserSearchScope string `ocisConfig:"user_search_scope" env:"GRAPH_LDAP_USER_SCOPE"`
UserFilter string `ocisConfig:"user_filter" env:"GRAPH_LDAP_USER_FILTER"`
UserEmailAttribute string `ocisConfig:"user_mail_attribute" env:"GRAPH_LDAP_USER_EMAIL_ATTRIBUTE"`
UserDisplayNameAttribute string `ocisConfig:"user_displayname_attribute" env:"GRAPH_LDAP_USER_DISPLAYNAME_ATTRIBUTE"`
UserNameAttribute string `ocisConfig:"user_name_attribute" env:"GRAPH_LDAP_USER_NAME_ATTRIBUTE"`
UserIDAttribute string `ocisConfig:"user_id_attribute" env:"GRAPH_LDAP_USER_UID_ATTRIBUTE"`
GroupBaseDN string `ocisConfig:"group_base_dn" env:"GRAPH_LDAP_GROUP_BASE_DN"`
GroupSearchScope string `ocisConfig:"group_search_scope" env:"GRAPH_LDAP_GROUP_SEARCH_SCOPE"`
GroupFilter string `ocisConfig:"group_filter" env:"GRAPH_LDAP_GROUP_FILTER"`
GroupNameAttribute string `ocisConfig:"group_name_attribute" env:"GRAPH_LDAP_GROUP_NAME_ATTRIBUTE"`
GroupIDAttribute string `ocisConfig:"group_id_attribute" env:"GRAPH_LDAP_GROUP_ID_ATTRIBUTE"`
}
type Identity struct {
Backend string `ocisConfig:"backend" env:"GRAPH_IDENTITY_BACKEND"`
LDAP LDAP `ocisConfig:"ldap"`
}

View File

@@ -0,0 +1,9 @@
package config
// Debug defines the available debug configuration.
type Debug struct {
Addr string `ocisConfig:"addr" env:"GRAPH_DEBUG_ADDR"`
Token string `ocisConfig:"token" env:"GRAPH_DEBUG_TOKEN"`
Pprof bool `ocisConfig:"pprof" env:"GRAPH_DEBUG_PPROF"`
Zpages bool `ocisConfig:"zpages" env:"GRAPH_DEBUG_ZPAGES"`
}

View File

@@ -0,0 +1,57 @@
package config
func DefaultConfig() *Config {
return &Config{
Debug: Debug{
Addr: "127.0.0.1:9124",
Token: "",
},
HTTP: HTTP{
Addr: "127.0.0.1:9120",
Namespace: "com.owncloud.graph",
Root: "/graph",
},
Service: Service{
Name: "graph",
},
Tracing: Tracing{
Enabled: false,
Type: "jaeger",
Endpoint: "",
Collector: "",
},
Reva: Reva{
Address: "127.0.0.1:9142",
},
TokenManager: TokenManager{
JWTSecret: "Pive-Fumkiu4",
},
Spaces: Spaces{
WebDavBase: "https://localhost:9200",
WebDavPath: "/dav/spaces/",
DefaultQuota: "1000000000",
},
Identity: Identity{
Backend: "cs3",
LDAP: LDAP{
URI: "ldap://localhost:9125",
BindDN: "",
BindPassword: "",
UserBaseDN: "ou=users,dc=ocis,dc=test",
UserSearchScope: "sub",
UserFilter: "(objectClass=posixaccount)",
UserEmailAttribute: "mail",
UserDisplayNameAttribute: "displayName",
UserNameAttribute: "uid",
// FIXME: switch this to some more widely available attribute by default
// ideally this needs to be constant for the lifetime of a users
UserIDAttribute: "ownclouduuid",
GroupBaseDN: "ou=groups,dc=ocis,dc=test",
GroupSearchScope: "sub",
GroupFilter: "(objectclass=groupOfNames)",
GroupNameAttribute: "cn",
GroupIDAttribute: "cn",
},
},
}
}

8
graph/pkg/config/http.go Normal file
View File

@@ -0,0 +1,8 @@
package config
// HTTP defines the available http configuration.
type HTTP struct {
Addr string `ocisConfig:"addr" env:"GRAPH_HTTP_ADDR"`
Namespace string
Root string `ocisConfig:"root" env:"GRAPH_HTTP_ROOT"`
}

9
graph/pkg/config/log.go Normal file
View File

@@ -0,0 +1,9 @@
package config
// Log defines the available log configuration.
type Log struct {
Level string `mapstructure:"level" env:"OCIS_LOG_LEVEL;GRAPH_LOG_LEVEL"`
Pretty bool `mapstructure:"pretty" env:"OCIS_LOG_PRETTY;GRAPH_LOG_PRETTY"`
Color bool `mapstructure:"color" env:"OCIS_LOG_COLOR;GRAPH_LOG_COLOR"`
File string `mapstructure:"file" env:"OCIS_LOG_FILE;GRAPH_LOG_FILE"`
}

View File

@@ -1,179 +0,0 @@
package config
import "github.com/owncloud/ocis/ocis-pkg/shared"
// GetEnv fetches a list of known env variables for this extension. It is to be used by gookit, as it provides a list
// with all the environment variables an extension supports.
func GetEnv(cfg *Config) []string {
var r = make([]string, len(structMappings(cfg)))
for i := range structMappings(cfg) {
r = append(r, structMappings(cfg)[i].EnvVars...)
}
return r
}
// StructMappings binds a set of environment variables to a destination on cfg. Iterating over this set and editing the
// Destination value of a binding will alter the original value, as it is a pointer to its memory address. This lets
// us propagate changes easier.
func StructMappings(cfg *Config) []shared.EnvBinding {
return structMappings(cfg)
}
// structMappings binds a set of environment variables to a destination on cfg.
func structMappings(cfg *Config) []shared.EnvBinding {
return []shared.EnvBinding{
{
EnvVars: []string{"GRAPH_CONFIG_FILE"},
Destination: &cfg.File,
},
{
EnvVars: []string{"OCIS_LOG_LEVEL", "GRAPH_LOG_LEVEL"},
Destination: &cfg.Log.Level,
},
{
EnvVars: []string{"OCIS_LOG_PRETTY", "GRAPH_LOG_PRETTY"},
Destination: &cfg.Log.Pretty,
},
{
EnvVars: []string{"OCIS_LOG_COLOR", "GRAPH_LOG_COLOR"},
Destination: &cfg.Log.Color,
},
{
EnvVars: []string{"OCIS_LOG_FILE", "GRAPH_LOG_FILE"},
Destination: &cfg.Log.File,
},
{
EnvVars: []string{"OCIS_TRACING_ENABLED", "GRAPH_TRACING_ENABLED"},
Destination: &cfg.Tracing.Enabled,
},
{
EnvVars: []string{"OCIS_TRACING_TYPE", "GRAPH_TRACING_TYPE"},
Destination: &cfg.Tracing.Type,
},
{
EnvVars: []string{"OCIS_TRACING_ENDPOINT", "GRAPH_TRACING_ENDPOINT"},
Destination: &cfg.Tracing.Endpoint,
},
{
EnvVars: []string{"OCIS_TRACING_COLLECTOR", "GRAPH_TRACING_COLLECTOR"},
Destination: &cfg.Tracing.Collector,
},
{
EnvVars: []string{"GRAPH_TRACING_SERVICE"},
Destination: &cfg.Tracing.Service,
},
{
EnvVars: []string{"GRAPH_DEBUG_ADDR"},
Destination: &cfg.Debug.Addr,
},
{
EnvVars: []string{"GRAPH_DEBUG_TOKEN"},
Destination: &cfg.Debug.Token,
},
{
EnvVars: []string{"GRAPH_DEBUG_PPROF"},
Destination: &cfg.Debug.Pprof,
},
{
EnvVars: []string{"GRAPH_DEBUG_ZPAGES"},
Destination: &cfg.Debug.Zpages,
},
{
EnvVars: []string{"GRAPH_HTTP_ADDR"},
Destination: &cfg.HTTP.Addr,
},
{
EnvVars: []string{"GRAPH_HTTP_ROOT"},
Destination: &cfg.HTTP.Root,
},
{
EnvVars: []string{"GRAPH_HTTP_NAMESPACE"},
Destination: &cfg.HTTP.Namespace,
},
{
EnvVars: []string{"OCIS_URL", "GRAPH_SPACES_WEBDAV_BASE"},
Destination: &cfg.Spaces.WebDavBase,
},
{
EnvVars: []string{"GRAPH_SPACES_WEBDAV_PATH"},
Destination: &cfg.Spaces.WebDavPath,
},
{
EnvVars: []string{"GRAPH_SPACES_DEFAULT_QUOTA"},
Destination: &cfg.Spaces.DefaultQuota,
},
{
EnvVars: []string{"OCIS_JWT_SECRET", "GRAPH_JWT_SECRET"},
Destination: &cfg.TokenManager.JWTSecret,
},
{
EnvVars: []string{"REVA_GATEWAY"},
Destination: &cfg.Reva.Address,
},
{
EnvVars: []string{"GRAPH_IDENTITY_BACKEND"},
Destination: &cfg.Identity.Backend,
},
{
EnvVars: []string{"GRAPH_LDAP_URI"},
Destination: &cfg.Identity.LDAP.URI,
},
{
EnvVars: []string{"GRAPH_LDAP_BIND_DN"},
Destination: &cfg.Identity.LDAP.BindDN,
},
{
EnvVars: []string{"GRAPH_LDAP_BIND_PASSWORD"},
Destination: &cfg.Identity.LDAP.BindPassword,
},
{
EnvVars: []string{"GRAPH_LDAP_USER_BASE_DN"},
Destination: &cfg.Identity.LDAP.UserBaseDN,
},
{
EnvVars: []string{"GRAPH_LDAP_USER_EMAIL_ATTRIBUTE"},
Destination: &cfg.Identity.LDAP.UserEmailAttribute,
},
{
EnvVars: []string{"GRAPH_LDAP_USER_DISPLAYNAME_ATTRIBUTE"},
Destination: &cfg.Identity.LDAP.UserDisplayNameAttribute,
},
{
EnvVars: []string{"GRAPH_LDAP_USER_NAME_ATTRIBUTE"},
Destination: &cfg.Identity.LDAP.UserNameAttribute,
},
{
EnvVars: []string{"GRAPH_LDAP_USER_UID_ATTRIBUTE"},
Destination: &cfg.Identity.LDAP.UserIDAttribute,
},
{
EnvVars: []string{"GRAPH_LDAP_USER_FILTER"},
Destination: &cfg.Identity.LDAP.UserFilter,
},
{
EnvVars: []string{"GRAPH_LDAP_USER_SCOPE"},
Destination: &cfg.Identity.LDAP.UserSearchScope,
},
{
EnvVars: []string{"GRAPH_LDAP_GROUP_BASE_DN"},
Destination: &cfg.Identity.LDAP.GroupBaseDN,
},
{
EnvVars: []string{"GRAPH_LDAP_GROUP_SEARCH_SCOPE"},
Destination: &cfg.Identity.LDAP.GroupSearchScope,
},
{
EnvVars: []string{"GRAPH_LDAP_GROUP_FILTER"},
Destination: &cfg.Identity.LDAP.GroupFilter,
},
{
EnvVars: []string{"GRAPH_LDAP_GROUP_NAME_ATTRIBUTE"},
Destination: &cfg.Identity.LDAP.GroupNameAttribute,
},
{
EnvVars: []string{"GRAPH_LDAP_GROUP_ID_ATTRIBUTE"},
Destination: &cfg.Identity.LDAP.GroupIDAttribute,
},
}
}

View File

@@ -0,0 +1,46 @@
package parser
import (
"errors"
"strings"
"github.com/owncloud/ocis/graph/pkg/config"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/config/envdecode"
)
// ParseConfig loads accounts configuration from known paths.
func ParseConfig(cfg *config.Config) error {
_, err := ociscfg.BindSourcesToStructs(cfg.Service.Name, cfg)
if err != nil {
return err
}
// provide with defaults for shared logging, since we need a valid destination address for BindEnv.
if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
cfg.Log = &config.Log{
Level: cfg.Commons.Log.Level,
Pretty: cfg.Commons.Log.Pretty,
Color: cfg.Commons.Log.Color,
File: cfg.Commons.Log.File,
}
} else if cfg.Log == nil && cfg.Commons == nil {
cfg.Log = &config.Log{}
}
// load all env variables relevant to the config in the current context.
if err := envdecode.Decode(cfg); err != nil {
// no environment variable set for this config is an expected "error"
if !errors.Is(err, envdecode.ErrNoTargetFieldsAreSet) {
return err
}
}
// sanitize config
if cfg.HTTP.Root != "/" {
cfg.HTTP.Root = strings.TrimSuffix(cfg.HTTP.Root, "/")
}
return nil
}

11
graph/pkg/config/reva.go Normal file
View File

@@ -0,0 +1,11 @@
package config
// Reva defines all available REVA configuration.
type Reva struct {
Address string `ocisConfig:"address" env:"REVA_GATEWAY"`
}
// TokenManager is the config for using the reva token manager
type TokenManager struct {
JWTSecret string `ocisConfig:"jwt_secret" env:"OCIS_JWT_SECRET;OCS_JWT_SECRET"`
}

View File

@@ -0,0 +1,6 @@
package config
// Service defines the available service configuration.
type Service struct {
Name string
}

View File

@@ -0,0 +1,9 @@
package config
// Tracing defines the available tracing configuration.
type Tracing struct {
Enabled bool `ocisConfig:"enabled" env:"OCIS_TRACING_ENABLED;GRAPH_TRACING_ENABLED"`
Type string `ocisConfig:"type" env:"OCIS_TRACING_TYPE;GRAPH_TRACING_TYPE"`
Endpoint string `ocisConfig:"endpoint" env:"OCIS_TRACING_ENDPOINT;GRAPH_TRACING_ENDPOINT"`
Collector string `ocisConfig:"collector" env:"OCIS_TRACING_COLLECTOR;GRAPH_TRACING_COLLECTOR"`
}

View File

@@ -0,0 +1,17 @@
package logging
import (
"github.com/owncloud/ocis/graph/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
)
// LoggerFromConfig initializes a service-specific logger instance.
func Configure(name string, cfg *config.Log) log.Logger {
return log.NewLogger(
log.Name(name),
log.Level(cfg.Level),
log.Pretty(cfg.Pretty),
log.Color(cfg.Color),
log.File(cfg.File),
)
}

View File

@@ -15,7 +15,7 @@ func Server(opts ...Option) (*http.Server, error) {
return debug.NewService(
debug.Logger(options.Logger),
debug.Name("graph"),
debug.Name(options.Config.Service.Name),
debug.Version(version.String),
debug.Address(options.Config.Debug.Addr),
debug.Token(options.Config.Debug.Token),
@@ -32,9 +32,11 @@ func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// TODO(tboerger): check if services are up and running
// TODO: check if services are up and running
if _, err := io.WriteString(w, http.StatusText(http.StatusOK)); err != nil {
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.
if err != nil {
panic(err)
}
}
@@ -46,9 +48,11 @@ func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
// TODO(tboerger): check if services are up and running
// TODO: check if services are up and running
if _, err := io.WriteString(w, http.StatusText(http.StatusOK)); err != nil {
_, err := io.WriteString(w, http.StatusText(http.StatusOK))
// io.WriteString should not fail but if it does we want to know.
if err != nil {
panic(err)
}
}

View File

@@ -14,7 +14,7 @@ var (
func Configure(cfg *config.Config) error {
var err error
if cfg.Tracing.Enabled {
if TraceProvider, err = pkgtrace.GetTraceProvider(cfg.Tracing.Endpoint, cfg.Tracing.Collector, "graph", cfg.Tracing.Type); err != nil {
if TraceProvider, err = pkgtrace.GetTraceProvider(cfg.Tracing.Endpoint, cfg.Tracing.Collector, cfg.Service.Name, cfg.Tracing.Type); err != nil {
return err
}
}

View File

@@ -5,19 +5,22 @@ import (
"net/http"
"github.com/owncloud/ocis/idp/pkg/config"
"github.com/owncloud/ocis/idp/pkg/config/parser"
"github.com/owncloud/ocis/idp/pkg/logging"
"github.com/urfave/cli/v2"
)
// Health is the entrypoint for the health command.
func Health(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "health",
Usage: "Check health status",
Name: "health",
Usage: "check health status",
Category: "info",
Before: func(c *cli.Context) error {
return ParseConfig(c, cfg)
return parser.ParseConfig(cfg)
},
Action: func(c *cli.Context) error {
logger := NewLogger(cfg)
logger := logging.Configure(cfg.Service.Name, cfg.Log)
resp, err := http.Get(
fmt.Sprintf(
@@ -34,7 +37,7 @@ func Health(cfg *config.Config) *cli.Command {
defer resp.Body.Close()
if resp.StatusCode != 200 {
if resp.StatusCode != http.StatusOK {
logger.Fatal().
Int("code", resp.StatusCode).
Msg("Health seems to be in bad state")

View File

@@ -4,91 +4,43 @@ import (
"context"
"os"
"github.com/owncloud/ocis/ocis-pkg/shared"
"github.com/owncloud/ocis/idp/pkg/config"
"github.com/owncloud/ocis/ocis-pkg/clihelper"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/version"
"github.com/thejerf/suture/v4"
"github.com/urfave/cli/v2"
)
// GetCommands provides all commands for this service
func GetCommands(cfg *config.Config) cli.Commands {
return []*cli.Command{
// start this service
Server(cfg),
// interaction with this service
// infos about this service
Health(cfg),
Version(cfg),
}
}
// Execute is the entry point for the ocis-idp command.
func Execute(cfg *config.Config) error {
app := &cli.App{
app := clihelper.DefaultApp(&cli.App{
Name: "ocis-idp",
Version: version.String,
Usage: "Serve IDP API for oCIS",
Compiled: version.Compiled(),
Authors: []*cli.Author{
{
Name: "ownCloud GmbH",
Email: "support@owncloud.com",
},
},
Before: func(c *cli.Context) error {
cfg.Service.Version = version.String
return nil
},
Commands: []*cli.Command{
Server(cfg),
Health(cfg),
PrintVersion(cfg),
},
}
Commands: GetCommands(cfg),
})
cli.HelpFlag = &cli.BoolFlag{
Name: "help,h",
Usage: "Show the help",
}
cli.VersionFlag = &cli.BoolFlag{
Name: "version,v",
Usage: "Print the version",
}
return app.Run(os.Args)
}
// NewLogger initializes a service-specific logger instance.
func NewLogger(cfg *config.Config) log.Logger {
return log.NewLogger(
log.Name("idp"),
log.Level(cfg.Log.Level),
log.Pretty(cfg.Log.Pretty),
log.Color(cfg.Log.Color),
log.File(cfg.Log.File),
)
}
// ParseConfig loads idp configuration from known paths.
func ParseConfig(c *cli.Context, cfg *config.Config) error {
conf, err := ociscfg.BindSourcesToStructs("idp", cfg)
if err != nil {
return err
}
// provide with defaults for shared logging, since we need a valid destination address for BindEnv.
if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
cfg.Log = &shared.Log{
Level: cfg.Commons.Log.Level,
Pretty: cfg.Commons.Log.Pretty,
Color: cfg.Commons.Log.Color,
File: cfg.Commons.Log.File,
}
} else if cfg.Log == nil && cfg.Commons == nil {
cfg.Log = &shared.Log{}
}
// load all env variables relevant to the config in the current context.
conf.LoadOSEnv(config.GetEnv(cfg), false)
bindings := config.StructMappings(cfg)
return ociscfg.BindEnv(conf, bindings)
}
// SutureService allows for the idp command to be embedded and supervised by a suture supervisor tree.
type SutureService struct {
cfg *config.Config

View File

@@ -2,38 +2,35 @@ package command
import (
"context"
"strings"
"fmt"
"github.com/oklog/run"
"github.com/owncloud/ocis/idp/pkg/config"
"github.com/owncloud/ocis/idp/pkg/config/parser"
"github.com/owncloud/ocis/idp/pkg/logging"
"github.com/owncloud/ocis/idp/pkg/metrics"
"github.com/owncloud/ocis/idp/pkg/server/debug"
"github.com/owncloud/ocis/idp/pkg/server/http"
"github.com/owncloud/ocis/idp/pkg/tracing"
"github.com/owncloud/ocis/ocis-pkg/version"
"github.com/urfave/cli/v2"
)
// Server is the entrypoint for the server command.
func Server(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "server",
Usage: "Start integrated server",
Before: func(ctx *cli.Context) error {
if err := ParseConfig(ctx, cfg); err != nil {
return err
}
if cfg.HTTP.Root != "/" {
cfg.HTTP.Root = strings.TrimSuffix(cfg.HTTP.Root, "/")
}
return nil
Name: "server",
Usage: fmt.Sprintf("start %s extension without runtime (unsupervised mode)", cfg.Service.Name),
Category: "server",
Before: func(c *cli.Context) error {
return parser.ParseConfig(cfg)
},
Action: func(c *cli.Context) error {
logger := NewLogger(cfg)
tracing.Configure(cfg)
logger := logging.Configure(cfg.Service.Name, cfg.Log)
err := tracing.Configure(cfg)
if err != nil {
return err
}
var (
gr = run.Group{}
ctx, cancel = func() (context.Context, context.CancelFunc) {
@@ -47,7 +44,7 @@ func Server(cfg *config.Config) *cli.Command {
defer cancel()
metrics.BuildInfo.WithLabelValues(cfg.Service.Version).Set(1)
metrics.BuildInfo.WithLabelValues(version.String).Set(1)
{
server, err := http.Server(

View File

@@ -5,30 +5,33 @@ import (
"os"
"github.com/owncloud/ocis/ocis-pkg/registry"
"github.com/owncloud/ocis/ocis-pkg/version"
tw "github.com/olekukonko/tablewriter"
"github.com/owncloud/ocis/idp/pkg/config"
"github.com/urfave/cli/v2"
)
// PrintVersion prints the service versions of all running instances.
func PrintVersion(cfg *config.Config) *cli.Command {
// Version prints the service versions of all running instances.
func Version(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "version",
Usage: "Print the versions of the running instances",
Before: func(c *cli.Context) error {
return ParseConfig(c, cfg)
},
Name: "version",
Usage: "print the version of this binary and the running extension instances",
Category: "info",
Action: func(c *cli.Context) error {
fmt.Println("Version: " + version.String)
fmt.Printf("Compiled: %s\n", version.Compiled())
fmt.Println("")
reg := registry.GetRegistry()
services, err := reg.GetService(cfg.Service.Namespace + "." + cfg.Service.Name)
services, err := reg.GetService(cfg.HTTP.Namespace + "." + cfg.Service.Name)
if err != nil {
fmt.Println(fmt.Errorf("could not get idp services from the registry: %v", err))
fmt.Println(fmt.Errorf("could not get %s services from the registry: %v", cfg.Service.Name, err))
return err
}
if len(services) == 0 {
fmt.Println("No running idp service found.")
fmt.Println("No running " + cfg.Service.Name + " service found.")
return nil
}

View File

@@ -2,191 +2,99 @@ package config
import (
"context"
"path"
"github.com/owncloud/ocis/ocis-pkg/shared"
"github.com/owncloud/ocis/ocis-pkg/config/defaults"
)
// Debug defines the available debug configuration.
type Debug struct {
Addr string `ocisConfig:"addr"`
Token string `ocisConfig:"token"`
Pprof bool `ocisConfig:"pprof"`
Zpages bool `ocisConfig:"zpages"`
}
// HTTP defines the available http configuration.
type HTTP struct {
Addr string `ocisConfig:"addr"`
Root string `ocisConfig:"root"`
TLSCert string `ocisConfig:"tls_cert"`
TLSKey string `ocisConfig:"tls_key"`
TLS bool `ocisConfig:"tls"`
}
// Ldap defines the available LDAP configuration.
type Ldap struct {
URI string `ocisConfig:"uri"`
BindDN string `ocisConfig:"bind_dn"`
BindPassword string `ocisConfig:"bind_password"`
BaseDN string `ocisConfig:"base_dn"`
Scope string `ocisConfig:"scope"`
LoginAttribute string `ocisConfig:"login_attribute"`
EmailAttribute string `ocisConfig:"email_attribute"`
NameAttribute string `ocisConfig:"name_attribute"`
UUIDAttribute string `ocisConfig:"uuid_attribute"`
UUIDAttributeType string `ocisConfig:"uuid_attribute_type"`
Filter string `ocisConfig:"filter"`
}
// Service defines the available service configuration.
type Service struct {
Name string `ocisConfig:"name"`
Namespace string `ocisConfig:"namespace"`
Version string `ocisConfig:"version"`
}
// Tracing defines the available tracing configuration.
type Tracing struct {
Enabled bool `ocisConfig:"enabled"`
Type string `ocisConfig:"type"`
Endpoint string `ocisConfig:"endpoint"`
Collector string `ocisConfig:"collector"`
Service string `ocisConfig:"service"`
}
// Asset defines the available asset configuration.
type Asset struct {
Path string `ocisConfig:"asset"`
}
type Settings struct {
Iss string `ocisConfig:"iss"`
IdentityManager string `ocisConfig:"identity_manager"`
URIBasePath string `ocisConfig:"uri_base_path"`
SignInURI string `ocisConfig:"sign_in_uri"`
SignedOutURI string `ocisConfig:"signed_out_uri"`
AuthorizationEndpointURI string `ocisConfig:"authorization_endpoint_uri"`
EndsessionEndpointURI string `ocisConfig:"end_session_endpoint_uri"`
Insecure bool `ocisConfig:"insecure"`
TrustedProxy []string `ocisConfig:"trusted_proxy"`
AllowScope []string `ocisConfig:"allow_scope"`
AllowClientGuests bool `ocisConfig:"allow_client_guests"`
AllowDynamicClientRegistration bool `ocisConfig:"allow_dynamic_client_registration"`
EncryptionSecretFile string `ocisConfig:"encrypt_secret_file"`
Listen string `ocisConfig:"listen"`
IdentifierClientDisabled bool `ocisConfig:"identifier_client_disabled"`
IdentifierClientPath string `ocisConfig:"identifier_client_path"`
IdentifierRegistrationConf string `ocisConfig:"identifier_registration_conf"`
IdentifierScopesConf string `ocisConfig:"identifier_scopes_conf"`
IdentifierDefaultBannerLogo string `ocisConfig:"identifier_default_banner_logo"`
IdentifierDefaultSignInPageText string `ocisConfig:"identifier_default_sign_in_page_text"`
IdentifierDefaultUsernameHintText string `ocisConfig:"identifier_default_username_hint_text"`
SigningKid string `ocisConfig:"sign_in_kid"`
SigningMethod string `ocisConfig:"sign_in_method"`
SigningPrivateKeyFiles []string `ocisConfig:"sign_in_private_key_files"`
ValidationKeysPath string `ocisConfig:"validation_keys_path"`
CookieBackendURI string `ocisConfig:"cookie_backend_uri"`
CookieNames []string `ocisConfig:"cookie_names"`
AccessTokenDurationSeconds uint64 `ocisConfig:"access_token_duration_seconds"`
IDTokenDurationSeconds uint64 `ocisConfig:"id_token_duration_seconds"`
RefreshTokenDurationSeconds uint64 `ocisConfig:"refresh_token_duration_seconds"`
DyamicClientSecretDurationSeconds uint64 `ocisConfig:"dynamic_client_secret_duration_seconds"`
}
// Config combines all available configuration parts.
type Config struct {
*shared.Commons
File string `ocisConfig:"file"`
Log *shared.Log `ocisConfig:"log"`
Debug Debug `ocisConfig:"debug"`
HTTP HTTP `ocisConfig:"http"`
Tracing Tracing `ocisConfig:"tracing"`
Asset Asset `ocisConfig:"asset"`
IDP Settings `ocisConfig:"idp"`
Ldap Ldap `ocisConfig:"ldap"`
Service Service `ocisConfig:"service"`
Service Service
Context context.Context
Supervised bool
Tracing Tracing `ocisConfig:"tracing"`
Log *Log `ocisConfig:"log"`
Debug Debug `ocisConfig:"debug"`
HTTP HTTP `ocisConfig:"http"`
Asset Asset `ocisConfig:"asset"`
IDP Settings `ocisConfig:"idp"`
Ldap Ldap `ocisConfig:"ldap"`
Context context.Context
}
// New initializes a new configuration with or without defaults.
func New() *Config {
return &Config{}
// Ldap defines the available LDAP configuration.
type Ldap struct {
URI string `ocisConfig:"uri" env:"IDP_LDAP_URI"`
BindDN string `ocisConfig:"bind_dn" env:"IDP_LDAP_BIND_DN"`
BindPassword string `ocisConfig:"bind_password" env:"IDP_LDAP_BIND_PASSWORD"`
BaseDN string `ocisConfig:"base_dn" env:"IDP_LDAP_BASE_DN"`
Scope string `ocisConfig:"scope" env:"IDP_LDAP_SCOPE"`
LoginAttribute string `ocisConfig:"login_attribute" env:"IDP_LDAP_LOGIN_ATTRIBUTE"`
EmailAttribute string `ocisConfig:"email_attribute" env:"IDP_LDAP_EMAIL_ATTRIBUTE"`
NameAttribute string `ocisConfig:"name_attribute" env:"IDP_LDAP_NAME_ATTRIBUTE"`
UUIDAttribute string `ocisConfig:"uuid_attribute" env:"IDP_LDAP_UUID_ATTRIBUTE"`
UUIDAttributeType string `ocisConfig:"uuid_attribute_type" env:"IDP_LDAP_UUID_ATTRIBUTE_TYPE"`
Filter string `ocisConfig:"filter" env:"IDP_LDAP_FILTER"`
}
func DefaultConfig() *Config {
return &Config{
Debug: Debug{
Addr: "127.0.0.1:9134",
},
HTTP: HTTP{
Addr: "127.0.0.1:9130",
Root: "/",
TLSCert: path.Join(defaults.BaseDataPath(), "idp", "server.crt"),
TLSKey: path.Join(defaults.BaseDataPath(), "idp", "server.key"),
TLS: false,
},
Tracing: Tracing{
Type: "jaeger",
Endpoint: "",
Collector: "",
Service: "idp",
},
Asset: Asset{},
IDP: Settings{
Iss: "https://localhost:9200",
IdentityManager: "ldap",
URIBasePath: "",
SignInURI: "",
SignedOutURI: "",
AuthorizationEndpointURI: "",
EndsessionEndpointURI: "",
Insecure: false,
TrustedProxy: nil,
AllowScope: nil,
AllowClientGuests: false,
AllowDynamicClientRegistration: false,
EncryptionSecretFile: "",
Listen: "",
IdentifierClientDisabled: true,
IdentifierClientPath: path.Join(defaults.BaseDataPath(), "idp"),
IdentifierRegistrationConf: path.Join(defaults.BaseDataPath(), "idp", "identifier-registration.yaml"),
IdentifierScopesConf: "",
IdentifierDefaultBannerLogo: "",
IdentifierDefaultSignInPageText: "",
IdentifierDefaultUsernameHintText: "",
SigningKid: "",
SigningMethod: "PS256",
SigningPrivateKeyFiles: nil,
ValidationKeysPath: "",
CookieBackendURI: "",
CookieNames: nil,
AccessTokenDurationSeconds: 60 * 10, // 10 minutes
IDTokenDurationSeconds: 60 * 60, // 1 hour
RefreshTokenDurationSeconds: 60 * 60 * 24 * 365 * 3, // 1 year
DyamicClientSecretDurationSeconds: 0,
},
Ldap: Ldap{
URI: "ldap://localhost:9125",
BindDN: "cn=idp,ou=sysusers,dc=ocis,dc=test",
BindPassword: "idp",
BaseDN: "ou=users,dc=ocis,dc=test",
Scope: "sub",
LoginAttribute: "cn",
EmailAttribute: "mail",
NameAttribute: "sn",
UUIDAttribute: "uid",
UUIDAttributeType: "text",
Filter: "(objectClass=posixaccount)",
},
Service: Service{
Name: "idp",
Namespace: "com.owncloud.web",
},
}
// Asset defines the available asset configuration.
type Asset struct {
Path string `ocisConfig:"asset" env:"IDP_ASSET_PATH"`
}
type Settings struct {
// don't change the order of elements in this struct
// it needs to match github.com/libregraph/lico/bootstrap.Settings
Iss string `ocisConfig:"iss" env:"OCIS_URL;IDP_ISS"`
IdentityManager string `ocisConfig:"identity_manager" env:"IDP_IDENTITY_MANAGER"`
URIBasePath string `ocisConfig:"uri_base_path" env:"IDP_URI_BASE_PATH"`
SignInURI string `ocisConfig:"sign_in_uri" env:"IDP_SIGN_IN_URI"`
SignedOutURI string `ocisConfig:"signed_out_uri" env:"IDP_SIGN_OUT_URI"`
AuthorizationEndpointURI string `ocisConfig:"authorization_endpoint_uri" env:"IDP_ENDPOINT_URI"`
EndsessionEndpointURI string `ocisConfig:"end_session_endpoint_uri" env:"IDP_ENDSESSION_ENDPOINT_URI"`
Insecure bool `ocisConfig:"insecure" env:"IDP_INSECURE"`
TrustedProxy []string `ocisConfig:"trusted_proxy"` //TODO: how to configure this via env?
AllowScope []string `ocisConfig:"allow_scope"` // TODO: is this even needed?
AllowClientGuests bool `ocisConfig:"allow_client_guests" env:"IDP_ALLOW_CLIENT_GUESTS"`
AllowDynamicClientRegistration bool `ocisConfig:"allow_dynamic_client_registration" env:"IDP_ALLOW_DYNAMIC_CLIENT_REGISTRATION"`
EncryptionSecretFile string `ocisConfig:"encrypt_secret_file" env:"IDP_ENCRYPTION_SECRET"`
Listen string
IdentifierClientDisabled bool `ocisConfig:"identifier_client_disabled" env:"IDP_DISABLE_IDENTIFIER_WEBAPP"`
IdentifierClientPath string `ocisConfig:"identifier_client_path" env:"IDP_IDENTIFIER_CLIENT_PATH"`
IdentifierRegistrationConf string `ocisConfig:"identifier_registration_conf" env:"IDP_IDENTIFIER_REGISTRATION_CONF"`
IdentifierScopesConf string `ocisConfig:"identifier_scopes_conf" env:"IDP_IDENTIFIER_SCOPES_CONF"`
IdentifierDefaultBannerLogo string
IdentifierDefaultSignInPageText string
IdentifierDefaultUsernameHintText string
SigningKid string `ocisConfig:"signing_kid" env:"IDP_SIGNING_KID"`
SigningMethod string `ocisConfig:"signing_method" env:"IDP_SIGNING_METHOD"`
SigningPrivateKeyFiles []string `ocisConfig:"signing_private_key_files"` // TODO: is this even needed?
ValidationKeysPath string `ocisConfig:"validation_keys_path" env:"IDP_VALIDATION_KEYS_PATH"`
CookieBackendURI string
CookieNames []string
AccessTokenDurationSeconds uint64 `ocisConfig:"access_token_duration_seconds" env:"IDP_ACCESS_TOKEN_EXPIRATION"`
IDTokenDurationSeconds uint64 `ocisConfig:"id_token_duration_seconds" env:"IDP_ID_TOKEN_EXPIRATION"`
RefreshTokenDurationSeconds uint64 `ocisConfig:"refresh_token_duration_seconds" env:"IDP_REFRESH_TOKEN_EXPIRATION"`
DyamicClientSecretDurationSeconds uint64 `ocisConfig:"dynamic_client_secret_duration_seconds" env:""`
}

9
idp/pkg/config/debug.go Normal file
View File

@@ -0,0 +1,9 @@
package config
// Debug defines the available debug configuration.
type Debug struct {
Addr string `ocisConfig:"addr" env:"IDP_DEBUG_ADDR"`
Token string `ocisConfig:"token" env:"IDP_DEBUG_TOKEN"`
Pprof bool `ocisConfig:"pprof" env:"IDP_DEBUG_PPROF"`
Zpages bool `ocisConfig:"zpages" env:"IDP_DEBUG_ZPAGES"`
}

View File

@@ -0,0 +1,79 @@
package config
import (
"path"
"github.com/owncloud/ocis/ocis-pkg/config/defaults"
)
func DefaultConfig() *Config {
return &Config{
Debug: Debug{
Addr: "127.0.0.1:9134",
},
HTTP: HTTP{
Addr: "127.0.0.1:9130",
Root: "/",
Namespace: "com.owncloud.web",
TLSCert: path.Join(defaults.BaseDataPath(), "idp", "server.crt"),
TLSKey: path.Join(defaults.BaseDataPath(), "idp", "server.key"),
TLS: false,
},
Service: Service{
Name: "idp",
},
Tracing: Tracing{
Enabled: false,
Type: "jaeger",
Endpoint: "",
Collector: "",
},
Asset: Asset{},
IDP: Settings{
Iss: "https://localhost:9200",
IdentityManager: "ldap",
URIBasePath: "",
SignInURI: "",
SignedOutURI: "",
AuthorizationEndpointURI: "",
EndsessionEndpointURI: "",
Insecure: false,
TrustedProxy: nil,
AllowScope: nil,
AllowClientGuests: false,
AllowDynamicClientRegistration: false,
EncryptionSecretFile: "",
Listen: "",
IdentifierClientDisabled: true,
IdentifierClientPath: path.Join(defaults.BaseDataPath(), "idp"),
IdentifierRegistrationConf: path.Join(defaults.BaseDataPath(), "idp", "identifier-registration.yaml"),
IdentifierScopesConf: "",
IdentifierDefaultBannerLogo: "",
IdentifierDefaultSignInPageText: "",
IdentifierDefaultUsernameHintText: "",
SigningKid: "",
SigningMethod: "PS256",
SigningPrivateKeyFiles: nil,
ValidationKeysPath: "",
CookieBackendURI: "",
CookieNames: nil,
AccessTokenDurationSeconds: 60 * 10, // 10 minutes
IDTokenDurationSeconds: 60 * 60, // 1 hour
RefreshTokenDurationSeconds: 60 * 60 * 24 * 365 * 3, // 1 year
DyamicClientSecretDurationSeconds: 0,
},
Ldap: Ldap{
URI: "ldap://localhost:9125",
BindDN: "cn=idp,ou=sysusers,dc=ocis,dc=test",
BindPassword: "idp",
BaseDN: "ou=users,dc=ocis,dc=test",
Scope: "sub",
LoginAttribute: "cn",
EmailAttribute: "mail",
NameAttribute: "sn",
UUIDAttribute: "uid",
UUIDAttributeType: "text",
Filter: "(objectClass=posixaccount)",
},
}
}

11
idp/pkg/config/http.go Normal file
View File

@@ -0,0 +1,11 @@
package config
// HTTP defines the available http configuration.
type HTTP struct {
Addr string `ocisConfig:"addr" env:"IDP_HTTP_ADDR"`
Root string `ocisConfig:"root" env:"IDP_HTTP_ROOT"`
Namespace string
TLSCert string `ocisConfig:"tls_cert" env:"IDP_TRANSPORT_TLS_CERT"`
TLSKey string `ocisConfig:"tls_key" env:"IDP_TRANSPORT_TLS_KEY"`
TLS bool `ocisConfig:"tls" env:"IDP_TLS"`
}

Some files were not shown because too many files have changed in this diff Show More