265 lines
6.6 KiB
Go
265 lines
6.6 KiB
Go
package mock
|
|
|
|
import (
|
|
"log"
|
|
"time"
|
|
|
|
"fmt"
|
|
"github.com/virtual-kubelet/virtual-kubelet/providers"
|
|
"k8s.io/api/core/v1"
|
|
"k8s.io/apimachinery/pkg/api/resource"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
)
|
|
|
|
// MockProvider implements the virtual-kubelet provider interface and stores pods in memory.
|
|
type MockProvider struct {
|
|
nodeName string
|
|
operatingSystem string
|
|
internalIP string
|
|
daemonEndpointPort int32
|
|
pods map[string]*v1.Pod
|
|
}
|
|
|
|
// NewMockProvider creates a new MockProvider
|
|
func NewMockProvider(nodeName, operatingSystem string, internalIP string, daemonEndpointPort int32) (*MockProvider, error) {
|
|
provider := MockProvider{
|
|
nodeName: nodeName,
|
|
operatingSystem: operatingSystem,
|
|
internalIP: internalIP,
|
|
daemonEndpointPort: daemonEndpointPort,
|
|
pods: make(map[string]*v1.Pod),
|
|
}
|
|
|
|
return &provider, nil
|
|
}
|
|
|
|
// CreatePod accepts a Pod definition and stores it in memory.
|
|
func (p *MockProvider) CreatePod(pod *v1.Pod) error {
|
|
log.Printf("receive CreatePod %q\n", pod.Name)
|
|
|
|
key, err := buildKey(pod)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
p.pods[key] = pod
|
|
|
|
return nil
|
|
}
|
|
|
|
// UpdatePod accepts a Pod definition and updates its reference.
|
|
func (p *MockProvider) UpdatePod(pod *v1.Pod) error {
|
|
log.Printf("receive UpdatePod %q\n", pod.Name)
|
|
|
|
key, err := buildKey(pod)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
p.pods[key] = pod
|
|
|
|
return nil
|
|
}
|
|
|
|
// DeletePod deletes the specified pod out of memory.
|
|
func (p *MockProvider) DeletePod(pod *v1.Pod) (err error) {
|
|
log.Printf("receive DeletePod %q\n", pod.Name)
|
|
|
|
key, err := buildKey(pod)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
delete(p.pods, key)
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetPod returns a pod by name that is stored in memory.
|
|
func (p *MockProvider) GetPod(namespace, name string) (pod *v1.Pod, err error) {
|
|
log.Printf("receive GetPod %q\n", name)
|
|
|
|
key, err := buildKeyFromNames(namespace, name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if pod, ok := p.pods[key]; ok {
|
|
return pod, nil
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
// GetContainerLogs retrieves the logs of a container by name from the provider.
|
|
func (p *MockProvider) GetContainerLogs(namespace, podName, containerName string, tail int) (string, error) {
|
|
log.Printf("receive GetContainerLogs %q\n", podName)
|
|
return "", nil
|
|
}
|
|
|
|
// GetPodStatus returns the status of a pod by name that is "running".
|
|
// returns nil if a pod by that name is not found.
|
|
func (p *MockProvider) GetPodStatus(namespace, name string) (*v1.PodStatus, error) {
|
|
log.Printf("receive GetPodStatus %q\n", name)
|
|
|
|
now := metav1.NewTime(time.Now())
|
|
|
|
status := &v1.PodStatus{
|
|
Phase: v1.PodRunning,
|
|
HostIP: "1.2.3.4",
|
|
PodIP: "5.6.7.8",
|
|
StartTime: &now,
|
|
Conditions: []v1.PodCondition{
|
|
{
|
|
Type: v1.PodInitialized,
|
|
Status: v1.ConditionTrue,
|
|
},
|
|
{
|
|
Type: v1.PodReady,
|
|
Status: v1.ConditionTrue,
|
|
},
|
|
{
|
|
Type: v1.PodScheduled,
|
|
Status: v1.ConditionTrue,
|
|
},
|
|
},
|
|
}
|
|
|
|
pod, err := p.GetPod(namespace, name)
|
|
if err != nil {
|
|
return status, err
|
|
}
|
|
|
|
for _, container := range pod.Spec.Containers {
|
|
status.ContainerStatuses = append(status.ContainerStatuses, v1.ContainerStatus{
|
|
Name: container.Name,
|
|
Image: container.Image,
|
|
Ready: true,
|
|
RestartCount: 0,
|
|
State: v1.ContainerState{
|
|
Running: &v1.ContainerStateRunning{
|
|
StartedAt: now,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
return status, nil
|
|
}
|
|
|
|
// GetPods returns a list of all pods known to be "running".
|
|
func (p *MockProvider) GetPods() ([]*v1.Pod, error) {
|
|
log.Printf("receive GetPods\n")
|
|
|
|
var pods []*v1.Pod
|
|
|
|
for _, pod := range p.pods {
|
|
pods = append(pods, pod)
|
|
}
|
|
|
|
return pods, nil
|
|
}
|
|
|
|
// Capacity returns a resource list containing the capacity limits.
|
|
func (p *MockProvider) Capacity() v1.ResourceList {
|
|
// TODO: These should be configurable
|
|
return v1.ResourceList{
|
|
"cpu": resource.MustParse("20"),
|
|
"memory": resource.MustParse("100Gi"),
|
|
"pods": resource.MustParse("20"),
|
|
}
|
|
}
|
|
|
|
// NodeConditions returns a list of conditions (Ready, OutOfDisk, etc), for updates to the node status
|
|
// within Kubernetes.
|
|
func (p *MockProvider) NodeConditions() []v1.NodeCondition {
|
|
// TODO: Make this configurable
|
|
return []v1.NodeCondition{
|
|
{
|
|
Type: "Ready",
|
|
Status: v1.ConditionTrue,
|
|
LastHeartbeatTime: metav1.Now(),
|
|
LastTransitionTime: metav1.Now(),
|
|
Reason: "KubeletReady",
|
|
Message: "kubelet is ready.",
|
|
},
|
|
{
|
|
Type: "OutOfDisk",
|
|
Status: v1.ConditionFalse,
|
|
LastHeartbeatTime: metav1.Now(),
|
|
LastTransitionTime: metav1.Now(),
|
|
Reason: "KubeletHasSufficientDisk",
|
|
Message: "kubelet has sufficient disk space available",
|
|
},
|
|
{
|
|
Type: "MemoryPressure",
|
|
Status: v1.ConditionFalse,
|
|
LastHeartbeatTime: metav1.Now(),
|
|
LastTransitionTime: metav1.Now(),
|
|
Reason: "KubeletHasSufficientMemory",
|
|
Message: "kubelet has sufficient memory available",
|
|
},
|
|
{
|
|
Type: "DiskPressure",
|
|
Status: v1.ConditionFalse,
|
|
LastHeartbeatTime: metav1.Now(),
|
|
LastTransitionTime: metav1.Now(),
|
|
Reason: "KubeletHasNoDiskPressure",
|
|
Message: "kubelet has no disk pressure",
|
|
},
|
|
{
|
|
Type: "NetworkUnavailable",
|
|
Status: v1.ConditionFalse,
|
|
LastHeartbeatTime: metav1.Now(),
|
|
LastTransitionTime: metav1.Now(),
|
|
Reason: "RouteCreated",
|
|
Message: "RouteController created a route",
|
|
},
|
|
}
|
|
|
|
}
|
|
|
|
// NodeAddresses returns a list of addresses for the node status
|
|
// within Kubernetes.
|
|
func (p *MockProvider) NodeAddresses() []v1.NodeAddress {
|
|
return []v1.NodeAddress{
|
|
{
|
|
Type: "InternalIP",
|
|
Address: p.internalIP,
|
|
},
|
|
}
|
|
}
|
|
|
|
// NodeDaemonEndpoints returns NodeDaemonEndpoints for the node status
|
|
// within Kubernetes.
|
|
func (p *MockProvider) NodeDaemonEndpoints() *v1.NodeDaemonEndpoints {
|
|
return &v1.NodeDaemonEndpoints{
|
|
KubeletEndpoint: v1.DaemonEndpoint{
|
|
Port: p.daemonEndpointPort,
|
|
},
|
|
}
|
|
}
|
|
|
|
// OperatingSystem returns the operating system for this provider.
|
|
// This is a noop to default to Linux for now.
|
|
func (p *MockProvider) OperatingSystem() string {
|
|
return providers.OperatingSystemLinux
|
|
}
|
|
|
|
func buildKeyFromNames(namespace string, name string) (string, error) {
|
|
return fmt.Sprintf("%s-%s", namespace, name), nil
|
|
}
|
|
|
|
// buildKey is a helper for building the "key" for the providers pod store.
|
|
func buildKey(pod *v1.Pod) (string, error) {
|
|
if pod.ObjectMeta.Namespace == "" {
|
|
return "", fmt.Errorf("pod namespace not found")
|
|
}
|
|
|
|
if pod.ObjectMeta.Name == "" {
|
|
return "", fmt.Errorf("pod name not found")
|
|
}
|
|
|
|
return buildKeyFromNames(pod.ObjectMeta.Namespace, pod.ObjectMeta.Name)
|
|
}
|