From 197fddf3353df38275c0d09063d70113a601f81d Mon Sep 17 00:00:00 2001 From: Luca Castellano Date: Thu, 21 Jun 2018 10:15:20 -0700 Subject: [PATCH] Add support for correctly displaying node and pod IP address + fix make clean --- Makefile | 2 +- providers/vic/operations/common_test.go | 9 +- providers/vic/operations/pod_creator.go | 4 + providers/vic/operations/pod_status.go | 151 +++++++++++++ providers/vic/operations/pod_status_test.go | 225 ++++++++++++++++++++ providers/vic/proxy/isolation_proxy.go | 78 ++++--- providers/vic/proxy/mocks/IsolationProxy.go | 23 ++ providers/vic/vic_provider.go | 69 ++++-- 8 files changed, 522 insertions(+), 39 deletions(-) create mode 100644 providers/vic/operations/pod_status.go create mode 100644 providers/vic/operations/pod_status_test.go diff --git a/Makefile b/Makefile index 477c9c5e0..f191ab894 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ docker: @echo "Docker Build..." $Q docker build -t $(DOCKER_IMAGE) . -clean: clean-build +clean: @echo "Clean..." $Q rm -rf bin diff --git a/providers/vic/operations/common_test.go b/providers/vic/operations/common_test.go index 7a881cb64..19ad1c9e9 100644 --- a/providers/vic/operations/common_test.go +++ b/providers/vic/operations/common_test.go @@ -12,6 +12,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "fmt" + "github.com/virtual-kubelet/virtual-kubelet/providers/vic/cache" "github.com/virtual-kubelet/virtual-kubelet/providers/vic/proxy" proxymocks "github.com/virtual-kubelet/virtual-kubelet/providers/vic/proxy/mocks" @@ -30,7 +31,13 @@ const ( podName = "busybox-sleep" podHandle = "fakehandle" - fakeEP = "fake-endpoint" + fakeEP = "fake-endpoint" + stateRunning = "Running" + stateStarting = "Starting" + stateStopping = "Stopping" + stateStopped = "Stopped" + stateRemoving = "Removing" + stateRemoved = "Removed" ) func createMocks(t *testing.T) (*proxymocks.ImageStore, *proxymocks.IsolationProxy, cache.PodCache, trace.Operation) { diff --git a/providers/vic/operations/pod_creator.go b/providers/vic/operations/pod_creator.go index 1858fdcdb..052423e3b 100644 --- a/providers/vic/operations/pod_creator.go +++ b/providers/vic/operations/pod_creator.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" "sync" + "time" "github.com/kr/pretty" @@ -17,6 +18,7 @@ import ( "github.com/vmware/vic/pkg/trace" "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) type PodCreator interface { @@ -143,6 +145,8 @@ func (v *VicPodCreator) CreatePod(op trace.Operation, pod *v1.Pod, start bool) e if err != nil { return err } + now := metav1.NewTime(time.Now()) + vp.Pod.Status.StartTime = &now } return nil diff --git a/providers/vic/operations/pod_status.go b/providers/vic/operations/pod_status.go new file mode 100644 index 000000000..dd5c1e8a3 --- /dev/null +++ b/providers/vic/operations/pod_status.go @@ -0,0 +1,151 @@ +package operations + +import ( + "fmt" + "net" + + "github.com/virtual-kubelet/virtual-kubelet/providers/vic/proxy" + + "github.com/vmware/vic/lib/apiservers/portlayer/client" + "github.com/vmware/vic/pkg/trace" + + "k8s.io/api/core/v1" +) + +type PodStatus interface { + GetStatus(op trace.Operation, namespace string, name string, hostAddress string) (*v1.PodStatus, error) +} + +type VicPodStatus struct { + client *client.PortLayer + isolationProxy proxy.IsolationProxy +} + +type VicPodStatusError string + +func (e VicPodStatusError) Error() string { return string(e) } + +const ( + PodStatusPortlayerClientError = VicPodStatusError("PodStatus called with an invalid portlayer client") + PodStatusIsolationProxyError = VicPodStatusError("PodStatus called with an invalid isolation proxy") + PodStatusInvalidPodIDError = VicPodStatusError("PodStatus called with invalid PodID") + PodStatusInvalidPodNameError = VicPodStatusError("PodStatus called with invalid PodName") +) + +func NewPodStatus(client *client.PortLayer, isolationProxy proxy.IsolationProxy) (PodStatus, error) { + if client == nil { + return nil, PodStatusPortlayerClientError + } else if isolationProxy == nil { + return nil, PodStatusIsolationProxyError + } + + return &VicPodStatus{ + client: client, + isolationProxy: isolationProxy, + }, nil +} + +// Gets pod status does not delete it +// +// arguments: +// op operation trace logger +// id pod id +// name pod name +// returns: +// error +func (v *VicPodStatus) GetStatus(op trace.Operation, id, name string, hostAddress string) (*v1.PodStatus, error) { + defer trace.End(trace.Begin(fmt.Sprintf("id(%s), name(%s)", id, name), op)) + + return v.getStatus(op, id, name, hostAddress) +} + +func (v *VicPodStatus) getStatus(op trace.Operation, id, name string, hostAddress string) (*v1.PodStatus, error) { + defer trace.End(trace.Begin(fmt.Sprintf("id(%s), name(%s)", id, name), op)) + // Start out with unknown + phase := v1.PodUnknown + podReady := v1.ConditionUnknown + podInitialized := v1.ConditionUnknown + podScheduled := v1.ConditionUnknown + + // Get current state + state, err := v.isolationProxy.State(op, id, name) + if err == nil { + podScheduled = v1.ConditionTrue + switch state { + case "Starting": + // if we are starting let the user know they must use the force + phase = v1.PodPending + podInitialized = v1.ConditionFalse + podReady = v1.ConditionFalse + case "Running": + phase = v1.PodRunning + podInitialized = v1.ConditionTrue + podReady = v1.ConditionTrue + case "Stopping": + phase = v1.PodRunning + podReady = v1.ConditionFalse + podInitialized = v1.ConditionTrue + case "Stopped": + phase = v1.PodSucceeded + podReady = v1.ConditionFalse + podInitialized = v1.ConditionTrue + case "Removing": + phase = v1.PodSucceeded + podReady = v1.ConditionFalse + podInitialized = v1.ConditionTrue + case "Removed": + phase = v1.PodSucceeded + podReady = v1.ConditionFalse + podInitialized = v1.ConditionTrue + } + } + + status := &v1.PodStatus{ + Phase: phase, + Conditions: []v1.PodCondition{ + { + Type: v1.PodInitialized, + Status: podInitialized, + }, + { + Type: v1.PodReady, + Status: podReady, + }, + { + Type: v1.PodScheduled, + Status: podScheduled, + }, + }, + } + addresses, err := v.getIPAddresses(op, id, name) + if err == nil && len(addresses) > 0 { + status.HostIP = hostAddress + status.PodIP = addresses[0] + } else { + status.HostIP = "0.0.0.0" + status.PodIP = "0.0.0.0" + } + + return status, nil +} + +func (v *VicPodStatus) getIPAddresses(op trace.Operation, id, name string) ([]string, error) { + defer trace.End(trace.Begin(id, op)) + + apAddresses, err := v.isolationProxy.EpAddresses(op, id, name) + if err != nil { + return nil, err + } + + IPAddresses := make([]string, 0) + for _, epAddr := range apAddresses { + if epAddr != "" { + ip, _, err := net.ParseCIDR(epAddr) + if err == nil { + IPAddresses = append(IPAddresses, ip.String()) + } + } + } + + return IPAddresses, err +} diff --git a/providers/vic/operations/pod_status_test.go b/providers/vic/operations/pod_status_test.go new file mode 100644 index 000000000..0b74eafc7 --- /dev/null +++ b/providers/vic/operations/pod_status_test.go @@ -0,0 +1,225 @@ +package operations + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/vmware/vic/lib/apiservers/portlayer/client" + "k8s.io/api/core/v1" +) + +func TestNewPodStatus(t *testing.T) { + _, ip, _, _ := createMocks(t) + client := client.Default + + // Positive Cases + s, err := NewPodStatus(client, ip) + assert.NotNil(t, s, "Expected non-nil creating a pod Status but received nil") + + // Negative Cases + s, err = NewPodStatus(nil, ip) + assert.Nil(t, s, "Expected nil") + assert.Equal(t, err, PodStatusPortlayerClientError) + + s, err = NewPodStatus(client, nil) + assert.Nil(t, s, "Expected nil") + assert.Equal(t, err, PodStatusIsolationProxyError) +} + +func TestStatusPodStarting(t *testing.T) { + client := client.Default + _, ip, _, op := createMocks(t) + + s, err := NewPodStatus(client, ip) + assert.NotNil(t, s, "Expected non-nil creating a pod Status but received nil") + assert.Nil(t, err, "Expected nil") + + HostAddress := "1.2.3.4" + EndpointAddresses := []string{ + "5.6.7.8/24", + } + + // Set up the mocks for this test + ip.On("State", op, podID, podName).Return(stateStarting, nil) + ip.On("EpAddresses", op, podID, podName).Return(EndpointAddresses, nil) + + // Positive case + status, err := s.GetStatus(op, podID, podName, HostAddress) + assert.Nil(t, err, "Expected nil") + assert.Equal(t, status.Phase, v1.PodPending, "Expected Phase Pending") + verifyConditions(t, status.Conditions, v1.ConditionTrue, v1.ConditionFalse, v1.ConditionFalse) + assert.Equal(t, status.HostIP, "1.2.3.4", "Expected Host IP Address") + assert.Equal(t, status.PodIP, "5.6.7.8", "Expected Pod IP Address") +} + +func TestStatusPodRunning(t *testing.T) { + client := client.Default + _, ip, _, op := createMocks(t) + + s, err := NewPodStatus(client, ip) + assert.NotNil(t, s, "Expected non-nil creating a pod Status but received nil") + assert.Nil(t, err, "Expected nil") + + HostAddress := "1.2.3.4" + EndpointAddresses := []string{ + "5.6.7.8/24", + } + + // Set up the mocks for this test + ip.On("State", op, podID, podName).Return(stateRunning, nil) + ip.On("EpAddresses", op, podID, podName).Return(EndpointAddresses, nil) + + // Pod Running case + status, err := s.GetStatus(op, podID, podName, HostAddress) + assert.Nil(t, err, "Expected nil") + assert.Equal(t, status.Phase, v1.PodRunning, "Expected Phase PodRunning") + verifyConditions(t, status.Conditions, v1.ConditionTrue, v1.ConditionTrue, v1.ConditionTrue) + assert.Equal(t, status.HostIP, "1.2.3.4", "Expected Host IP Address") + assert.Equal(t, status.PodIP, "5.6.7.8", "Expected Pod IP Address") +} + +func TestStatusPodStopping(t *testing.T) { + client := client.Default + _, ip, _, op := createMocks(t) + + s, err := NewPodStatus(client, ip) + assert.NotNil(t, s, "Expected non-nil creating a pod Status but received nil") + assert.Nil(t, err, "Expected nil") + + HostAddress := "1.2.3.4" + EndpointAddresses := []string{ + "5.6.7.8/24", + } + + // Set up the mocks for this test + ip.On("State", op, podID, podName).Return(stateStopping, nil) + ip.On("EpAddresses", op, podID, podName).Return(EndpointAddresses, nil) + + // Pod error case + status, err := s.GetStatus(op, podID, podName, HostAddress) + + assert.Equal(t, status.Phase, v1.PodRunning, "Expected Phase PodFailed") + verifyConditions(t, status.Conditions, v1.ConditionTrue, v1.ConditionTrue, v1.ConditionFalse) + assert.Equal(t, status.HostIP, "1.2.3.4", "Expected Host IP Address") + assert.Equal(t, status.PodIP, "5.6.7.8", "Expected Pod IP Address") +} + +func TestStatusPodStopped(t *testing.T) { + client := client.Default + _, ip, _, op := createMocks(t) + + s, err := NewPodStatus(client, ip) + assert.NotNil(t, s, "Expected non-nil creating a pod Status but received nil") + assert.Nil(t, err, "Expected nil") + + HostAddress := "1.2.3.4" + EndpointAddresses := []string{ + "5.6.7.8/24", + } + + // Set up the mocks for this test + ip.On("State", op, podID, podName).Return(stateStopped, nil) + ip.On("EpAddresses", op, podID, podName).Return(EndpointAddresses, nil) + + // Pod error case + status, err := s.GetStatus(op, podID, podName, HostAddress) + + assert.Equal(t, status.Phase, v1.PodSucceeded, "Expected Phase PodFailed") + verifyConditions(t, status.Conditions, v1.ConditionTrue, v1.ConditionTrue, v1.ConditionFalse) + assert.Equal(t, status.HostIP, "1.2.3.4", "Expected Host IP Address") + assert.Equal(t, status.PodIP, "5.6.7.8", "Expected Pod IP Address") +} + +func TestStatusPodRemoving(t *testing.T) { + client := client.Default + _, ip, _, op := createMocks(t) + + s, err := NewPodStatus(client, ip) + assert.NotNil(t, s, "Expected non-nil creating a pod Status but received nil") + assert.Nil(t, err, "Expected nil") + + HostAddress := "1.2.3.4" + EndpointAddresses := []string{ + "5.6.7.8/24", + } + + // Set up the mocks for this test + ip.On("State", op, podID, podName).Return(stateRemoving, nil) + ip.On("EpAddresses", op, podID, podName).Return(EndpointAddresses, nil) + + // Pod error case + status, err := s.GetStatus(op, podID, podName, HostAddress) + + assert.Equal(t, status.Phase, v1.PodSucceeded, "Expected Phase PodFailed") + verifyConditions(t, status.Conditions, v1.ConditionTrue, v1.ConditionTrue, v1.ConditionFalse) + assert.Equal(t, status.HostIP, "1.2.3.4", "Expected Host IP Address") + assert.Equal(t, status.PodIP, "5.6.7.8", "Expected Pod IP Address") +} + +func TestStatusPodRemoved(t *testing.T) { + client := client.Default + _, ip, _, op := createMocks(t) + + s, err := NewPodStatus(client, ip) + assert.NotNil(t, s, "Expected non-nil creating a pod Status but received nil") + assert.Nil(t, err, "Expected nil") + + HostAddress := "1.2.3.4" + EndpointAddresses := []string{ + "5.6.7.8/24", + } + + // Set up the mocks for this test + ip.On("State", op, podID, podName).Return(stateRemoved, nil) + ip.On("EpAddresses", op, podID, podName).Return(EndpointAddresses, nil) + + // Pod error case + status, err := s.GetStatus(op, podID, podName, HostAddress) + + assert.Equal(t, status.Phase, v1.PodSucceeded, "Expected Phase PodFailed") + verifyConditions(t, status.Conditions, v1.ConditionTrue, v1.ConditionTrue, v1.ConditionFalse) + assert.Equal(t, status.HostIP, "1.2.3.4", "Expected Host IP Address") + assert.Equal(t, status.PodIP, "5.6.7.8", "Expected Pod IP Address") +} + +func TestStatusError(t *testing.T) { + client := client.Default + _, ip, _, op := createMocks(t) + + // Start with arguments + s, err := NewPodStatus(client, ip) + assert.NotNil(t, s, "Expected non-nil creating a pod Status but received nil") + assert.Nil(t, err, "Expected nil") + + HostAddress := "0.0.0.0" + + // Set up the mocks for this test + fakeErr := fakeError("invalid Pod") + ip.On("State", op, podID, podName).Return("", fakeErr) + ip.On("EpAddresses", op, podID, podName).Return(nil, fakeErr) + + // Error case + status, err := s.GetStatus(op, podID, podName, HostAddress) + assert.Nil(t, err, "Expected nil") + assert.Equal(t, status.Phase, v1.PodUnknown, "Expected Phase PodUnknown") + verifyConditions(t, status.Conditions, v1.ConditionUnknown, v1.ConditionUnknown, v1.ConditionUnknown) + assert.Equal(t, status.HostIP, "0.0.0.0", "Expected Host IP Address") + assert.Equal(t, status.PodIP, "0.0.0.0", "Expected Pod IP Address") +} + +func verifyConditions(t *testing.T, conditions []v1.PodCondition, scheduled v1.ConditionStatus, initialized v1.ConditionStatus, ready v1.ConditionStatus) { + for _, condition := range conditions { + switch condition.Type { + case v1.PodScheduled: + assert.Equal(t, condition.Status, scheduled, "Condition Pod Scheduled") + break + case v1.PodInitialized: + assert.Equal(t, condition.Status, initialized, "Condition Pod Initialized") + break + case v1.PodReady: + assert.Equal(t, condition.Status, ready, "Condition Pod Ready") + break + } + } +} diff --git a/providers/vic/proxy/isolation_proxy.go b/providers/vic/proxy/isolation_proxy.go index 4503e8ae6..dc4af4534 100644 --- a/providers/vic/proxy/isolation_proxy.go +++ b/providers/vic/proxy/isolation_proxy.go @@ -36,8 +36,10 @@ type IsolationProxy interface { UnbindScope(op trace.Operation, handle string, name string) (string, interface{}, error) Handle(op trace.Operation, id, name string) (string, error) - State(op trace.Operation, id, name string) (string, error) Remove(op trace.Operation, id string, force bool) error + + State(op trace.Operation, id, name string) (string, error) + EpAddresses(op trace.Operation, id, name string) ([]string, error) } type VicIsolationProxy struct { @@ -440,29 +442,6 @@ func (v *VicIsolationProxy) SetState(op trace.Operation, handle, name, state str return resp.Payload, nil } -func (v *VicIsolationProxy) State(op trace.Operation, id, name string) (string, error) { - defer trace.End(trace.Begin(id, op)) - - if v.client == nil { - return "", vicerrors.NillPortlayerClientError("IsolationProxy") - } - - results, err := v.client.Containers.GetContainerInfo(containers.NewGetContainerInfoParamsWithContext(op).WithID(id)) - if err != nil { - switch err := err.(type) { - case *containers.GetContainerInfoNotFound: - return "", vicerrors.NotFoundError(name) - case *containers.GetContainerInfoInternalServerError: - return "", vicerrors.InternalServerError(err.Payload.Message) - default: - return "", vicerrors.InternalServerError(fmt.Sprintf("Unknown error from the interaction port layer: %s", err)) - } - } - - state := results.Payload.ContainerConfig.State - return state, nil -} - func (v *VicIsolationProxy) Remove(op trace.Operation, id string, force bool) error { defer trace.End(trace.Begin(id, op)) @@ -481,6 +460,57 @@ func (v *VicIsolationProxy) Remove(op trace.Operation, id string, force bool) er return err } +func (v *VicIsolationProxy) State(op trace.Operation, id, name string) (string, error) { + defer trace.End(trace.Begin(id, op)) + + payload, err := v.getInfo(op, id, name) + if err != nil { + return "", err + } + + state := payload.ContainerConfig.State + return state, nil +} + +func (v *VicIsolationProxy) EpAddresses(op trace.Operation, id, name string) ([]string, error) { + defer trace.End(trace.Begin(id, op)) + + payload, err := v.getInfo(op, id, name) + if err != nil { + return nil, err + } + + addresses := make([]string, 0) + for _, ep := range payload.Endpoints { + addresses = append(addresses, ep.Address) + } + + return addresses, nil +} + +// Private methods +func (v *VicIsolationProxy) getInfo(op trace.Operation, id, name string) (*models.ContainerInfo, error) { + defer trace.End(trace.Begin(id, op)) + + if v.client == nil { + return nil, vicerrors.NillPortlayerClientError("IsolationProxy") + } + + results, err := v.client.Containers.GetContainerInfo(containers.NewGetContainerInfoParamsWithContext(op).WithID(id)) + if err != nil { + switch err := err.(type) { + case *containers.GetContainerInfoNotFound: + return nil, vicerrors.NotFoundError(name) + case *containers.GetContainerInfoInternalServerError: + return nil, vicerrors.InternalServerError(err.Payload.Message) + default: + return nil, vicerrors.InternalServerError(fmt.Sprintf("Unknown error from port layer: %s", err)) + } + } + + return results.Payload, nil +} + //------------------------------------ // Utility Functions //------------------------------------ diff --git a/providers/vic/proxy/mocks/IsolationProxy.go b/providers/vic/proxy/mocks/IsolationProxy.go index 48dc5c97a..77e843603 100644 --- a/providers/vic/proxy/mocks/IsolationProxy.go +++ b/providers/vic/proxy/mocks/IsolationProxy.go @@ -187,6 +187,29 @@ func (_m *IsolationProxy) CreateHandleTask(op trace.Operation, handle string, id return r0, r1 } +// EpAddresses provides a mock function with given fields: op, id, name +func (_m *IsolationProxy) EpAddresses(op trace.Operation, id string, name string) ([]string, error) { + ret := _m.Called(op, id, name) + + var r0 []string + if rf, ok := ret.Get(0).(func(trace.Operation, string, string) []string); ok { + r0 = rf(op, id, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(trace.Operation, string, string) error); ok { + r1 = rf(op, id, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Handle provides a mock function with given fields: op, id, name func (_m *IsolationProxy) Handle(op trace.Operation, id string, name string) (string, error) { ret := _m.Called(op, id, name) diff --git a/providers/vic/vic_provider.go b/providers/vic/vic_provider.go index 2eb236845..f2f567275 100644 --- a/providers/vic/vic_provider.go +++ b/providers/vic/vic_provider.go @@ -28,6 +28,8 @@ import ( "github.com/virtual-kubelet/virtual-kubelet/providers/vic/proxy" "github.com/virtual-kubelet/virtual-kubelet/providers/vic/utils" + "net" + "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -120,6 +122,7 @@ func waitForVCH(op trace.Operation, plClient *client.PortLayer, personaAddr stri backoffConf := retry.NewBackoffConfig() backoffConf.MaxInterval = 2 * time.Second backoffConf.InitialInterval = 500 * time.Millisecond + backoffConf.MaxElapsedTime = 10 * time.Minute // Wait for portlayer to start up systemProxy := vicproxy.NewSystemProxy(plClient) @@ -262,34 +265,56 @@ func (v *VicProvider) GetPodStatus(namespace, name string) (*v1.PodStatus, error defer trace.End(trace.Begin("GetPodStatus", op)) now := metav1.NewTime(time.Now()) - - status := &v1.PodStatus{ - Phase: v1.PodRunning, - HostIP: "1.2.3.4", - PodIP: "5.6.7.8", + errorStatus := &v1.PodStatus{ + Phase: v1.PodUnknown, StartTime: &now, Conditions: []v1.PodCondition{ { Type: v1.PodInitialized, - Status: v1.ConditionTrue, + Status: v1.ConditionUnknown, }, { Type: v1.PodReady, - Status: v1.ConditionTrue, + Status: v1.ConditionUnknown, }, { Type: v1.PodScheduled, - Status: v1.ConditionTrue, + Status: v1.ConditionUnknown, }, }, } - pod, err := v.GetPod(namespace, name) + // Look for the pod in our cache of running pods + vp, err := v.podCache.Get(op, namespace, name) if err != nil { - return status, err + return errorStatus, err } - for _, container := range pod.Spec.Containers { + // Instantiate status object + statusReporter, err := operations.NewPodStatus(v.client, v.isolationProxy) + if err != nil { + return errorStatus, err + } + + var nodeAddress string + nodeAddresses := v.NodeAddresses() + if len(nodeAddresses) > 0 { + nodeAddress = nodeAddresses[0].Address + } else { + nodeAddress = "0.0.0.0" + } + status, err := statusReporter.GetStatus(op, vp.ID, name, nodeAddress) + if err != nil { + return errorStatus, err + } + + if vp.Pod.Status.StartTime != nil { + status.StartTime = vp.Pod.Status.StartTime + } else { + status.StartTime = &now + } + + for _, container := range vp.Pod.Spec.Containers { status.ContainerStatuses = append(status.ContainerStatuses, v1.ContainerStatus{ Name: container.Name, Image: container.Image, @@ -297,7 +322,7 @@ func (v *VicProvider) GetPodStatus(namespace, name string) (*v1.PodStatus, error RestartCount: 0, State: v1.ContainerState{ Running: &v1.ContainerStateRunning{ - StartedAt: now, + StartedAt: *status.StartTime, }, }, }) @@ -390,7 +415,25 @@ func (v *VicProvider) NodeConditions() []v1.NodeCondition { // NodeAddresses returns a list of addresses for the node status // within Kubernetes. func (v *VicProvider) NodeAddresses() []v1.NodeAddress { - return nil + addrs, err := net.InterfaceAddrs() + if err != nil { + return []v1.NodeAddress{} + } + + var outAddresses []v1.NodeAddress + for _, addr := range addrs { + ipnet, ok := addr.(*net.IPNet) + if !ok || ipnet.IP.IsLoopback() || ipnet.IP.To4() == nil { + continue + } + outAddress := v1.NodeAddress{ + Type: v1.NodeInternalIP, + Address: ipnet.IP.String(), + } + outAddresses = append(outAddresses, outAddress) + } + + return outAddresses } // NodeDaemonEndpoints returns NodeDaemonEndpoints for the node status