Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
- partial support of ProjectedVolume, CreateToken API to get token, env
vars to provide k8s API URL
  • Loading branch information
antoinetran committed Jan 29, 2025
1 parent 1e20f35 commit d3f52f9
Show file tree
Hide file tree
Showing 7 changed files with 409 additions and 94 deletions.
7 changes: 7 additions & 0 deletions ci/manifests/service-account.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ rules:
- get
- list
- watch
# For https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/token-request-v1/
- apiGroups: [""]
resources: ["serviceaccounts/token"]
verbs:
- create
- get
- list
- apiGroups:
- ""
resources:
Expand Down
7 changes: 7 additions & 0 deletions example/interlink-docker/vk/service-account.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ rules:
- get
- list
- watch
# For https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/token-request-v1/
- apiGroups: [""]
resources: ["serviceaccounts/token"]
verbs:
- create
- get
- list
- apiGroups:
- ""
resources:
Expand Down
11 changes: 11 additions & 0 deletions pkg/interlink/api/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,17 @@ func (h *InterLinkHandler) CreateHandler(w http.ResponseWriter, r *http.Request)
return
}

if log.G(h.Ctx).Logger.IsLevelEnabled(log.DebugLevel) {
// For debugging purpose only.
allContainers := pod.Pod.Spec.InitContainers
allContainers = append(allContainers, pod.Pod.Spec.Containers...)
for _, container := range allContainers {
for _, envVar := range container.Env {
log.G(h.Ctx).Debug("InterLink VK environment variable to pod ", pod.Pod.Name, " container: ", container.Name, " env: ", envVar.Name, " value: ", envVar.Value)
}
}
}

retrievedData = append(retrievedData, data)

if retrievedData != nil {
Expand Down
69 changes: 53 additions & 16 deletions pkg/interlink/api/func.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package api
import (
"context"
"path/filepath"
"strings"
"sync"
"time"

Expand Down Expand Up @@ -35,10 +36,10 @@ func getData(ctx context.Context, config types.Config, pod types.PodCreateReques
startContainer := time.Now().UnixMicro()
log.G(ctx).Info("- Retrieving Secrets and ConfigMaps for the Docker Sidecar. InitContainer: " + container.Name)
log.G(ctx).Debug(container.VolumeMounts)
data, InterlinkIP := retrieveData(ctx, config, pod, container)
if InterlinkIP != nil {
log.G(ctx).Error(InterlinkIP)
return types.RetrievedPodData{}, InterlinkIP
data, err := retrieveData(ctx, config, pod, container)
if err != nil {
log.G(ctx).Error(err)
return types.RetrievedPodData{}, err
}
retrievedData.Containers = append(retrievedData.Containers, data)

Expand Down Expand Up @@ -75,40 +76,76 @@ func getData(ctx context.Context, config types.Config, pod types.PodCreateReques
// It returns the retrieved data in a variable of type commonIL.RetrievedContainer and the first encountered error.
func retrieveData(ctx context.Context, config types.Config, pod types.PodCreateRequests, container v1.Container) (types.RetrievedContainer, error) {
retrievedData := types.RetrievedContainer{}
retrievedData.Name = container.Name
for _, mountVar := range container.VolumeMounts {
log.G(ctx).Debug("-- Retrieving data for mountpoint " + mountVar.Name)
log.G(ctx).Debug("-- Retrieving data for mountpoint ", mountVar.Name)

loopVolumes:
for _, vol := range pod.Pod.Spec.Volumes {
if vol.Name == mountVar.Name {
switch {
case vol.ConfigMap != nil:

log.G(ctx).Info("--- Retrieving ConfigMap " + vol.ConfigMap.Name)
retrievedData.Name = container.Name
log.G(ctx).Info("--- Retrieving ConfigMap ", vol.ConfigMap.Name)
for _, cfgMap := range pod.ConfigMaps {
if cfgMap.Name == vol.ConfigMap.Name {
retrievedData.Name = container.Name
log.G(ctx).Debug("configMap found! Name: ", cfgMap.Name)
retrievedData.ConfigMaps = append(retrievedData.ConfigMaps, cfgMap)
break loopVolumes
}
}
// This should not happen, error. Building error context.
var configMapsKeys []string
for _, cfgMap := range pod.ConfigMaps {
configMapsKeys = append(configMapsKeys, cfgMap.Name)
}
log.G(ctx).Errorf("could not find in retrievedData the matching object for volume: %s (pod: %s container: %s configMap: %s) retrievedData keys: %s", vol.Name,
pod.Pod.Name, container.Name, vol.ConfigMap.Name, strings.Join(configMapsKeys, ","))

case vol.Projected != nil:
log.G(ctx).Info("--- Retrieving ProjectedVolume ", vol.Name)
for _, projectedVolumeMap := range pod.ProjectedVolumeMaps {
log.G(ctx).Debug("Comparing projectedVolumeMap.Name: ", projectedVolumeMap.Name, " with vol.Name: ", vol.Name)
if projectedVolumeMap.Name == vol.Name {
log.G(ctx).Debug("projectedVolumeMap found! Name: ", projectedVolumeMap.Name)

retrievedData.ProjectedVolumeMaps = append(retrievedData.ProjectedVolumeMaps, projectedVolumeMap)
break loopVolumes
}
}
// This should not happen, error. Building error context.
var projectedVolumeMapsKeys []string
for _, projectedVolumeMap := range pod.ProjectedVolumeMaps {
projectedVolumeMapsKeys = append(projectedVolumeMapsKeys, projectedVolumeMap.Name)
}
log.G(ctx).Errorf("could not find in retrievedData the matching object for volume: %s (pod: %s container: %s projectedVolumeMap) retrievedData keys: %s",
vol.Name, pod.Pod.Name, container.Name, strings.Join(projectedVolumeMapsKeys, ","))

case vol.Secret != nil:

log.G(ctx).Info("--- Retrieving Secret " + vol.Secret.SecretName)
retrievedData.Name = container.Name
log.G(ctx).Info("--- Retrieving Secret ", vol.Secret.SecretName)
for _, secret := range pod.Secrets {
if secret.Name == vol.Secret.SecretName {
retrievedData.Name = container.Name
log.G(ctx).Debug("secret found! Name: ", secret.Name)
retrievedData.Secrets = append(retrievedData.Secrets, secret)
break loopVolumes
}
}
// This should not happen, error. Building error context.
var secretKeys []string
for _, secret := range pod.Secrets {
secretKeys = append(secretKeys, secret.Name)
}
log.G(ctx).Errorf("could not find in retrievedData the matching object for volume: %s (pod: %s container: %s secret: %s) retrievedData keys: %s",
pod.Pod.Name, container.Name, vol.Name, vol.Secret.SecretName, strings.Join(secretKeys, ","))

case vol.EmptyDir != nil:
edPath := filepath.Join(config.DataRootFolder, pod.Pod.Namespace+"-"+string(pod.Pod.UID)+"/"+"emptyDirs/"+vol.Name)

retrievedData.Name = container.Name
// Deprecated: EmptyDirs is useless at VK level. It should be moved to plugin level.
edPath := filepath.Join(config.DataRootFolder, pod.Pod.Namespace+"-"+string(pod.Pod.UID), "emptyDirs", vol.Name)
retrievedData.EmptyDirs = append(retrievedData.EmptyDirs, edPath)

Check failure on line 143 in pkg/interlink/api/func.go

View workflow job for this annotation

GitHub Actions / lint

SA1019: retrievedData.EmptyDirs is deprecated: EmptyDirs should be built on plugin side. Currently, it holds the DATA_ROOT_DIR/emptydirs/volumeName, but this should be a plugin choice instead, like it currently is for ConfigMaps, ProjectedVolumeMaps, Secrets. (staticcheck)

default:
log.G(ctx).Warning("ignoring unsupported volume type for ", mountVar.Name)
}

}
}
}
Expand Down
15 changes: 11 additions & 4 deletions pkg/interlink/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ type PodCreateRequests struct {
Pod v1.Pod `json:"pod"`
ConfigMaps []v1.ConfigMap `json:"configmaps"`
Secrets []v1.Secret `json:"secrets"`
// The projected volumes are those created by ServiceAccounts (in K8S >= 1.24). They are automatically added in the pod from kubelet code.
// Here the configmap will hold the files name (as key) and content (as value).
ProjectedVolumeMaps []v1.ConfigMap `json:"projectedvolumesmaps"`
}

// PodStatus is a simplified v1.Pod struct, holding only necessary variables to uniquely identify a job/service in the sidecar. It is used to request
Expand All @@ -31,10 +34,14 @@ type CreateStruct struct {

// RetrievedContainer is used in InterLink to rearrange data structure in a suitable way for the sidecar
type RetrievedContainer struct {
Name string `json:"name"`
ConfigMaps []v1.ConfigMap `json:"configMaps"`
Secrets []v1.Secret `json:"secrets"`
EmptyDirs []string `json:"emptyDirs"`
Name string `json:"name"`
ConfigMaps []v1.ConfigMap `json:"configMaps"`
ProjectedVolumeMaps []v1.ConfigMap `json:"projectedvolumemaps"`
Secrets []v1.Secret `json:"secrets"`
// Deprecated: EmptyDirs should be built on plugin side.
// Currently, it holds the DATA_ROOT_DIR/emptydirs/volumeName, but this should be a plugin choice instead,
// like it currently is for ConfigMaps, ProjectedVolumeMaps, Secrets.
EmptyDirs []string `json:"emptyDirs"`
}

// RetrievedPoData is used in InterLink to rearrange data structure in a suitable way for the sidecar
Expand Down
33 changes: 18 additions & 15 deletions pkg/virtualkubelet/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,24 @@ package virtualkubelet

// Config holds the whole configuration
type Config struct {
InterlinkURL string `yaml:"InterlinkURL"`
Interlinkport string `yaml:"InterlinkPort"`
VKConfigPath string `yaml:"VKConfigPath"`
VKTokenFile string `yaml:"VKTokenFile"`
ServiceAccount string `yaml:"ServiceAccount"`
Namespace string `yaml:"Namespace"`
PodIP string `yaml:"PodIP"`
VerboseLogging bool `yaml:"VerboseLogging"`
ErrorsOnlyLogging bool `yaml:"ErrorsOnlyLogging"`
HTTP HTTP `yaml:"HTTP"`
KubeletHTTP HTTP `yaml:"KubeletHTTP"`
CPU string `yaml:"CPU,omitempty"`
Memory string `yaml:"Memory,omitempty"`
Pods string `yaml:"Pods,omitempty"`
GPU string `yaml:"nvidia.com/gpu,omitempty"`
InterlinkURL string `yaml:"InterlinkURL"`
Interlinkport string `yaml:"InterlinkPort"`
KubernetesApiAddr string `yaml:"KubernetesApiAddr"`

Check failure on line 7 in pkg/virtualkubelet/config.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: struct field KubernetesApiAddr should be KubernetesAPIAddr (revive)
KubernetesApiPort string `yaml:"KubernetesApiPort"`

Check failure on line 8 in pkg/virtualkubelet/config.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: struct field KubernetesApiPort should be KubernetesAPIPort (revive)
KubernetesApiCaCrt string `yaml:"KubernetesApiCaCrt"`

Check failure on line 9 in pkg/virtualkubelet/config.go

View workflow job for this annotation

GitHub Actions / lint

var-naming: struct field KubernetesApiCaCrt should be KubernetesAPICaCrt (revive)
VKConfigPath string `yaml:"VKConfigPath"`
VKTokenFile string `yaml:"VKTokenFile"`
ServiceAccount string `yaml:"ServiceAccount"`
Namespace string `yaml:"Namespace"`
PodIP string `yaml:"PodIP"`
VerboseLogging bool `yaml:"VerboseLogging"`
ErrorsOnlyLogging bool `yaml:"ErrorsOnlyLogging"`
HTTP HTTP `yaml:"HTTP"`
KubeletHTTP HTTP `yaml:"KubeletHTTP"`
CPU string `yaml:"CPU,omitempty"`
Memory string `yaml:"Memory,omitempty"`
Pods string `yaml:"Pods,omitempty"`
GPU string `yaml:"nvidia.com/gpu,omitempty"`
}

type HTTP struct {
Expand Down
Loading

0 comments on commit d3f52f9

Please sign in to comment.