github.com/azure-devops-engineer/helm@v3.0.0-alpha.2+incompatible/pkg/repo/repotest/server.go (about) 1 /* 2 Copyright The Helm Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package repotest 17 18 import ( 19 "io/ioutil" 20 "net/http" 21 "net/http/httptest" 22 "os" 23 "path/filepath" 24 25 "sigs.k8s.io/yaml" 26 27 "helm.sh/helm/pkg/helmpath" 28 "helm.sh/helm/pkg/repo" 29 ) 30 31 // NewTempServer creates a server inside of a temp dir. 32 // 33 // If the passed in string is not "", it will be treated as a shell glob, and files 34 // will be copied from that path to the server's docroot. 35 // 36 // The caller is responsible for destroying the temp directory as well as stopping 37 // the server. 38 func NewTempServer(glob string) (*Server, helmpath.Home, error) { 39 tdir, err := ioutil.TempDir("", "helm-repotest-") 40 tdirh := helmpath.Home(tdir) 41 if err != nil { 42 return nil, tdirh, err 43 } 44 srv := NewServer(tdir) 45 46 if glob != "" { 47 if _, err := srv.CopyCharts(glob); err != nil { 48 srv.Stop() 49 return srv, tdirh, err 50 } 51 } 52 53 return srv, tdirh, nil 54 } 55 56 // NewServer creates a repository server for testing. 57 // 58 // docroot should be a temp dir managed by the caller. 59 // 60 // This will start the server, serving files off of the docroot. 61 // 62 // Use CopyCharts to move charts into the repository and then index them 63 // for service. 64 func NewServer(docroot string) *Server { 65 root, err := filepath.Abs(docroot) 66 if err != nil { 67 panic(err) 68 } 69 srv := &Server{ 70 docroot: root, 71 } 72 srv.Start() 73 // Add the testing repository as the only repo. 74 if err := setTestingRepository(helmpath.Home(docroot), "test", srv.URL()); err != nil { 75 panic(err) 76 } 77 return srv 78 } 79 80 // Server is an implementation of a repository server for testing. 81 type Server struct { 82 docroot string 83 srv *httptest.Server 84 middleware http.HandlerFunc 85 } 86 87 // WithMiddleware injects middleware in front of the server. This can be used to inject 88 // additional functionality like layering in an authentication frontend. 89 func (s *Server) WithMiddleware(middleware http.HandlerFunc) { 90 s.middleware = middleware 91 } 92 93 // Root gets the docroot for the server. 94 func (s *Server) Root() string { 95 return s.docroot 96 } 97 98 // CopyCharts takes a glob expression and copies those charts to the server root. 99 func (s *Server) CopyCharts(origin string) ([]string, error) { 100 files, err := filepath.Glob(origin) 101 if err != nil { 102 return []string{}, err 103 } 104 copied := make([]string, len(files)) 105 for i, f := range files { 106 base := filepath.Base(f) 107 newname := filepath.Join(s.docroot, base) 108 data, err := ioutil.ReadFile(f) 109 if err != nil { 110 return []string{}, err 111 } 112 if err := ioutil.WriteFile(newname, data, 0755); err != nil { 113 return []string{}, err 114 } 115 copied[i] = newname 116 } 117 118 err = s.CreateIndex() 119 return copied, err 120 } 121 122 // CreateIndex will read docroot and generate an index.yaml file. 123 func (s *Server) CreateIndex() error { 124 // generate the index 125 index, err := repo.IndexDirectory(s.docroot, s.URL()) 126 if err != nil { 127 return err 128 } 129 130 d, err := yaml.Marshal(index) 131 if err != nil { 132 return err 133 } 134 135 ifile := filepath.Join(s.docroot, "index.yaml") 136 return ioutil.WriteFile(ifile, d, 0755) 137 } 138 139 func (s *Server) Start() { 140 s.srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 141 if s.middleware != nil { 142 s.middleware.ServeHTTP(w, r) 143 } 144 http.FileServer(http.Dir(s.docroot)).ServeHTTP(w, r) 145 })) 146 } 147 148 // Stop stops the server and closes all connections. 149 // 150 // It should be called explicitly. 151 func (s *Server) Stop() { 152 s.srv.Close() 153 } 154 155 // URL returns the URL of the server. 156 // 157 // Example: 158 // http://localhost:1776 159 func (s *Server) URL() string { 160 return s.srv.URL 161 } 162 163 // LinkIndices links the index created with CreateIndex and makes a symboic link to the repositories/cache directory. 164 // 165 // This makes it possible to simulate a local cache of a repository. 166 func (s *Server) LinkIndices() error { 167 destfile := "test-index.yaml" 168 // Link the index.yaml file to the 169 lstart := filepath.Join(s.docroot, "index.yaml") 170 ldest := filepath.Join(s.docroot, "repository/cache", destfile) 171 return os.Symlink(lstart, ldest) 172 } 173 174 // setTestingRepository sets up a testing repository.yaml with only the given name/URL. 175 func setTestingRepository(home helmpath.Home, name, url string) error { 176 r := repo.NewFile() 177 r.Add(&repo.Entry{ 178 Name: name, 179 URL: url, 180 Cache: home.CacheIndex(name), 181 }) 182 os.MkdirAll(filepath.Join(home.Repository(), name), 0755) 183 return r.WriteFile(home.RepositoryFile(), 0644) 184 }