Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
@@ -0,0 +1,54 @@
package command
import (
"fmt"
"net/http"
"github.com/qsfera/server/pkg/config/configlog"
"github.com/qsfera/server/pkg/log"
"github.com/qsfera/server/services/graph/pkg/config"
"github.com/qsfera/server/services/graph/pkg/config/parser"
"github.com/spf13/cobra"
)
// Health is the entrypoint for the health command.
func Health(cfg *config.Config) *cobra.Command {
return &cobra.Command{
Use: "health",
Short: "check health status",
PreRunE: func(cmd *cobra.Command, args []string) error {
return configlog.ReturnError(parser.ParseConfig(cfg))
},
RunE: func(cmd *cobra.Command, args []string) error {
logger := log.Configure(cfg.Service.Name, cfg.Commons, cfg.LogLevel)
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
},
}
}
+36
View File
@@ -0,0 +1,36 @@
package command
import (
"os"
"github.com/qsfera/server/pkg/clihelper"
"github.com/qsfera/server/services/graph/pkg/config"
"github.com/spf13/cobra"
)
// GetCommands provides all commands for this service
func GetCommands(cfg *config.Config) []*cobra.Command {
return append([]*cobra.Command{
// start this service
Server(cfg),
// interaction with this service
// infos about this service
Health(cfg),
Version(cfg),
}, UnifiedRoles(cfg)...)
}
// Execute is the entry point for the qsfera graph command.
func Execute(cfg *config.Config) error {
app := clihelper.DefaultApp(&cobra.Command{
Use: "graph",
Short: "Serve Graph API for КуСфера",
})
app.AddCommand(GetCommands(cfg)...)
app.SetArgs(os.Args[1:])
return app.ExecuteContext(cfg.Context)
}
+126
View File
@@ -0,0 +1,126 @@
package command
import (
"context"
"fmt"
"os/signal"
"github.com/qsfera/server/pkg/config/configlog"
"github.com/qsfera/server/pkg/log"
"github.com/qsfera/server/pkg/runner"
"github.com/qsfera/server/pkg/tracing"
"github.com/qsfera/server/pkg/version"
"github.com/qsfera/server/services/graph/pkg/config"
"github.com/qsfera/server/services/graph/pkg/config/parser"
"github.com/qsfera/server/services/graph/pkg/metrics"
"github.com/qsfera/server/services/graph/pkg/server/debug"
"github.com/qsfera/server/services/graph/pkg/server/http"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
// Server is the entrypoint for the server command.
func Server(cfg *config.Config) *cobra.Command {
return &cobra.Command{
Use: "server",
Short: fmt.Sprintf("start the %s service without runtime (unsupervised mode)", cfg.Service.Name),
PreRunE: func(cmd *cobra.Command, args []string) error {
return configlog.ReturnFatal(parser.ParseConfig(cfg))
},
RunE: func(cmd *cobra.Command, args []string) error {
logger := log.Configure(cfg.Service.Name, cfg.Commons, cfg.LogLevel)
traceProvider, err := tracing.GetTraceProvider(cmd.Context(), cfg.Commons.TracesExporter, cfg.Service.Name)
if err != nil {
return err
}
var cancel context.CancelFunc
if cfg.Context == nil {
cfg.Context, cancel = signal.NotifyContext(context.Background(), runner.StopSignals...)
defer cancel()
}
ctx := cfg.Context
mtrcs := metrics.New()
mtrcs.BuildInfo.WithLabelValues(version.GetString()).Set(1)
var kv jetstream.KeyValue
// Allow to run without a NATS store (e.g. for the standalone Education provisioning service)
if len(cfg.Store.Nodes) > 0 {
//Connect to NATS servers
natsOptions := nats.Options{
Servers: cfg.Store.Nodes,
User: cfg.Store.AuthUsername,
Password: cfg.Store.AuthPassword,
}
conn, err := natsOptions.Connect()
if err != nil {
return err
}
js, err := jetstream.New(conn)
if err != nil {
return err
}
kv, err = js.KeyValue(ctx, cfg.Store.Database)
if err != nil {
if !errors.Is(err, jetstream.ErrBucketNotFound) {
return fmt.Errorf("failed to get bucket (%s): %w", cfg.Store.Database, err)
}
kv, err = js.CreateKeyValue(ctx, jetstream.KeyValueConfig{
Bucket: cfg.Store.Database,
})
if err != nil {
return fmt.Errorf("failed to create bucket (%s): %w", cfg.Store.Database, err)
}
}
}
gr := runner.NewGroup()
{
server, err := http.Server(
http.Logger(logger),
http.Context(ctx),
http.Config(cfg),
http.Metrics(mtrcs),
http.TraceProvider(traceProvider),
http.NatsKeyValue(kv),
)
if err != nil {
logger.Error().Err(err).Str("transport", "http").Msg("Failed to initialize server")
return err
}
gr.Add(runner.NewGoMicroHttpServerRunner(cfg.Service.Name+".http", server))
}
{
server, err := debug.Server(
debug.Logger(logger),
debug.Context(ctx),
debug.Config(cfg),
)
if err != nil {
logger.Info().Err(err).Str("transport", "debug").Msg("Failed to initialize server")
return err
}
gr.Add(runner.NewGolangHttpServerRunner(cfg.Service.Name+".debug", server))
}
grResults := gr.Run(ctx)
// return the first non-nil error found in the results
for _, grResult := range grResults {
if grResult.RunnerError != nil {
return grResult.RunnerError
}
}
return nil
},
}
}
@@ -0,0 +1,103 @@
package command
import (
"os"
"slices"
"strings"
"github.com/qsfera/server/pkg/config/configlog"
"github.com/qsfera/server/services/graph/pkg/config"
"github.com/qsfera/server/services/graph/pkg/config/parser"
"github.com/qsfera/server/services/graph/pkg/unifiedrole"
"github.com/olekukonko/tablewriter"
"github.com/olekukonko/tablewriter/renderer"
"github.com/olekukonko/tablewriter/tw"
"github.com/spf13/cobra"
)
var (
unifiedRolesNames = map[string]string{
unifiedrole.UnifiedRoleViewerID: "Viewer",
unifiedrole.UnifiedRoleViewerListGrantsID: "ViewerListGrants",
unifiedrole.UnifiedRoleSpaceViewerID: "SpaceViewer",
unifiedrole.UnifiedRoleEditorID: "Editor",
unifiedrole.UnifiedRoleEditorListGrantsID: "EditorListGrants",
unifiedrole.UnifiedRoleSpaceEditorID: "SpaceEditor",
unifiedrole.UnifiedRoleSpaceEditorWithoutVersionsID: "SpaceEditorWithoutVersions",
unifiedrole.UnifiedRoleFileEditorID: "FileEditor",
unifiedrole.UnifiedRoleFileEditorListGrantsID: "FileEditorListGrants",
unifiedrole.UnifiedRoleEditorLiteID: "EditorLite",
unifiedrole.UnifiedRoleManagerID: "SpaceManager",
unifiedrole.UnifiedRoleSecureViewerID: "SecureViewer",
}
)
// UnifiedRoles bundles available commands for unified roles
func UnifiedRoles(cfg *config.Config) []*cobra.Command {
cmds := []*cobra.Command{
listUnifiedRoles(cfg),
}
for _, cmd := range cmds {
cmd.Use = strings.Join([]string{cmd.Use, "unified-roles"}, "-")
cmd.PreRunE = func(cmd *cobra.Command, args []string) error {
return configlog.ReturnError(parser.ParseConfig(cfg))
}
}
return cmds
}
// unifiedRolesStatus lists available unified roles, it contains an indicator to show if the role is enabled or not
func listUnifiedRoles(cfg *config.Config) *cobra.Command {
return &cobra.Command{
Use: "list",
Short: "list available unified roles",
RunE: func(cmd *cobra.Command, args []string) error {
r := tw.Rendition{
Settings: tw.Settings{
Separators: tw.Separators{
BetweenRows: tw.On,
},
},
}
tbl := tablewriter.NewTable(os.Stdout, tablewriter.WithRenderer(renderer.NewBlueprint(r)))
headers := []string{"Name", "UID", "Enabled", "Description", "Condition", "Allowed resource actions"}
tbl.Header(headers)
for _, definition := range unifiedrole.GetRoles(unifiedrole.RoleFilterAll()) {
const enabled = "enabled"
const disabled = "disabled"
rows := [][]string{
{unifiedRolesNames[definition.GetId()], definition.GetId(), disabled, definition.GetDescription()},
}
if slices.Contains(cfg.UnifiedRoles.AvailableRoles, definition.GetId()) {
rows[0][2] = enabled
}
for i, rolePermission := range definition.GetRolePermissions() {
actions := strings.Join(rolePermission.GetAllowedResourceActions(), "\n")
row := []string{rolePermission.GetCondition(), actions}
switch i {
case 0:
rows[0] = append(rows[0], row...)
default:
rows[0][4] = rows[0][4] + "\n" + rolePermission.GetCondition()
}
}
for _, row := range rows {
// balance the row before adding it to the table,
// this prevents the row from having empty columns.
tbl.Append(append(row, make([]string, len(headers)-len(row))...))
}
}
tbl.Render()
return nil
},
}
}
@@ -0,0 +1,50 @@
package command
import (
"fmt"
"os"
"github.com/qsfera/server/pkg/registry"
"github.com/qsfera/server/pkg/version"
"github.com/qsfera/server/services/graph/pkg/config"
"github.com/olekukonko/tablewriter"
"github.com/olekukonko/tablewriter/tw"
"github.com/spf13/cobra"
)
// Version prints the service versions of all running instances.
func Version(cfg *config.Config) *cobra.Command {
return &cobra.Command{
Use: "version",
Short: "print the version of this binary and the running service instances",
RunE: func(cmd *cobra.Command, args []string) error {
fmt.Println("Version: " + version.GetString())
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 := tablewriter.NewTable(os.Stdout, tablewriter.WithHeaderAutoFormat(tw.Off))
table.Header([]string{"Version", "Address", "Id"})
for _, s := range services {
for _, n := range s.Nodes {
table.Append([]string{s.Version, n.Address, n.Id})
}
}
table.Render()
return nil
},
}
}