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  }