github.com/swiftstack/proxyfs@v0.0.0-20201223034610-5434d919416e/httpserver/config.go (about) 1 package httpserver 2 3 import ( 4 "fmt" 5 "net" 6 "strconv" 7 "sync" 8 "time" 9 10 "github.com/swiftstack/sortedmap" 11 12 "github.com/swiftstack/ProxyFS/conf" 13 "github.com/swiftstack/ProxyFS/fs" 14 "github.com/swiftstack/ProxyFS/headhunter" 15 "github.com/swiftstack/ProxyFS/inode" 16 "github.com/swiftstack/ProxyFS/transitions" 17 18 // Force importing of the following next "top-most" packages 19 _ "github.com/swiftstack/ProxyFS/fuse" 20 _ "github.com/swiftstack/ProxyFS/jrpcfs" 21 _ "github.com/swiftstack/ProxyFS/statslogger" 22 "github.com/swiftstack/ProxyFS/trackedlock" 23 ) 24 25 type ExtentMapElementStruct struct { 26 FileOffset uint64 `json:"file_offset"` 27 ContainerName string `json:"container_name"` 28 ObjectName string `json:"object_name"` 29 ObjectOffset uint64 `json:"object_offset"` 30 Length uint64 `json:"length"` 31 } 32 33 type jobState uint8 34 35 const ( 36 jobRunning jobState = iota 37 jobHalted 38 jobCompleted 39 ) 40 41 type jobTypeType uint8 42 43 const ( 44 fsckJobType jobTypeType = iota 45 scrubJobType 46 limitJobType 47 ) 48 49 type jobStruct struct { 50 id uint64 51 volume *volumeStruct 52 jobHandle fs.JobHandle 53 state jobState 54 startTime time.Time 55 endTime time.Time 56 } 57 58 // JobStatusJSONPackedStruct describes all the possible fields returned in JSON-encoded job GET body 59 type JobStatusJSONPackedStruct struct { 60 StartTime string `json:"start time"` 61 HaltTime string `json:"halt time"` 62 DoneTime string `json:"done time"` 63 ErrorList []string `json:"error list"` 64 InfoList []string `json:"info list"` 65 } 66 67 type volumeStruct struct { 68 trackedlock.Mutex 69 name string 70 fsVolumeHandle fs.VolumeHandle 71 inodeVolumeHandle inode.VolumeHandle 72 headhunterVolumeHandle headhunter.VolumeHandle 73 fsckActiveJob *jobStruct 74 fsckJobs sortedmap.LLRBTree // Key == jobStruct.id, Value == *jobStruct 75 scrubActiveJob *jobStruct 76 scrubJobs sortedmap.LLRBTree // Key == jobStruct.id, Value == *jobStruct 77 activeDefragInodeNumberSet map[inode.InodeNumber]struct{} 78 } 79 80 type globalsStruct struct { 81 trackedlock.Mutex 82 active bool 83 jobHistoryMaxSize uint32 84 whoAmI string 85 ipAddr string 86 tcpPort uint16 87 ipAddrTCPPort string 88 netListener net.Listener 89 wg sync.WaitGroup 90 confMap conf.ConfMap 91 volumeLLRB sortedmap.LLRBTree // Key == volumeStruct.name, Value == *volumeStruct 92 } 93 94 var globals globalsStruct 95 96 func init() { 97 transitions.Register("httpserver", &globals) 98 } 99 100 func (dummy *globalsStruct) Up(confMap conf.ConfMap) (err error) { 101 globals.volumeLLRB = sortedmap.NewLLRBTree(sortedmap.CompareString, nil) 102 103 globals.jobHistoryMaxSize, err = confMap.FetchOptionValueUint32("HTTPServer", "JobHistoryMaxSize") 104 if nil != err { 105 /* 106 TODO: Eventually change this to: 107 err = fmt.Errorf("confMap.FetchOptionValueString(\"HTTPServer\", \"JobHistoryMaxSize\") failed: %v", err) 108 return 109 */ 110 globals.jobHistoryMaxSize = 5 111 } 112 113 globals.whoAmI, err = confMap.FetchOptionValueString("Cluster", "WhoAmI") 114 if nil != err { 115 err = fmt.Errorf("confMap.FetchOptionValueString(\"Cluster\", \"WhoAmI\") failed: %v", err) 116 return 117 } 118 119 globals.ipAddr, err = confMap.FetchOptionValueString("Peer:"+globals.whoAmI, "PrivateIPAddr") 120 if nil != err { 121 err = fmt.Errorf("confMap.FetchOptionValueString(\"<whoAmI>\", \"PrivateIPAddr\") failed: %v", err) 122 return 123 } 124 125 globals.tcpPort, err = confMap.FetchOptionValueUint16("HTTPServer", "TCPPort") 126 if nil != err { 127 err = fmt.Errorf("confMap.FetchOptionValueUint16(\"HTTPServer\", \"TCPPort\") failed: %v", err) 128 return 129 } 130 131 globals.ipAddrTCPPort = net.JoinHostPort(globals.ipAddr, strconv.Itoa(int(globals.tcpPort))) 132 133 globals.netListener, err = net.Listen("tcp", globals.ipAddrTCPPort) 134 if nil != err { 135 err = fmt.Errorf("net.Listen(\"tcp\", \"%s\") failed: %v", globals.ipAddrTCPPort, err) 136 return 137 } 138 139 globals.active = false 140 141 globals.wg.Add(1) 142 go serveHTTP() 143 144 err = nil 145 return 146 } 147 148 func (dummy *globalsStruct) VolumeGroupCreated(confMap conf.ConfMap, volumeGroupName string, activePeer string, virtualIPAddr string) (err error) { 149 return nil 150 } 151 func (dummy *globalsStruct) VolumeGroupMoved(confMap conf.ConfMap, volumeGroupName string, activePeer string, virtualIPAddr string) (err error) { 152 return nil 153 } 154 func (dummy *globalsStruct) VolumeGroupDestroyed(confMap conf.ConfMap, volumeGroupName string) (err error) { 155 return nil 156 } 157 func (dummy *globalsStruct) VolumeCreated(confMap conf.ConfMap, volumeName string, volumeGroupName string) (err error) { 158 return nil 159 } 160 func (dummy *globalsStruct) VolumeMoved(confMap conf.ConfMap, volumeName string, volumeGroupName string) (err error) { 161 return nil 162 } 163 func (dummy *globalsStruct) VolumeDestroyed(confMap conf.ConfMap, volumeName string) (err error) { 164 return nil 165 } 166 167 func (dummy *globalsStruct) ServeVolume(confMap conf.ConfMap, volumeName string) (err error) { 168 var ( 169 ok bool 170 volume *volumeStruct 171 ) 172 173 volume = &volumeStruct{ 174 name: volumeName, 175 fsckActiveJob: nil, 176 fsckJobs: sortedmap.NewLLRBTree(sortedmap.CompareUint64, nil), 177 scrubActiveJob: nil, 178 scrubJobs: sortedmap.NewLLRBTree(sortedmap.CompareUint64, nil), 179 activeDefragInodeNumberSet: make(map[inode.InodeNumber]struct{}), 180 } 181 182 volume.fsVolumeHandle, err = fs.FetchVolumeHandleByVolumeName(volume.name) 183 if nil != err { 184 return 185 } 186 187 volume.inodeVolumeHandle, err = inode.FetchVolumeHandle(volume.name) 188 if nil != err { 189 return 190 } 191 192 volume.headhunterVolumeHandle, err = headhunter.FetchVolumeHandle(volume.name) 193 if nil != err { 194 return 195 } 196 197 globals.Lock() 198 199 ok, err = globals.volumeLLRB.Put(volumeName, volume) 200 if nil != err { 201 globals.Unlock() 202 err = fmt.Errorf("globals.volumeLLRB.Put(%s,) failed: %v", volumeName, err) 203 return 204 } 205 if !ok { 206 globals.Unlock() 207 err = fmt.Errorf("globals.volumeLLRB.Put(%s,) returned ok == false", volumeName) 208 return 209 } 210 211 globals.Unlock() 212 213 return // return err from globals.volumeLLRB.Put() sufficient 214 } 215 216 func (dummy *globalsStruct) UnserveVolume(confMap conf.ConfMap, volumeName string) (err error) { 217 var ( 218 ok bool 219 volume *volumeStruct 220 volumeAsValue sortedmap.Value 221 ) 222 223 globals.Lock() 224 225 volumeAsValue, ok, err = globals.volumeLLRB.GetByKey(volumeName) 226 if nil != err { 227 globals.Unlock() 228 err = fmt.Errorf("globals.volumeLLRB.Get(%v) failed: %v", volumeName, err) 229 return 230 } 231 232 volume, ok = volumeAsValue.(*volumeStruct) 233 if !ok { 234 globals.Unlock() 235 err = fmt.Errorf("volumeAsValue.(*volumeStruct) returned ok == false for volume %s", volumeName) 236 return 237 } 238 239 if !ok { 240 globals.Unlock() 241 return // return err from globals.volumeLLRB.GetByKey() sufficient 242 } 243 244 volume.Lock() 245 if nil != volume.fsckActiveJob { 246 volume.fsckActiveJob.jobHandle.Cancel() 247 volume.fsckActiveJob.state = jobHalted 248 volume.fsckActiveJob.endTime = time.Now() 249 volume.fsckActiveJob = nil 250 } 251 if nil != volume.scrubActiveJob { 252 volume.scrubActiveJob.jobHandle.Cancel() 253 volume.scrubActiveJob.state = jobHalted 254 volume.scrubActiveJob.endTime = time.Now() 255 volume.scrubActiveJob = nil 256 } 257 volume.Unlock() 258 259 ok, err = globals.volumeLLRB.DeleteByKey(volumeName) 260 if nil != err { 261 globals.Unlock() 262 err = fmt.Errorf("globals.volumeLLRB.DeleteByKey(%v) failed: %v", volumeName, err) 263 return 264 } 265 266 globals.Unlock() 267 268 return // return err from globals.volumeLLRB.DeleteByKey sufficient 269 } 270 271 func (dummy *globalsStruct) VolumeToBeUnserved(confMap conf.ConfMap, volumeName string) (err error) { 272 return nil 273 } 274 275 func (dummy *globalsStruct) SignaledStart(confMap conf.ConfMap) (err error) { 276 globals.confMap = confMap 277 globals.active = false 278 return nil 279 } 280 281 func (dummy *globalsStruct) SignaledFinish(confMap conf.ConfMap) (err error) { 282 globals.confMap = confMap 283 globals.active = true 284 return nil 285 } 286 287 func (dummy *globalsStruct) Down(confMap conf.ConfMap) (err error) { 288 var ( 289 numVolumes int 290 ) 291 292 globals.Lock() 293 294 numVolumes, err = globals.volumeLLRB.Len() 295 if nil != err { 296 globals.Unlock() 297 err = fmt.Errorf("httpserver.Down() couldn't read globals.volumeLLRB: %v", err) 298 return 299 } 300 if 0 != numVolumes { 301 globals.Unlock() 302 err = fmt.Errorf("httpserver.Down() called with 0 != globals.volumeLLRB.Len()") 303 return 304 } 305 306 _ = globals.netListener.Close() 307 308 globals.Unlock() 309 310 globals.wg.Wait() 311 312 err = nil 313 return 314 }