From e63c43e1503f04e827e570a020a9135e6600d4a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0ediv=C3=BD?= Date: Sat, 22 May 2021 00:45:09 +0200 Subject: [PATCH] add internal & external storage. --- dev/start | 9 ++++--- internal/config/room.go | 53 ++++++++++++++++++++++++++++------------ internal/room/manager.go | 19 ++++++++++---- 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/dev/start b/dev/start index 8388934..eabd482 100755 --- a/dev/start +++ b/dev/start @@ -9,15 +9,18 @@ fi export $(cat ../.env | sed 's/#.*//g' | xargs) -mkdir -p "./data" +DATA_PATH="./data" +mkdir -p "${DATA_PATH}" docker run --rm -it \ --name="neko_rooms_server" \ - -v "${PWD}/../:/app" \ + -v "`realpath ..`:/app" \ + -v "`realpath ${DATA_PATH}`:/data" \ -e "TZ=${TZ}" \ -e "NEKO_ROOMS_EPR=${NEKO_ROOMS_EPR}" \ -e "NEKO_ROOMS_NAT1TO1=${NEKO_ROOMS_NAT1TO1}" \ - -e "NEKO_ROOMS_INSTANCE_DATA=`realpath ./data`" \ + -e "NEKO_ROOMS_STORAGE_INTERNAL=/data" \ + -e "NEKO_ROOMS_STORAGE_EXTERNAL=`realpath ${DATA_PATH}`" \ -e "NEKO_ROOMS_TRAEFIK_DOMAIN=${NEKO_ROOMS_TRAEFIK_DOMAIN}" \ -e "NEKO_ROOMS_TRAEFIK_ENTRYPOINT=${NEKO_ROOMS_TRAEFIK_ENTRYPOINT}" \ -e "NEKO_ROOMS_TRAEFIK_NETWORK=${NEKO_ROOMS_TRAEFIK_NETWORK}" \ diff --git a/internal/config/room.go b/internal/config/room.go index e308fe3..167c200 100644 --- a/internal/config/room.go +++ b/internal/config/room.go @@ -18,9 +18,12 @@ type Room struct { NAT1To1IPs []string NekoImages []string + StorageEnabled bool + StorageInternal string + StorageExternal string + InstanceName string InstanceUrl string - InstanceData string TraefikDomain string TraefikEntrypoint string @@ -53,6 +56,23 @@ func (Room) Init(cmd *cobra.Command) error { return err } + // Data + + cmd.PersistentFlags().Bool("storage.enabled", true, "whether storage is enabled, where peristent containers data will be stored") + if err := viper.BindPFlag("storage.enabled", cmd.PersistentFlags().Lookup("storage.enabled")); err != nil { + return err + } + + cmd.PersistentFlags().String("storage.external", "", "external absolute path (on the host) to storage folder") + if err := viper.BindPFlag("storage.external", cmd.PersistentFlags().Lookup("storage.external")); err != nil { + return err + } + + cmd.PersistentFlags().String("storage.internal", "/data", "internal absolute path (inside container) to storage folder") + if err := viper.BindPFlag("storage.internal", cmd.PersistentFlags().Lookup("storage.internal")); err != nil { + return err + } + // Instance cmd.PersistentFlags().String("instance.name", "neko-rooms", "unique instance name (if running muliple on the same host)") @@ -65,11 +85,6 @@ func (Room) Init(cmd *cobra.Command) error { return err } - cmd.PersistentFlags().String("instance.data", "", "absolute path on host to a folder, where peristent containers data will be stored") - if err := viper.BindPFlag("instance.data", cmd.PersistentFlags().Lookup("instance.url")); err != nil { - return err - } - // Traefik cmd.PersistentFlags().String("traefik.domain", "neko.lan", "traefik: domain on which will be container hosted") @@ -128,22 +143,28 @@ func (s *Room) Set() { s.NAT1To1IPs = viper.GetStringSlice("nat1to1") s.NekoImages = viper.GetStringSlice("neko_images") + s.StorageEnabled = viper.GetBool("storage.enabled") + s.StorageInternal = viper.GetString("storage.internal") + s.StorageExternal = viper.GetString("storage.external") + + if s.StorageInternal != "" && s.StorageExternal != "" { + s.StorageInternal = filepath.Clean(s.StorageInternal) + s.StorageExternal = filepath.Clean(s.StorageExternal) + + if !filepath.IsAbs(s.StorageInternal) || !filepath.IsAbs(s.StorageExternal) { + log.Panic().Msg("invalid `storage.internal` or `storage.external`, must be an absolute path") + } + } else { + log.Warn().Msg("missing `storage.internal` or `storage.external`, storage is unavailable") + s.StorageEnabled = false + } + s.InstanceName = viper.GetString("instance.name") if !dockerNames.RestrictedNamePattern.MatchString(s.InstanceName) { log.Panic().Msg("invalid `instance.name`, must match " + dockerNames.RestrictedNameChars) } s.InstanceUrl = viper.GetString("instance.url") - s.InstanceData = viper.GetString("instance.data") - if s.InstanceData != "" { - s.InstanceData = filepath.Clean(s.InstanceData) - - if !filepath.IsAbs(s.InstanceData) { - log.Panic().Msg("invalid `instance.data`, must be an absolute path") - } - } else { - log.Warn().Msg("missing `instance.data`, container mounts are unavailable") - } s.TraefikDomain = viper.GetString("traefik.domain") s.TraefikEntrypoint = viper.GetString("traefik.entrypoint") diff --git a/internal/room/manager.go b/internal/room/manager.go index ac8fdae..5486c03 100644 --- a/internal/room/manager.go +++ b/internal/room/manager.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "os" "path" "path/filepath" "strings" @@ -25,7 +26,8 @@ import ( ) const ( - frontendPort = 8080 + frontendPort = 8080 + roomStoragePath = "./rooms" ) func New(config *config.Room) *RoomManagerCtx { @@ -91,8 +93,8 @@ func (manager *RoomManagerCtx) Create(settings types.RoomSettings) (string, erro return "", fmt.Errorf("invalid container name, must match " + dockerNames.RestrictedNameChars) } - if manager.config.InstanceData == "" && len(settings.Mounts) > 0 { - return "", fmt.Errorf("mounts cannot be specified, because `instance.data` config value is not set") + if !manager.config.StorageEnabled && len(settings.Mounts) > 0 { + return "", fmt.Errorf("mounts cannot be specified, because storage is disabled or unavailable") } if in, _ := utils.ArrayIn(settings.NekoImage, manager.config.NekoImages); !in { @@ -198,10 +200,17 @@ func (manager *RoomManagerCtx) Create(settings types.RoomSettings) (string, erro return "", fmt.Errorf("mount paths must be absolute") } + externalPath := path.Join(manager.config.StorageExternal, roomStoragePath, roomName, hostPath) + internalPath := path.Join(manager.config.StorageInternal, roomStoragePath, roomName, hostPath) + + if err := os.MkdirAll(internalPath, os.ModePerm); err != nil { + return "", err + } + mounts = append(mounts, dockerMount.Mount{ Type: dockerMount.TypeBind, - Source: path.Join(manager.config.InstanceData, roomName, hostPath), + Source: externalPath, Target: containerPath, ReadOnly: false, Consistency: dockerMount.ConsistencyDefault, @@ -335,7 +344,7 @@ func (manager *RoomManagerCtx) GetSettings(id string) (*types.RoomSettings, erro } mounts := []types.RoomMount{} - dataRoot := path.Join(manager.config.InstanceData, roomName) + dataRoot := path.Join(manager.config.StorageExternal, roomStoragePath, roomName) for _, mount := range container.Mounts { mounts = append(mounts, types.RoomMount{ HostPath: strings.TrimPrefix(mount.Source, dataRoot),