Added Copyright header.
[src/xds/xds-server.git] / lib / xdsserver / folder-pathmap.go
1 /*
2  * Copyright (C) 2017 "IoT.bzh"
3  * Author Sebastien Douheret <sebastien@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 package xdsserver
19
20 import (
21         "fmt"
22         "io/ioutil"
23         "os"
24         "path/filepath"
25         "strings"
26
27         common "github.com/iotbzh/xds-common/golib"
28         "github.com/iotbzh/xds-server/lib/xsapiv1"
29         uuid "github.com/satori/go.uuid"
30 )
31
32 // IFOLDER interface implementation for native/path mapping folders
33
34 // PathMap .
35 type PathMap struct {
36         *Context
37         config xsapiv1.FolderConfig
38 }
39
40 // NewFolderPathMap Create a new instance of PathMap
41 func NewFolderPathMap(ctx *Context) *PathMap {
42         f := PathMap{
43                 Context: ctx,
44                 config: xsapiv1.FolderConfig{
45                         Status: xsapiv1.StatusDisable,
46                 },
47         }
48         return &f
49 }
50
51 // NewUID Get a UUID
52 func (f *PathMap) NewUID(suffix string) string {
53         uuid := uuid.NewV1().String()
54         if len(suffix) > 0 {
55                 uuid += "_" + suffix
56         }
57         return uuid
58 }
59
60 // Add a new folder
61 func (f *PathMap) Add(cfg xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error) {
62         if cfg.DataPathMap.ServerPath == "" {
63                 return nil, fmt.Errorf("ServerPath must be set")
64         }
65
66         // Use shareRootDir if ServerPath is a relative path
67         dir := cfg.DataPathMap.ServerPath
68         if !filepath.IsAbs(dir) {
69                 dir = filepath.Join(f.Config.FileConf.ShareRootDir, dir)
70         }
71
72         // Sanity check
73         if !common.Exists(dir) {
74                 // try to create if not existing
75                 if err := os.MkdirAll(dir, 0755); err != nil {
76                         return nil, fmt.Errorf("Cannot create ServerPath directory: %s", dir)
77                 }
78         }
79         if !common.Exists(dir) {
80                 return nil, fmt.Errorf("ServerPath directory is not accessible: %s", dir)
81         }
82
83         f.config = cfg
84         f.config.RootPath = dir
85         f.config.DataPathMap.ServerPath = dir
86         f.config.IsInSync = true
87
88         // Verify file created by XDS agent when needed
89         if cfg.DataPathMap.CheckFile != "" {
90                 errMsg := "ServerPath sanity check error (%d): %v"
91                 ckFile := f.ConvPathCli2Svr(cfg.DataPathMap.CheckFile)
92                 if !common.Exists(ckFile) {
93                         return nil, fmt.Errorf(errMsg, 1, "file not present")
94                 }
95                 if cfg.DataPathMap.CheckContent != "" {
96                         fd, err := os.OpenFile(ckFile, os.O_APPEND|os.O_RDWR, 0600)
97                         if err != nil {
98                                 return nil, fmt.Errorf(errMsg, 2, err)
99                         }
100                         defer fd.Close()
101
102                         // Check specific message written by agent
103                         content, err := ioutil.ReadAll(fd)
104                         if err != nil {
105                                 return nil, fmt.Errorf(errMsg, 3, err)
106                         }
107                         if string(content) != cfg.DataPathMap.CheckContent {
108                                 return nil, fmt.Errorf(errMsg, 4, "file content differ")
109                         }
110
111                         // Write a specific message that will be check back on agent side
112                         msg := "Pathmap checked message written by xds-server ID: " + f.Config.ServerUID + "\n"
113                         if n, err := fd.WriteString(msg); n != len(msg) || err != nil {
114                                 return nil, fmt.Errorf(errMsg, 5, err)
115                         }
116                 }
117         }
118
119         f.config.Status = xsapiv1.StatusEnable
120
121         return &f.config, nil
122 }
123
124 // GetConfig Get public part of folder config
125 func (f *PathMap) GetConfig() xsapiv1.FolderConfig {
126         return f.config
127 }
128
129 // GetFullPath returns the full path of a directory (from server POV)
130 func (f *PathMap) GetFullPath(dir string) string {
131         if &dir == nil {
132                 return f.config.DataPathMap.ServerPath
133         }
134         return filepath.Join(f.config.DataPathMap.ServerPath, dir)
135 }
136
137 // ConvPathCli2Svr Convert path from Client to Server
138 func (f *PathMap) ConvPathCli2Svr(s string) string {
139         if f.config.ClientPath != "" && f.config.DataPathMap.ServerPath != "" {
140                 return strings.Replace(s,
141                         f.config.ClientPath,
142                         f.config.DataPathMap.ServerPath,
143                         -1)
144         }
145         return s
146 }
147
148 // ConvPathSvr2Cli Convert path from Server to Client
149 func (f *PathMap) ConvPathSvr2Cli(s string) string {
150         if f.config.ClientPath != "" && f.config.DataPathMap.ServerPath != "" {
151                 return strings.Replace(s,
152                         f.config.DataPathMap.ServerPath,
153                         f.config.ClientPath,
154                         -1)
155         }
156         return s
157 }
158
159 // Remove a folder
160 func (f *PathMap) Remove() error {
161         // nothing to do
162         return nil
163 }
164
165 // Update update some fields of a folder
166 func (f *PathMap) Update(cfg xsapiv1.FolderConfig) (*xsapiv1.FolderConfig, error) {
167         if f.config.ID != cfg.ID {
168                 return nil, fmt.Errorf("Invalid id")
169         }
170         f.config = cfg
171         return &f.config, nil
172 }
173
174 // RegisterEventChange requests registration for folder change event
175 func (f *PathMap) RegisterEventChange(cb *FolderEventCB, data *FolderEventCBData) error {
176         return nil
177 }
178
179 // UnRegisterEventChange remove registered callback
180 func (f *PathMap) UnRegisterEventChange() error {
181         return nil
182 }
183
184 // Sync Force folder files synchronization
185 func (f *PathMap) Sync() error {
186         return nil
187 }
188
189 // IsInSync Check if folder files are in-sync
190 func (f *PathMap) IsInSync() (bool, error) {
191         return true, nil
192 }