123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- package git_repo
- import (
- "fmt"
- "io/ioutil"
- "path/filepath"
- "strings"
- "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/types"
- "k8s.io/kubernetes/pkg/volume"
- volumeutil "k8s.io/kubernetes/pkg/volume/util"
- "k8s.io/utils/exec"
- utilstrings "k8s.io/utils/strings"
- )
- func ProbeVolumePlugins() []volume.VolumePlugin {
- return []volume.VolumePlugin{&gitRepoPlugin{nil}}
- }
- type gitRepoPlugin struct {
- host volume.VolumeHost
- }
- var _ volume.VolumePlugin = &gitRepoPlugin{}
- func wrappedVolumeSpec() volume.Spec {
- return volume.Spec{
- Volume: &v1.Volume{VolumeSource: v1.VolumeSource{EmptyDir: &v1.EmptyDirVolumeSource{}}},
- }
- }
- const (
- gitRepoPluginName = "kubernetes.io/git-repo"
- )
- func (plugin *gitRepoPlugin) Init(host volume.VolumeHost) error {
- plugin.host = host
- return nil
- }
- func (plugin *gitRepoPlugin) GetPluginName() string {
- return gitRepoPluginName
- }
- func (plugin *gitRepoPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
- volumeSource, _ := getVolumeSource(spec)
- if volumeSource == nil {
- return "", fmt.Errorf("Spec does not reference a Git repo volume type")
- }
- return fmt.Sprintf(
- "%v:%v:%v",
- volumeSource.Repository,
- volumeSource.Revision,
- volumeSource.Directory), nil
- }
- func (plugin *gitRepoPlugin) CanSupport(spec *volume.Spec) bool {
- return spec.Volume != nil && spec.Volume.GitRepo != nil
- }
- func (plugin *gitRepoPlugin) IsMigratedToCSI() bool {
- return false
- }
- func (plugin *gitRepoPlugin) RequiresRemount() bool {
- return false
- }
- func (plugin *gitRepoPlugin) SupportsMountOption() bool {
- return false
- }
- func (plugin *gitRepoPlugin) SupportsBulkVolumeVerification() bool {
- return false
- }
- func (plugin *gitRepoPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, opts volume.VolumeOptions) (volume.Mounter, error) {
- if err := validateVolume(spec.Volume.GitRepo); err != nil {
- return nil, err
- }
- return &gitRepoVolumeMounter{
- gitRepoVolume: &gitRepoVolume{
- volName: spec.Name(),
- podUID: pod.UID,
- plugin: plugin,
- },
- pod: *pod,
- source: spec.Volume.GitRepo.Repository,
- revision: spec.Volume.GitRepo.Revision,
- target: spec.Volume.GitRepo.Directory,
- exec: exec.New(),
- opts: opts,
- }, nil
- }
- func (plugin *gitRepoPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
- return &gitRepoVolumeUnmounter{
- &gitRepoVolume{
- volName: volName,
- podUID: podUID,
- plugin: plugin,
- },
- }, nil
- }
- func (plugin *gitRepoPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
- gitVolume := &v1.Volume{
- Name: volumeName,
- VolumeSource: v1.VolumeSource{
- GitRepo: &v1.GitRepoVolumeSource{},
- },
- }
- return volume.NewSpecFromVolume(gitVolume), nil
- }
- type gitRepoVolume struct {
- volName string
- podUID types.UID
- plugin *gitRepoPlugin
- volume.MetricsNil
- }
- var _ volume.Volume = &gitRepoVolume{}
- func (gr *gitRepoVolume) GetPath() string {
- name := gitRepoPluginName
- return gr.plugin.host.GetPodVolumeDir(gr.podUID, utilstrings.EscapeQualifiedName(name), gr.volName)
- }
- type gitRepoVolumeMounter struct {
- *gitRepoVolume
- pod v1.Pod
- source string
- revision string
- target string
- exec exec.Interface
- opts volume.VolumeOptions
- }
- var _ volume.Mounter = &gitRepoVolumeMounter{}
- func (b *gitRepoVolumeMounter) GetAttributes() volume.Attributes {
- return volume.Attributes{
- ReadOnly: false,
- Managed: true,
- SupportsSELinux: true,
- }
- }
- func (b *gitRepoVolumeMounter) CanMount() error {
- return nil
- }
- func (b *gitRepoVolumeMounter) SetUp(mounterArgs volume.MounterArgs) error {
- return b.SetUpAt(b.GetPath(), mounterArgs)
- }
- func (b *gitRepoVolumeMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
- if volumeutil.IsReady(b.getMetaDir()) {
- return nil
- }
-
- wrapped, err := b.plugin.host.NewWrapperMounter(b.volName, wrappedVolumeSpec(), &b.pod, b.opts)
- if err != nil {
- return err
- }
- if err := wrapped.SetUpAt(dir, mounterArgs); err != nil {
- return err
- }
- args := []string{"clone", "--", b.source}
- if len(b.target) != 0 {
- args = append(args, b.target)
- }
- if output, err := b.execCommand("git", args, dir); err != nil {
- return fmt.Errorf("failed to exec 'git %s': %s: %v",
- strings.Join(args, " "), output, err)
- }
- files, err := ioutil.ReadDir(dir)
- if err != nil {
- return err
- }
- if len(b.revision) == 0 {
-
- volumeutil.SetReady(b.getMetaDir())
- return nil
- }
- var subdir string
- switch {
- case len(b.target) != 0 && filepath.Clean(b.target) == ".":
-
- subdir = filepath.Join(dir)
- case len(files) == 1:
-
- subdir = filepath.Join(dir, files[0].Name())
- default:
-
- return fmt.Errorf("unexpected directory contents: %v", files)
- }
- if output, err := b.execCommand("git", []string{"checkout", b.revision}, subdir); err != nil {
- return fmt.Errorf("failed to exec 'git checkout %s': %s: %v", b.revision, output, err)
- }
- if output, err := b.execCommand("git", []string{"reset", "--hard"}, subdir); err != nil {
- return fmt.Errorf("failed to exec 'git reset --hard': %s: %v", output, err)
- }
- volume.SetVolumeOwnership(b, mounterArgs.FsGroup)
- volumeutil.SetReady(b.getMetaDir())
- return nil
- }
- func (b *gitRepoVolumeMounter) getMetaDir() string {
- return filepath.Join(b.plugin.host.GetPodPluginDir(b.podUID, utilstrings.EscapeQualifiedName(gitRepoPluginName)), b.volName)
- }
- func (b *gitRepoVolumeMounter) execCommand(command string, args []string, dir string) ([]byte, error) {
- cmd := b.exec.Command(command, args...)
- cmd.SetDir(dir)
- return cmd.CombinedOutput()
- }
- func validateVolume(src *v1.GitRepoVolumeSource) error {
- if err := validateNonFlagArgument(src.Repository, "repository"); err != nil {
- return err
- }
- if err := validateNonFlagArgument(src.Revision, "revision"); err != nil {
- return err
- }
- if err := validateNonFlagArgument(src.Directory, "directory"); err != nil {
- return err
- }
- return nil
- }
- type gitRepoVolumeUnmounter struct {
- *gitRepoVolume
- }
- var _ volume.Unmounter = &gitRepoVolumeUnmounter{}
- func (c *gitRepoVolumeUnmounter) TearDown() error {
- return c.TearDownAt(c.GetPath())
- }
- func (c *gitRepoVolumeUnmounter) TearDownAt(dir string) error {
- return volumeutil.UnmountViaEmptyDir(dir, c.plugin.host, c.volName, wrappedVolumeSpec(), c.podUID)
- }
- func getVolumeSource(spec *volume.Spec) (*v1.GitRepoVolumeSource, bool) {
- var readOnly bool
- var volumeSource *v1.GitRepoVolumeSource
- if spec.Volume != nil && spec.Volume.GitRepo != nil {
- volumeSource = spec.Volume.GitRepo
- readOnly = spec.ReadOnly
- }
- return volumeSource, readOnly
- }
- func validateNonFlagArgument(arg, argName string) error {
- if len(arg) > 0 && arg[0] == '-' {
- return fmt.Errorf("%q is an invalid value for %s", arg, argName)
- }
- return nil
- }
|