sigs.k8s.io/cluster-api@v1.7.1/cmd/clusterctl/client/repository/repository_memory.go (about) 1 /* 2 Copyright 2021 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package repository 18 19 import ( 20 "context" 21 "fmt" 22 23 "github.com/pkg/errors" 24 "k8s.io/apimachinery/pkg/runtime" 25 "k8s.io/apimachinery/pkg/runtime/serializer" 26 27 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 28 clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" 29 "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/scheme" 30 ) 31 32 // MemoryRepository contains an instance of the repository data. 33 type MemoryRepository struct { 34 defaultVersion string 35 rootPath string 36 componentsPath string 37 versions map[string]bool 38 files map[string][]byte 39 } 40 41 var _ Repository = &MemoryRepository{} 42 43 // NewMemoryRepository returns a new MemoryRepository instance. 44 func NewMemoryRepository() *MemoryRepository { 45 return &MemoryRepository{ 46 versions: map[string]bool{}, 47 files: map[string][]byte{}, 48 } 49 } 50 51 // DefaultVersion returns the default version for this repository. 52 // NOTE: The DefaultVersion is a required info usually derived from the repository configuration, 53 // and it is used whenever the users gets files from the repository without providing a specific version. 54 func (f *MemoryRepository) DefaultVersion() string { 55 if f.defaultVersion == "" { 56 return latestVersionTag 57 } 58 return f.defaultVersion 59 } 60 61 // RootPath returns the RootPath for this repository. 62 // NOTE: The RootPath is a required info usually derived from the repository configuration, 63 // and it is used to map the file path to the internal repository structure. 64 func (f *MemoryRepository) RootPath() string { 65 return f.rootPath 66 } 67 68 // ComponentsPath returns ComponentsPath for this repository 69 // NOTE: The ComponentsPath is a required info usually derived from the repository configuration, 70 // and it is used to identify the components yaml for the provider. 71 func (f *MemoryRepository) ComponentsPath() string { 72 return f.componentsPath 73 } 74 75 // GetFile returns a file for a given provider version. 76 // NOTE: If the provided version is missing, the default version is used. 77 func (f *MemoryRepository) GetFile(ctx context.Context, version string, path string) ([]byte, error) { 78 if version == "" { 79 version = f.DefaultVersion() 80 } 81 if version == latestVersionTag { 82 var err error 83 version, err = latestContractRelease(ctx, f, clusterv1.GroupVersion.Version) 84 if err != nil { 85 return nil, err 86 } 87 } 88 if _, ok := f.versions[version]; !ok { 89 return nil, errors.Errorf("unable to get files for version %s", version) 90 } 91 92 for p, c := range f.files { 93 if p == vpath(version, path) { 94 return c, nil 95 } 96 } 97 return nil, errors.Errorf("unable to get file %s for version %s", path, version) 98 } 99 100 // GetVersions returns the list of versions that are available. 101 func (f *MemoryRepository) GetVersions(_ context.Context) ([]string, error) { 102 v := make([]string, 0, len(f.versions)) 103 for k := range f.versions { 104 v = append(v, k) 105 } 106 return v, nil 107 } 108 109 // WithPaths allows setting of the rootPath and componentsPath fields. 110 func (f *MemoryRepository) WithPaths(rootPath, componentsPath string) *MemoryRepository { 111 f.rootPath = rootPath 112 f.componentsPath = componentsPath 113 return f 114 } 115 116 // WithVersions allows setting of the available versions. 117 // NOTE: When adding a file to the repository for a specific version, a version 118 // is automatically generated if missing; this func allows to define versions without any file. 119 func (f *MemoryRepository) WithVersions(version ...string) *MemoryRepository { 120 for _, v := range version { 121 f.versions[v] = true 122 } 123 return f 124 } 125 126 // WithDefaultVersion allows setting of the default version. 127 func (f *MemoryRepository) WithDefaultVersion(version string) *MemoryRepository { 128 f.defaultVersion = version 129 return f 130 } 131 132 // WithFile allows setting of a file for a given version. 133 // NOTE: 134 // - If the provided version is missing, a new one will be generated automatically. 135 // - If the defaultVersion has not been set, it will be initialized with the first version passed in WithFile(). 136 // - If the version is "latest" or "", nothing will be added. 137 func (f *MemoryRepository) WithFile(version, path string, content []byte) *MemoryRepository { 138 if version == latestVersionTag || version == "" { 139 return f 140 } 141 142 f.versions[version] = true 143 f.files[vpath(version, path)] = content 144 145 if f.defaultVersion == "" { 146 f.defaultVersion = version 147 } 148 return f 149 } 150 151 // WithMetadata allows setting of the metadata. 152 func (f *MemoryRepository) WithMetadata(version string, metadata *clusterctlv1.Metadata) *MemoryRepository { 153 codecs := serializer.NewCodecFactory(scheme.Scheme) 154 155 mediaType := "application/yaml" 156 info, match := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), mediaType) 157 if !match { 158 panic("failed to get SerializerInfo for application/yaml") 159 } 160 161 metadata.SetGroupVersionKind(clusterctlv1.GroupVersion.WithKind("Metadata")) 162 163 encoder := codecs.EncoderForVersion(info.Serializer, metadata.GroupVersionKind().GroupVersion()) 164 data, err := runtime.Encode(encoder, metadata) 165 if err != nil { 166 panic(err) 167 } 168 169 return f.WithFile(version, "metadata.yaml", data) 170 } 171 172 func vpath(version string, path string) string { 173 return fmt.Sprintf("%s/%s", version, path) 174 }