Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: introduce emulation for sc, pv and pvc #38

Merged
merged 5 commits into from
Sep 4, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/k2d.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ func main() {
container.Add(apis.Events())
// /apis/authorization.k8s.io
container.Add(apis.Authorization())
// /apis/storage.k8s.io
container.Add(apis.Storages())

k2d := k2d.NewK2DAPI(serverConfiguration, kubeDockerAdapter)
// /k2d/kubeconfig
Expand Down
8 changes: 7 additions & 1 deletion internal/adapter/naming.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

// Each container is named using the following format:
// [namespace]-[container-name]
func buildContainerName(containerName, namespace string) string {
func buildContainerName(containerName string, namespace string) string {
stevensbkang marked this conversation as resolved.
Show resolved Hide resolved
containerName = strings.TrimPrefix(containerName, "/")
return fmt.Sprintf("%s-%s", namespace, containerName)
}
Expand All @@ -17,3 +17,9 @@ func buildContainerName(containerName, namespace string) string {
func buildNetworkName(namespace string) string {
return fmt.Sprintf("k2d-%s", namespace)
}

// Each persistentVolume is named using the following format:
// k2d-pv-[namespace]-[volume-name]
func buildPersistentVolumeName(volumeName string, namespace string) string {
return fmt.Sprintf("k2d-pv-%s-%s", namespace, volumeName)
}
180 changes: 180 additions & 0 deletions internal/adapter/persistentvolume.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package adapter

import (
"context"
"fmt"
"time"

"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/volume"
k2dtypes "github.com/portainer/k2d/internal/adapter/types"
"github.com/portainer/k2d/internal/k8s"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/apis/core"
)

func (adapter *KubeDockerAdapter) GetPersistentVolume(ctx context.Context, persistentVolumeName string) (*corev1.PersistentVolume, error) {
labelFilter := filters.NewArgs()
labelFilter.Add("name", persistentVolumeName)
labelFilter.Add("label", fmt.Sprintf("%s=%s", k2dtypes.PersistentVolumeLabelKey, persistentVolumeName))

volumeList, err := adapter.cli.VolumeList(ctx, volume.ListOptions{Filters: labelFilter})
stevensbkang marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, fmt.Errorf("unable to list volumes to return the output values from a Docker volume: %w", err)
}

if len(volumeList.Volumes) > 0 {
creationDate, err := time.Parse(time.RFC3339, volumeList.Volumes[0].CreatedAt)
if err != nil {
return nil, fmt.Errorf("unable to parse volume creation date: %w", err)
}

resourceList := corev1.ResourceList{}
if volumeList.Volumes[0].UsageData != nil {
resourceList[corev1.ResourceStorage] = resource.MustParse(fmt.Sprint(volumeList.Volumes[0].UsageData.Size))
}

return &corev1.PersistentVolume{
stevensbkang marked this conversation as resolved.
Show resolved Hide resolved
ObjectMeta: metav1.ObjectMeta{
Name: volumeList.Volumes[0].Name,
CreationTimestamp: metav1.Time{
Time: creationDate,
},
},
TypeMeta: metav1.TypeMeta{
Kind: "PersistentVolume",
APIVersion: "v1",
},
Spec: corev1.PersistentVolumeSpec{
Capacity: resourceList,
AccessModes: []corev1.PersistentVolumeAccessMode{
corev1.ReadWriteOnce,
},
PersistentVolumeReclaimPolicy: corev1.PersistentVolumeReclaimDelete,
PersistentVolumeSource: corev1.PersistentVolumeSource{
HostPath: &corev1.HostPathVolumeSource{
Path: volumeList.Volumes[0].Mountpoint,
},
},
ClaimRef: nil,
},
Status: corev1.PersistentVolumeStatus{
Phase: corev1.VolumeBound,
},
}, nil
}

return nil, nil
}

func (adapter *KubeDockerAdapter) ListPersistentVolumes(ctx context.Context) (core.PersistentVolumeList, error) {
persistentVolumes, err := adapter.listPersistentVolumes(ctx)
if err != nil {
return core.PersistentVolumeList{}, fmt.Errorf("unable to list nodes: %w", err)
}

return persistentVolumes, nil
}

func (adapter *KubeDockerAdapter) GetPersistentVolumeTable(ctx context.Context) (*metav1.Table, error) {
persistentVolumeList, err := adapter.listPersistentVolumes(ctx)
if err != nil {
return &metav1.Table{}, fmt.Errorf("unable to list nodes: %w", err)
}

return k8s.GenerateTable(&persistentVolumeList)
}

func (adapter *KubeDockerAdapter) listPersistentVolumes(ctx context.Context) (core.PersistentVolumeList, error) {
labelFilter := filters.NewArgs()
labelFilter.Add("label", k2dtypes.PersistentVolumeLabelKey)

volumeList, err := adapter.cli.VolumeList(ctx, volume.ListOptions{Filters: labelFilter})
if err != nil {
return core.PersistentVolumeList{}, fmt.Errorf("unable to list volumes to return the output values from a Docker volume: %w", err)
}

persistentVolumes := []core.PersistentVolume{}

for volume := range volumeList.Volumes {
creationDate, err := time.Parse(time.RFC3339, volumeList.Volumes[volume].CreatedAt)
if err != nil {
return core.PersistentVolumeList{}, fmt.Errorf("unable to parse volume creation date: %w", err)
}

resourceList := core.ResourceList{}
if volumeList.Volumes[volume].UsageData != nil {
resourceList[core.ResourceStorage] = resource.MustParse(fmt.Sprint(volumeList.Volumes[volume].UsageData.Size))
}

persistentClaimReference := &core.ObjectReference{
Kind: "PersistentVolumeClaim",
Namespace: volumeList.Volumes[volume].Labels[k2dtypes.NamespaceLabelKey],
Name: volumeList.Volumes[volume].Labels[k2dtypes.PersistentVolumeClaimLabelKey],
}

// TODO: status of the persistent volume has to be retrieved from the
// containers that are using it

// "Mounts": [
// {
// "Type": "bind",
// "Source": "/var/run/docker.sock",
// "Destination": "/var/run/docker.sock",
// "Mode": "z",
// "RW": true,
// "Propagation": "rprivate"
// },
// {
// "Type": "volume",
// "Name": "portainer_data",
// "Source": "/var/lib/docker/volumes/portainer_data/_data",
// "Destination": "/data",
// "Driver": "local",
// "Mode": "z",
// "RW": true,
// "Propagation": ""
// }
// ]

persistentVolumes = append(persistentVolumes, core.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: volumeList.Volumes[volume].Name,
CreationTimestamp: metav1.Time{
Time: creationDate,
},
},
TypeMeta: metav1.TypeMeta{
Kind: "PersistentVolume",
APIVersion: "v1",
},
Spec: core.PersistentVolumeSpec{
Capacity: resourceList,
AccessModes: []core.PersistentVolumeAccessMode{
core.ReadWriteOnce,
},
PersistentVolumeReclaimPolicy: core.PersistentVolumeReclaimDelete,
PersistentVolumeSource: core.PersistentVolumeSource{
HostPath: &core.HostPathVolumeSource{
Path: volumeList.Volumes[volume].Mountpoint,
},
},
ClaimRef: persistentClaimReference,
StorageClassName: "local",
},
Status: core.PersistentVolumeStatus{
Phase: core.VolumeBound,
},
})
}

return core.PersistentVolumeList{
TypeMeta: metav1.TypeMeta{
Kind: "PersistentVolumeList",
APIVersion: "v1",
},
Items: persistentVolumes,
}, nil
}
Loading