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  }