add mount types.

This commit is contained in:
Miroslav Šedivý
2021-05-22 17:50:16 +02:00
parent 97b577ff55
commit 3cb777e047
6 changed files with 107 additions and 18 deletions
+4
View File
@@ -246,6 +246,10 @@ components:
RoomMount: RoomMount:
type: object type: object
properties: properties:
type:
type: string
enum: [ private, template, public ]
example: private
host_path: host_path:
type: string type: string
example: /profile example: /profile
+17
View File
@@ -113,6 +113,12 @@ export interface RoomMember {
* @interface RoomMount * @interface RoomMount
*/ */
export interface RoomMount { export interface RoomMount {
/**
*
* @type {string}
* @memberof RoomMount
*/
type?: RoomMountTypeEnum;
/** /**
* *
* @type {string} * @type {string}
@@ -126,6 +132,17 @@ export interface RoomMount {
*/ */
container_path?: string; container_path?: string;
} }
/**
* @export
* @enum {string}
*/
export enum RoomMountTypeEnum {
private = 'private',
template = 'template',
public = 'public'
}
/** /**
* *
* @export * @export
+1 -1
View File
@@ -210,7 +210,7 @@
</v-row> </v-row>
<v-row align="center" no-gutters class="mt-3"> <v-row align="center" no-gutters class="mt-3">
<h2> Mounts </h2> <h2> Mounts </h2>
<v-btn @click="data.mounts = [ ...data.mounts, { host_path: '', container_path: '' }]" icon color="green"><v-icon>mdi-plus</v-icon></v-btn> <v-btn @click="data.mounts = [ ...data.mounts, { type: 'private', host_path: '', container_path: '' }]" icon color="green"><v-icon>mdi-plus</v-icon></v-btn>
</v-row> </v-row>
<v-row align="center" v-for="({ host_path, container_path }, index) in data.mounts" :key="index"> <v-row align="center" v-for="({ host_path, container_path }, index) in data.mounts" :key="index">
<v-col class="py-0"> <v-col class="py-0">
+16
View File
@@ -22,6 +22,8 @@ type Room struct {
StorageInternal string StorageInternal string
StorageExternal string StorageExternal string
MountsWhitelist []string
InstanceName string InstanceName string
InstanceUrl string InstanceUrl string
@@ -73,6 +75,11 @@ func (Room) Init(cmd *cobra.Command) error {
return err return err
} }
cmd.PersistentFlags().StringSlice("mounts.whitelist", []string{}, "whitelisted public mounts for containers")
if err := viper.BindPFlag("mounts.whitelist", cmd.PersistentFlags().Lookup("mounts.whitelist")); err != nil {
return err
}
// Instance // Instance
cmd.PersistentFlags().String("instance.name", "neko-rooms", "unique instance name (if running muliple on the same host)") cmd.PersistentFlags().String("instance.name", "neko-rooms", "unique instance name (if running muliple on the same host)")
@@ -159,6 +166,15 @@ func (s *Room) Set() {
s.StorageEnabled = false s.StorageEnabled = false
} }
s.MountsWhitelist = viper.GetStringSlice("mounts.whitelist")
for _, path := range s.MountsWhitelist {
path = filepath.Clean(path)
if !filepath.IsAbs(path) {
log.Panic().Msg("invalid `mounts.whitelist`, must be an absolute path")
}
}
s.InstanceName = viper.GetString("instance.name") s.InstanceName = viper.GetString("instance.name")
if !dockerNames.RestrictedNamePattern.MatchString(s.InstanceName) { if !dockerNames.RestrictedNamePattern.MatchString(s.InstanceName) {
log.Panic().Msg("invalid `instance.name`, must match " + dockerNames.RestrictedNameChars) log.Panic().Msg("invalid `instance.name`, must match " + dockerNames.RestrictedNameChars)
+58 -15
View File
@@ -26,10 +26,11 @@ import (
) )
const ( const (
frontendPort = 8080 frontendPort = 8080
roomStoragePath = "./rooms" templateStoragePath = "./templates"
roomStorageUid = 1000 privateStoragePath = "./rooms"
roomStorageGid = 1000 privateStorageUid = 1000
privateStorageGid = 1000
) )
func New(config *config.Room) *RoomManagerCtx { func New(config *config.Room) *RoomManagerCtx {
@@ -195,6 +196,8 @@ func (manager *RoomManagerCtx) Create(settings types.RoomSettings) (string, erro
mounts := []dockerMount.Mount{} mounts := []dockerMount.Mount{}
for _, mount := range settings.Mounts { for _, mount := range settings.Mounts {
readOnly := false
hostPath := filepath.Clean(mount.HostPath) hostPath := filepath.Clean(mount.HostPath)
containerPath := filepath.Clean(mount.ContainerPath) containerPath := filepath.Clean(mount.ContainerPath)
@@ -202,23 +205,49 @@ func (manager *RoomManagerCtx) Create(settings types.RoomSettings) (string, erro
return "", fmt.Errorf("mount paths must be absolute") return "", fmt.Errorf("mount paths must be absolute")
} }
externalPath := path.Join(manager.config.StorageExternal, roomStoragePath, roomName, hostPath) // private container's data
internalPath := path.Join(manager.config.StorageInternal, roomStoragePath, roomName, hostPath) if mount.Type == types.MountPrivate {
// ensure that target exists
internalPath := path.Join(manager.config.StorageInternal, privateStoragePath, roomName, hostPath)
if err := os.MkdirAll(internalPath, os.ModePerm); err != nil {
return "", err
}
if err := os.MkdirAll(internalPath, os.ModePerm); err != nil { if err := utils.ChownR(internalPath, privateStorageUid, privateStorageGid); err != nil {
return "", err return "", err
} }
if err := utils.ChownR(internalPath, roomStorageUid, roomStorageGid); err != nil { // prefix host path
return "", err hostPath = path.Join(manager.config.StorageExternal, privateStoragePath, roomName, hostPath)
} else if mount.Type == types.MountTemplate {
// readonly template data
readOnly = true
// prefix host path
hostPath = path.Join(manager.config.StorageExternal, templateStoragePath, hostPath)
} else if mount.Type == types.MountPublic {
// public whitelisted mounts
var isAllowed = false
for _, path := range manager.config.MountsWhitelist {
if strings.HasPrefix(hostPath, path) {
isAllowed = true
break
}
}
if !isAllowed {
return "", fmt.Errorf("mount path is not whitelisted in config")
}
} else {
return "", fmt.Errorf("unknown mount type %q", mount.Type)
} }
mounts = append(mounts, mounts = append(mounts,
dockerMount.Mount{ dockerMount.Mount{
Type: dockerMount.TypeBind, Type: dockerMount.TypeBind,
Source: externalPath, Source: hostPath,
Target: containerPath, Target: containerPath,
ReadOnly: false, ReadOnly: readOnly,
Consistency: dockerMount.ConsistencyDefault, Consistency: dockerMount.ConsistencyDefault,
BindOptions: &dockerMount.BindOptions{ BindOptions: &dockerMount.BindOptions{
@@ -349,11 +378,25 @@ func (manager *RoomManagerCtx) GetSettings(id string) (*types.RoomSettings, erro
return nil, err return nil, err
} }
privateStorageRoot := path.Join(manager.config.StorageExternal, privateStoragePath, roomName)
templateStorageRoot := path.Join(manager.config.StorageExternal, templateStoragePath)
mounts := []types.RoomMount{} mounts := []types.RoomMount{}
dataRoot := path.Join(manager.config.StorageExternal, roomStoragePath, roomName)
for _, mount := range container.Mounts { for _, mount := range container.Mounts {
mountType := types.MountPublic
hostPath := mount.Source
if strings.HasPrefix(hostPath, privateStorageRoot) {
mountType = types.MountPrivate
hostPath = strings.TrimPrefix(hostPath, privateStorageRoot)
} else if strings.HasPrefix(hostPath, templateStorageRoot) {
mountType = types.MountTemplate
hostPath = strings.TrimPrefix(hostPath, templateStorageRoot)
}
mounts = append(mounts, types.RoomMount{ mounts = append(mounts, types.RoomMount{
HostPath: strings.TrimPrefix(mount.Source, dataRoot), Type: mountType,
HostPath: hostPath,
ContainerPath: mount.Destination, ContainerPath: mount.Destination,
}) })
} }
+11 -2
View File
@@ -39,9 +39,18 @@ type RoomEntry struct {
Created time.Time `json:"created"` Created time.Time `json:"created"`
} }
type MountType string
const (
MountPrivate MountType = "private"
MountTemplate MountType = "template"
MountPublic MountType = "public"
)
type RoomMount struct { type RoomMount struct {
HostPath string `json:"host_path"` Type MountType `json:"type"`
ContainerPath string `json:"container_path"` HostPath string `json:"host_path"`
ContainerPath string `json:"container_path"`
} }
type RoomSettings struct { type RoomSettings struct {