Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding an interface to the system socket to help nydusd obtain config #504

Merged
merged 8 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ type Experimental struct {
EnableStargz bool `toml:"enable_stargz"`
EnableReferrerDetect bool `toml:"enable_referrer_detect"`
TarfsConfig TarfsConfig `toml:"tarfs"`
EnableBackendSource bool `toml:"enable_backend_source"`
}

type TarfsConfig struct {
Expand Down
63 changes: 59 additions & 4 deletions config/daemonconfig/daemonconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ package daemonconfig
import (
"encoding/json"
"os"
"reflect"
"strings"

"github.com/pkg/errors"

Expand Down Expand Up @@ -75,16 +77,16 @@ type BackendConfig struct {
// Registry backend configs
Host string `json:"host,omitempty"`
Repo string `json:"repo,omitempty"`
Auth string `json:"auth,omitempty"`
RegistryToken string `json:"registry_token,omitempty"`
Auth string `json:"auth,omitempty" secret:"true"`
RegistryToken string `json:"registry_token,omitempty" secret:"true"`
BlobURLScheme string `json:"blob_url_scheme,omitempty"`
BlobRedirectedHost string `json:"blob_redirected_host,omitempty"`
Mirrors []MirrorConfig `json:"mirrors,omitempty"`

// OSS backend configs
EndPoint string `json:"endpoint,omitempty"`
AccessKeyID string `json:"access_key_id,omitempty"`
AccessKeySecret string `json:"access_key_secret,omitempty"`
AccessKeyID string `json:"access_key_id,omitempty" secret:"true"`
AccessKeySecret string `json:"access_key_secret,omitempty" secret:"true"`
BucketName string `json:"bucket_name,omitempty"`
ObjectPrefix string `json:"object_prefix,omitempty"`

Expand Down Expand Up @@ -124,6 +126,9 @@ type DeviceConfig struct {
// We don't have to persist configuration file for fscache since its configuration
// is passed through HTTP API.
func DumpConfigFile(c interface{}, path string) error {
if config.IsBackendSourceEnabled() {
c = serializeWithSecretFilter(c)
}
b, err := json.Marshal(c)
if err != nil {
return errors.Wrapf(err, "marshal config")
Expand Down Expand Up @@ -179,3 +184,53 @@ func SupplementDaemonConfig(c DaemonConfig, imageID, snapshotID string,

return nil
}

func serializeWithSecretFilter(obj interface{}) map[string]interface{} {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a UT for this func?

result := make(map[string]interface{})
value := reflect.ValueOf(obj)
typeOfObj := reflect.TypeOf(obj)

if value.Kind() == reflect.Ptr {
value = value.Elem()
typeOfObj = typeOfObj.Elem()
}

for i := 0; i < value.NumField(); i++ {
field := value.Field(i)
fieldType := typeOfObj.Field(i)
secretTag := fieldType.Tag.Get("secret")
jsonTags := strings.Split(fieldType.Tag.Get("json"), ",")
omitemptyTag := false

for _, tag := range jsonTags {
if tag == "omitempty" {
omitemptyTag = true
break
}
}

if secretTag == "true" {
continue
}

if field.Kind() == reflect.Ptr && field.IsNil() {
continue
}

if omitemptyTag && reflect.DeepEqual(reflect.Zero(field.Type()).Interface(), field.Interface()) {
continue
}

//nolint:exhaustive
switch fieldType.Type.Kind() {
case reflect.Struct:
result[jsonTags[0]] = serializeWithSecretFilter(field.Interface())
case reflect.Ptr:
result[jsonTags[0]] = serializeWithSecretFilter(field.Elem().Interface())
default:
result[jsonTags[0]] = field.Interface()
}
}

return result
}
61 changes: 61 additions & 0 deletions config/daemonconfig/daemonconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,64 @@ func TestLoadConfig(t *testing.T) {
require.Equal(t, cfg.Device.Backend.Config.SkipVerify, true)
require.Equal(t, cfg.Device.Backend.Config.Proxy.CheckInterval, 5)
}

func TestSerializeWithSecretFilter(t *testing.T) {
buf := []byte(`{
"device": {
"backend": {
"type": "registry",
"config": {
"skip_verify": true,
"host": "acr-nydus-registry-vpc.cn-hangzhou.cr.aliyuncs.com",
"repo": "test/myserver",
"auth": "token_token",
"blob_url_scheme": "http",
"proxy": {
"url": "http://p2p-proxy:65001",
"fallback": true,
"ping_url": "http://p2p-proxy:40901/server/ping",
"check_interval": 5
},
"timeout": 5,
"connect_timeout": 5,
"retry_limit": 0
}
},
"cache": {
"type": "blobcache",
"config": {
"work_dir": "/cache"
}
}
},
"mode": "direct",
"digest_validate": true,
"iostats_files": true,
"enable_xattr": true,
"fs_prefetch": {
"enable": true,
"threads_count": 10,
"merging_size": 131072
}
}`)
var cfg FuseDaemonConfig
_ = json.Unmarshal(buf, &cfg)
filter := serializeWithSecretFilter(&cfg)
jsonData, err := json.Marshal(filter)
require.Nil(t, err)
var newCfg FuseDaemonConfig
err = json.Unmarshal(jsonData, &newCfg)
require.Nil(t, err)
require.Equal(t, newCfg.FSPrefetch, cfg.FSPrefetch)
require.Equal(t, newCfg.Device.Cache.CacheType, cfg.Device.Cache.CacheType)
require.Equal(t, newCfg.Device.Cache.Config, cfg.Device.Cache.Config)
require.Equal(t, newCfg.Mode, cfg.Mode)
require.Equal(t, newCfg.DigestValidate, cfg.DigestValidate)
require.Equal(t, newCfg.IOStatsFiles, cfg.IOStatsFiles)
require.Equal(t, newCfg.Device.Backend.Config.Host, cfg.Device.Backend.Config.Host)
require.Equal(t, newCfg.Device.Backend.Config.Repo, cfg.Device.Backend.Config.Repo)
require.Equal(t, newCfg.Device.Backend.Config.Proxy, cfg.Device.Backend.Config.Proxy)
require.Equal(t, newCfg.Device.Backend.Config.BlobURLScheme, cfg.Device.Backend.Config.BlobURLScheme)
require.Equal(t, newCfg.Device.Backend.Config.Auth, "")
require.NotEqual(t, newCfg.Device.Backend.Config.Auth, cfg.Device.Backend.Config.Auth)
}
4 changes: 4 additions & 0 deletions config/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ func GetLogToStdout() bool {
return globalConfig.origin.LoggingConfig.LogToStdout
}

func IsBackendSourceEnabled() bool {
return globalConfig.origin.Experimental.EnableBackendSource && globalConfig.origin.SystemControllerConfig.Enable
}

func IsSystemControllerEnabled() bool {
return globalConfig.origin.SystemControllerConfig.Enable
}
Expand Down
3 changes: 3 additions & 0 deletions misc/snapshotter/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ enable_stargz = false
# The option enables trying to fetch the Nydus image associated with the OCI image and run it.
# Also see https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers
enable_referrer_detect = false
# Whether to enable authentication support
# The option enables nydus snapshot to provide backend information to nydusd.
enable_backend_source = false
[experimental.tarfs]
# Whether to enable nydus tarfs mode. Tarfs is supported by:
# - The EROFS filesystem driver since Linux 6.4
Expand Down
7 changes: 7 additions & 0 deletions pkg/daemon/command/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type DaemonCommand struct {
Supervisor string `type:"param" name:"supervisor"`
LogFile string `type:"param" name:"log-file"`
PrefetchFiles string `type:"param" name:"prefetch-files"`
BackendSource string `type:"param" name:"backend-source"`
}

// Build exec style command line
Expand Down Expand Up @@ -189,3 +190,9 @@ func WithUpgrade() Opt {
cmd.Upgrade = true
}
}

func WithBackendSource(source string) Opt {
return func(cmd *DaemonCommand) {
cmd.BackendSource = source
}
}
9 changes: 9 additions & 0 deletions pkg/manager/daemon_adaptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package manager

import (
"fmt"
"os"
"os/exec"
"strings"
Expand All @@ -25,6 +26,8 @@ import (
"github.com/containerd/nydus-snapshotter/pkg/prefetch"
)

const endpointGetBackend string = "/api/v1/daemons/%s/backend"

// Spawn a nydusd daemon to serve the daemon instance.
//
// When returning from `StartDaemon()` with out error:
Expand Down Expand Up @@ -156,6 +159,12 @@ func (m *Manager) BuildDaemonCommand(d *daemon.Daemon, bin string, upgrade bool)
command.WithConfig(d.ConfigFile("")),
command.WithBootstrap(bootstrap),
)
if config.IsBackendSourceEnabled() {
configAPIPath := fmt.Sprintf(endpointGetBackend, d.States.ID)
cmdOpts = append(cmdOpts,
command.WithBackendSource(config.SystemControllerAddress()+configAPIPath),
)
}
default:
return nil, errors.Errorf("invalid daemon mode %s ", d.States.DaemonMode)
}
Expand Down
43 changes: 43 additions & 0 deletions pkg/system/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ const (
endpointDaemonRecords string = "/api/v1/daemons/records"
endpointDaemonsUpgrade string = "/api/v1/daemons/upgrade"
endpointPrefetch string = "/api/v1/prefetch"
// Provide backend information
endpointGetBackend string = "/api/v1/daemons/{id}/backend"
)

const defaultErrorCode string = "Unknown"
Expand Down Expand Up @@ -171,6 +173,47 @@ func (sc *Controller) registerRouter() {
sc.router.HandleFunc(endpointDaemonsUpgrade, sc.upgradeDaemons()).Methods(http.MethodPut)
sc.router.HandleFunc(endpointDaemonRecords, sc.getDaemonRecords()).Methods(http.MethodGet)
sc.router.HandleFunc(endpointPrefetch, sc.setPrefetchConfiguration()).Methods(http.MethodPut)
sc.router.HandleFunc(endpointGetBackend, sc.getBackend()).Methods(http.MethodGet)
}

func (sc *Controller) getBackend() func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
var err error
var statusCode int

defer func() {
if err != nil {
m := newErrorMessage(err.Error())
http.Error(w, m.encode(), statusCode)
}
}()

vars := mux.Vars(r)
id := vars["id"]

for _, ma := range sc.managers {
ma.Lock()
d := ma.GetByDaemonID(id)

if d != nil {
backendType, backendConfig := d.Config.StorageBackend()
backend := struct {
BackendType string `json:"type"`
Config interface{} `json:"config"`
}{
backendType,
backendConfig,
}
jsonResponse(w, backend)
ma.Unlock()
return
}
ma.Unlock()
}

err = errdefs.ErrNotFound
statusCode = http.StatusNotFound
}
}

func (sc *Controller) setPrefetchConfiguration() func(w http.ResponseWriter, r *http.Request) {
Expand Down
Loading