~juju-qa/ubuntu/yakkety/juju/2.0-rc3-again

« back to all changes in this revision

Viewing changes to src/launchpad.net/juju-core/environs/local/backend.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-04-24 22:34:47 UTC
  • Revision ID: package-import@ubuntu.com-20130424223447-f0qdji7ubnyo0s71
Tags: upstream-1.10.0.1
ImportĀ upstreamĀ versionĀ 1.10.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package local
 
2
 
 
3
import (
 
4
        "fmt"
 
5
        "io"
 
6
        "io/ioutil"
 
7
        "net"
 
8
        "net/http"
 
9
        "os"
 
10
        "path/filepath"
 
11
        "sort"
 
12
        "strings"
 
13
)
 
14
 
 
15
// storageBackend provides HTTP access to a defined path. The local
 
16
// provider otimally would use a much simpler Storage, but this
 
17
// code may be useful in storage-free environs. Here it requires
 
18
// additional authentication work before it's viable.
 
19
type storageBackend struct {
 
20
        environName string
 
21
        path        string
 
22
}
 
23
 
 
24
// ServeHTTP handles the HTTP requests to the container.
 
25
func (s *storageBackend) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 
26
        switch req.Method {
 
27
        case "GET":
 
28
                if strings.HasSuffix(req.URL.Path, "*") {
 
29
                        s.handleList(w, req)
 
30
                } else {
 
31
                        s.handleGet(w, req)
 
32
                }
 
33
        case "PUT":
 
34
                s.handlePut(w, req)
 
35
        case "DELETE":
 
36
                s.handleDelete(w, req)
 
37
        default:
 
38
                http.Error(w, "method "+req.Method+" is not supported", http.StatusMethodNotAllowed)
 
39
        }
 
40
}
 
41
 
 
42
// handleGet returns a storage file to the client.
 
43
func (s *storageBackend) handleGet(w http.ResponseWriter, req *http.Request) {
 
44
        data, err := ioutil.ReadFile(filepath.Join(s.path, req.URL.Path))
 
45
        if err != nil {
 
46
                http.Error(w, fmt.Sprintf("404 %v", err), http.StatusNotFound)
 
47
                return
 
48
        }
 
49
        w.Header().Set("Content-Type", "application/octet-stream")
 
50
        w.Write(data)
 
51
}
 
52
 
 
53
// handleList returns the file names in the storage to the client.
 
54
func (s *storageBackend) handleList(w http.ResponseWriter, req *http.Request) {
 
55
        fp := filepath.Join(s.path, req.URL.Path)
 
56
        dir, prefix := filepath.Split(fp)
 
57
        names, err := readDirs(dir, prefix[:len(prefix)-1], len(s.path)+1)
 
58
        if err != nil {
 
59
                http.Error(w, fmt.Sprintf("404 %v", err), http.StatusNotFound)
 
60
                return
 
61
        }
 
62
        sort.Strings(names)
 
63
        data := []byte(strings.Join(names, "\n"))
 
64
        w.Header().Set("Content-Type", "application/octet-stream")
 
65
        w.Write(data)
 
66
}
 
67
 
 
68
// readDirs reads the directory hierarchy and compares the found
 
69
// names with the given prefix.
 
70
func readDirs(dir, prefix string, start int) ([]string, error) {
 
71
        names := []string{}
 
72
        fis, err := ioutil.ReadDir(dir)
 
73
        if err != nil {
 
74
                return nil, err
 
75
        }
 
76
        for _, fi := range fis {
 
77
                name := fi.Name()
 
78
                if strings.HasPrefix(name, prefix) {
 
79
                        if fi.IsDir() {
 
80
                                dnames, err := readDirs(filepath.Join(dir, name), prefix, start)
 
81
                                if err != nil {
 
82
                                        return nil, err
 
83
                                }
 
84
                                names = append(names, dnames...)
 
85
                                continue
 
86
                        }
 
87
                        fullname := filepath.Join(dir, name)[start:]
 
88
                        names = append(names, fullname)
 
89
                }
 
90
        }
 
91
        return names, nil
 
92
}
 
93
 
 
94
// handlePut stores data from the client in the storage.
 
95
func (s *storageBackend) handlePut(w http.ResponseWriter, req *http.Request) {
 
96
        fp := filepath.Join(s.path, req.URL.Path)
 
97
        dir, _ := filepath.Split(fp)
 
98
        err := os.MkdirAll(dir, 0777)
 
99
        if err != nil {
 
100
                http.Error(w, fmt.Sprintf("500 %v", err), http.StatusInternalServerError)
 
101
                return
 
102
        }
 
103
        out, err := os.Create(fp)
 
104
        if err != nil {
 
105
                http.Error(w, fmt.Sprintf("500 %v", err), http.StatusInternalServerError)
 
106
                return
 
107
        }
 
108
        defer out.Close()
 
109
        if _, err := io.Copy(out, req.Body); err != nil {
 
110
                http.Error(w, fmt.Sprintf("500 %v", err), http.StatusInternalServerError)
 
111
                return
 
112
        }
 
113
        w.WriteHeader(http.StatusCreated)
 
114
}
 
115
 
 
116
// handleDelete removes a file from the storage.
 
117
func (s *storageBackend) handleDelete(w http.ResponseWriter, req *http.Request) {
 
118
        fp := filepath.Join(s.path, req.URL.Path)
 
119
        if err := os.Remove(fp); err != nil && !os.IsNotExist(err) {
 
120
                http.Error(w, fmt.Sprintf("500 %v", err), http.StatusInternalServerError)
 
121
                return
 
122
        }
 
123
        w.WriteHeader(http.StatusOK)
 
124
}
 
125
 
 
126
// listen starts an HTTP listener to serve the
 
127
// provider storage.
 
128
func listen(dataPath, environName, ip string, port int) (net.Listener, error) {
 
129
        backend := &storageBackend{
 
130
                environName: environName,
 
131
                path:        filepath.Join(dataPath, environName),
 
132
        }
 
133
        if err := os.MkdirAll(backend.path, 0777); err != nil {
 
134
                return nil, err
 
135
        }
 
136
        listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", ip, port))
 
137
        if err != nil {
 
138
                return nil, fmt.Errorf("cannot start listener: %v", err)
 
139
        }
 
140
        mux := http.NewServeMux()
 
141
        mux.Handle("/", backend)
 
142
 
 
143
        go http.Serve(listener, mux)
 
144
 
 
145
        return listener, nil
 
146
}