Fix CSI node bind mount and publish to correct image registry.
Use k8s mount-utils for bind mounts so the pod target directory is created before mounting, and push CI images to ghcr.io/kubelancloud/kks-csi-plugin to match the deployed chart. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -21,7 +21,7 @@ jobs:
|
|||||||
- name: Container image name (GHCR is lowercase)
|
- name: Container image name (GHCR is lowercase)
|
||||||
run: |
|
run: |
|
||||||
owner=$(echo "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]')
|
owner=$(echo "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]')
|
||||||
echo "IMAGE_NAME=${REGISTRY_HOST}/${owner}/kloud-csi-plugin" >> "$GITHUB_ENV"
|
echo "IMAGE_NAME=${REGISTRY_HOST}/${owner}/kks-csi-plugin" >> "$GITHUB_ENV"
|
||||||
echo "APP_VERSION=$(grep '^appVersion:' charts/kloud-csi/Chart.yaml | awk '{print $2}' | tr -d '\"')" >> "$GITHUB_ENV"
|
echo "APP_VERSION=$(grep '^appVersion:' charts/kloud-csi/Chart.yaml | awk '{print $2}' | tr -d '\"')" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- uses: docker/setup-buildx-action@v3
|
- uses: docker/setup-buildx-action@v3
|
||||||
@@ -61,4 +61,4 @@ jobs:
|
|||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
owner=$(echo "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]')
|
owner=$(echo "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]')
|
||||||
gh api --method PATCH "/orgs/${owner}/packages/container/kloud-csi-plugin/visibility" -f visibility=public || true
|
gh api --method PATCH "/orgs/${owner}/packages/container/kks-csi-plugin/visibility" -f visibility=public || true
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ rules:
|
|||||||
- apiGroups: ["storage.k8s.io"]
|
- apiGroups: ["storage.k8s.io"]
|
||||||
resources: ["volumeattachments/status"]
|
resources: ["volumeattachments/status"]
|
||||||
verbs: ["patch"]
|
verbs: ["patch"]
|
||||||
|
- apiGroups: ["storage.k8s.io"]
|
||||||
|
resources: ["csinodes"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
- apiGroups: ["coordination.k8s.io"]
|
- apiGroups: ["coordination.k8s.io"]
|
||||||
resources: ["leases"]
|
resources: ["leases"]
|
||||||
verbs: ["get", "watch", "list", "create", "update", "patch"]
|
verbs: ["get", "watch", "list", "create", "update", "patch"]
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ fullnameOverride: ""
|
|||||||
image:
|
image:
|
||||||
repository: ghcr.io/kubelancloud/kks-csi-plugin
|
repository: ghcr.io/kubelancloud/kks-csi-plugin
|
||||||
tag: "latest"
|
tag: "latest"
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: Always
|
||||||
|
|
||||||
imagePullSecrets: []
|
imagePullSecrets: []
|
||||||
|
|
||||||
|
|||||||
@@ -107,9 +107,15 @@ func cleanupMountPoint(target string, mounter *mount.SafeFormatAndMount) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func bindMount(source, target string) error {
|
func bindMount(source, target string) error {
|
||||||
out, err := exec.Command("mount", "--bind", source, target).CombinedOutput()
|
if !isMounted(source) {
|
||||||
if err != nil {
|
return fmt.Errorf("staging path %s is not mounted", source)
|
||||||
return fmt.Errorf("bind mount %s -> %s: %w: %s", source, target, err, strings.TrimSpace(string(out)))
|
}
|
||||||
|
if isMounted(target) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
mounter := mount.New("")
|
||||||
|
if err := mounter.Mount(source, target, "", []string{"bind"}); err != nil {
|
||||||
|
return fmt.Errorf("bind mount %s -> %s: %w", source, target, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
//go:build linux
|
||||||
|
|
||||||
|
package driver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBindMountCreatesTargetAndIsIdempotent(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
root := t.TempDir()
|
||||||
|
source := filepath.Join(root, "globalmount")
|
||||||
|
target := filepath.Join(root, "pods", "test", "mount")
|
||||||
|
if err := os.MkdirAll(source, 0o755); err != nil {
|
||||||
|
t.Fatalf("mkdir source: %v", err)
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(filepath.Join(source, "probe"), []byte("ok"), 0o644); err != nil {
|
||||||
|
t.Fatalf("write probe file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mounter := newMounter()
|
||||||
|
if err := mounter.Mount("tmpfs", source, "tmpfs", []string{}); err != nil {
|
||||||
|
t.Fatalf("mount tmpfs at source: %v", err)
|
||||||
|
}
|
||||||
|
t.Cleanup(func() {
|
||||||
|
_ = cleanupMountPoint(source, mounter)
|
||||||
|
})
|
||||||
|
|
||||||
|
if err := bindMount(source, target); err != nil {
|
||||||
|
t.Fatalf("first bindMount failed: %v", err)
|
||||||
|
}
|
||||||
|
t.Cleanup(func() {
|
||||||
|
_ = cleanupMountPoint(target, mounter)
|
||||||
|
})
|
||||||
|
|
||||||
|
if _, err := os.Stat(target); err != nil {
|
||||||
|
t.Fatalf("target mount path missing: %v", err)
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(filepath.Join(target, "probe")); err != nil {
|
||||||
|
t.Fatalf("bind mount did not expose source contents: %v", err)
|
||||||
|
}
|
||||||
|
if err := bindMount(source, target); err != nil {
|
||||||
|
t.Fatalf("second bindMount failed: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -91,8 +90,8 @@ func (s *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublish
|
|||||||
return nil, invalidArgument("staging target path is required")
|
return nil, invalidArgument("staging target path is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(filepath.Dir(req.GetTargetPath()), 0o755); err != nil {
|
if !isMounted(req.GetStagingTargetPath()) {
|
||||||
return nil, internalError(err)
|
return nil, internalError(fmt.Errorf("staging path %s is not mounted", req.GetStagingTargetPath()))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := bindMount(req.GetStagingTargetPath(), req.GetTargetPath()); err != nil {
|
if err := bindMount(req.GetStagingTargetPath(), req.GetTargetPath()); err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user