github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/cli/cmd/plugin/types.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 This file is part of KubeBlocks project 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU Affero General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 package plugin 21 22 import ( 23 "os" 24 "path/filepath" 25 26 "github.com/pkg/errors" 27 "sigs.k8s.io/yaml" 28 29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 ) 31 32 const ( 33 DefaultIndexURI = "https://github.com/apecloud/block-index.git" 34 DefaultIndexName = "default" 35 KrewIndexURI = "https://github.com/kubernetes-sigs/krew-index.git" 36 KrewIndexName = "krew" 37 ManifestExtension = ".yaml" 38 PluginKind = "Plugin" 39 ) 40 41 var SupportAPIVersion = []string{ 42 "krew.googlecontainertools.github.com/v1alpha2", 43 } 44 45 type Paths struct { 46 base string 47 tmp string 48 } 49 50 func (p *Paths) BasePath() string { 51 return p.base 52 } 53 54 func (p *Paths) IndexBase() string { 55 return filepath.Join(p.base, "index") 56 } 57 58 func (p *Paths) IndexPath(name string) string { 59 return filepath.Join(p.IndexBase(), name) 60 } 61 62 func (p *Paths) IndexPluginsPath(name string) []string { 63 result := make([]string, 0) 64 if _, err := os.Stat(filepath.Join(p.IndexPath(name), "plugins")); err == nil { 65 result = append(result, filepath.Join(p.IndexPath(name), "plugins")) 66 } 67 if _, err := os.Stat(filepath.Join(p.IndexPath(name), "krew-plugins")); err == nil { 68 result = append(result, filepath.Join(p.IndexPath(name), "krew-plugins")) 69 } 70 if _, err := os.Stat(filepath.Join(p.IndexPath(name), "cli-plugins")); err == nil { 71 result = append(result, filepath.Join(p.IndexPath(name), "cli-plugins")) 72 } 73 return result 74 } 75 76 func (p *Paths) InstallReceiptsPath() string { 77 return filepath.Join(p.base, "receipts") 78 } 79 80 func (p *Paths) BinPath() string { 81 return filepath.Join(p.base, "bin") 82 } 83 84 func (p *Paths) InstallPath() string { 85 return filepath.Join(p.base, "store") 86 } 87 88 func (p *Paths) PluginInstallPath(plugin string) string { 89 return filepath.Join(p.InstallPath(), plugin) 90 } 91 92 func (p *Paths) PluginVersionInstallPath(plugin, version string) string { 93 return filepath.Join(p.InstallPath(), plugin, version) 94 } 95 96 func (p *Paths) PluginInstallReceiptPath(plugin string) string { 97 return filepath.Join(p.InstallReceiptsPath(), plugin+".yaml") 98 } 99 100 type Index struct { 101 Name string 102 URL string 103 } 104 105 type Plugin struct { 106 metav1.TypeMeta `json:",inline" yaml:",inline"` 107 metav1.ObjectMeta `json:"metadata,omitempty" yaml:"metadata"` 108 109 Spec PluginSpec `json:"spec"` 110 } 111 112 // PluginSpec is the plugin specification. 113 type PluginSpec struct { 114 Version string `json:"version,omitempty"` 115 ShortDescription string `json:"shortDescription,omitempty"` 116 Description string `json:"description,omitempty"` 117 Caveats string `json:"caveats,omitempty"` 118 Homepage string `json:"homepage,omitempty"` 119 120 Platforms []Platform `json:"platforms,omitempty"` 121 } 122 123 // Platform describes how to perform an installation on a specific platform 124 // and how to match the target platform (os, arch). 125 type Platform struct { 126 URI string `json:"uri,omitempty"` 127 Sha256 string `json:"sha256,omitempty"` 128 129 Selector *metav1.LabelSelector `json:"selector,omitempty"` 130 Files []FileOperation `json:"files"` 131 132 // Bin specifies the path to the plugin executable. 133 // The path is relative to the root of the installation folder. 134 // The binary will be linked after all FileOperations are executed. 135 Bin string `json:"bin"` 136 } 137 138 // FileOperation specifies a file copying operation from plugin archive to the 139 // installation directory. 140 type FileOperation struct { 141 From string `json:"from,omitempty"` 142 To string `json:"to,omitempty"` 143 } 144 145 // Receipt describes a plugin receipt file. 146 type Receipt struct { 147 Plugin `json:",inline" yaml:",inline"` 148 149 Status ReceiptStatus `json:"status"` 150 } 151 152 // ReceiptStatus contains information about the installed plugin. 153 type ReceiptStatus struct { 154 Source SourceIndex `json:"source"` 155 } 156 157 // SourceIndex contains information about the index a plugin was installed from. 158 type SourceIndex struct { 159 // Name is the configured name of an index a plugin was installed from. 160 Name string `json:"name"` 161 } 162 163 type InstallOpts struct { 164 ArchiveFileOverride string 165 } 166 167 type installOperation struct { 168 pluginName string 169 platform Platform 170 171 binDir string 172 installDir string 173 } 174 175 // NewReceipt returns a new receipt with the given plugin and index name. 176 func NewReceipt(plugin Plugin, indexName string, timestamp metav1.Time) Receipt { 177 plugin.CreationTimestamp = timestamp 178 return Receipt{ 179 Plugin: plugin, 180 Status: ReceiptStatus{ 181 Source: SourceIndex{ 182 Name: indexName, 183 }, 184 }, 185 } 186 } 187 func StoreReceipt(receipt Receipt, dest string) error { 188 yamlBytes, err := yaml.Marshal(receipt) 189 if err != nil { 190 return errors.Wrapf(err, "convert to yaml") 191 } 192 193 err = os.WriteFile(dest, yamlBytes, 0o644) 194 return errors.Wrapf(err, "write plugin receipt %q", dest) 195 }