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

Implement antctl agent-info #318

Merged
merged 1 commit into from
Feb 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
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
11 changes: 11 additions & 0 deletions pkg/antctl/antctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,17 @@ var CommandList = &commandList{
CommandGroup: flat,
AddonTransform: versionTransform,
},
{
Use: "agent-info",
Short: "Print agent's basic information",
Long: "Print agent's basic information including version, node subnet, OVS info, AgentConditions, etc.",
HandlerFactory: new(handlers.AgentInfo),
GroupVersion: &systemGroup,
TransformedResponse: reflect.TypeOf(handlers.AntreaAgentInfoResponse{}),
Agent: true,
SingleObject: true,
CommandGroup: flat,
},
},
codec: scheme.Codecs,
}
69 changes: 69 additions & 0 deletions pkg/antctl/handlers/agentinfo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2020 Antrea Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package handlers

import (
"encoding/json"
"net/http"

corev1 "k8s.io/api/core/v1"
"k8s.io/klog"

"github.com/vmware-tanzu/antrea/pkg/apis/clusterinformation/v1beta1"
"github.com/vmware-tanzu/antrea/pkg/monitor"
)

var _ Factory = new(AgentInfo)

// AntreaAgentInfoResponse is the struct for the response of agent-info command.
// It includes all fields except meta info from v1beta1.AntreaAgentInfo struct.
type AntreaAgentInfoResponse struct {
Version string `json:"version,omitempty"` // Antrea binary version
PodRef corev1.ObjectReference `json:"podRef,omitempty"` // The Pod that Antrea Agent is running in
NodeRef corev1.ObjectReference `json:"nodeRef,omitempty"` // The Node that Antrea Agent is running in
NodeSubnet []string `json:"nodeSubnet,omitempty"` // Node subnet
OVSInfo v1beta1.OVSInfo `json:"ovsInfo,omitempty"` // OVS Information
NetworkPolicyControllerInfo v1beta1.NetworkPolicyControllerInfo `json:"networkPolicyControllerInfo,omitempty"` // Antrea Agent NetworkPolicy information
LocalPodNum int32 `json:"localPodNum,omitempty"` // The number of Pods which the agent is in charge of
AgentConditions []v1beta1.AgentCondition `json:"agentConditions,omitempty"` // Agent condition contains types like AgentHealthy
}

// AgentInfo is the implementation of the Factory interface for the agent-info command.
type AgentInfo struct{}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Humm...
Question - what is the convention of this handler struct. Do we assume it includes the real result data and how about other commands? If so, should we add AntreaAgentInfo into the struct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have put an example in the PR description.

This struct doesn't contain data or result. It is only for command handler below:
func (v *AgentInfo) Handler(aq monitor.AgentQuerier, cq monitor.ControllerQuerier) http.HandlerFunc


// Handler returns the function which can handle queries issued by agent-info commands,
// the handler function populate component's agent-info to the response.
func (v *AgentInfo) Handler(aq monitor.AgentQuerier, cq monitor.ControllerQuerier) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var info *AntreaAgentInfoResponse
if aq != nil {
allInfo := aq.GetAgentInfo()
info = &AntreaAgentInfoResponse{
Version: allInfo.Version,
PodRef: allInfo.PodRef,
NodeRef: allInfo.NodeRef,
OVSInfo: allInfo.OVSInfo,
NetworkPolicyControllerInfo: allInfo.NetworkPolicyControllerInfo,
LocalPodNum: allInfo.LocalPodNum,
AgentConditions: allInfo.AgentConditions,
}
}
err := json.NewEncoder(w).Encode(info)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
klog.Errorf("Error when encoding AntreaAgentInfo to json: %v", err)
}
}
}
87 changes: 87 additions & 0 deletions pkg/antctl/handlers/agentinfo_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright 2020 Antrea Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package handlers

import (
"net/http"
"net/http/httptest"
"testing"

"github.com/vmware-tanzu/antrea/pkg/apis/clusterinformation/v1beta1"
mockmonitor "github.com/vmware-tanzu/antrea/pkg/monitor/testing"

"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var antreaAgentInfo0 v1beta1.AntreaAgentInfo = v1beta1.AntreaAgentInfo{
ObjectMeta: metav1.ObjectMeta{
Name: "node0-k8",
},
Version: "1.0",
PodRef: corev1.ObjectReference{
Kind: "Pod",
Namespace: "kube-system",
Name: "antrea-agent-flx99",
},
NodeRef: corev1.ObjectReference{
Kind: "Node",
Name: "node0-k8",
},
NodeSubnet: []string{
"192.168.0.0/24",
},
OVSInfo: v1beta1.OVSInfo{},
NetworkPolicyControllerInfo: v1beta1.NetworkPolicyControllerInfo{},
LocalPodNum: 1,
AgentConditions: []v1beta1.AgentCondition{
{
Type: v1beta1.AgentHealthy,
Status: corev1.ConditionTrue,
},
},
}

func TestAgentInfo(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

testcases := map[string]struct {
testNode corev1.ObjectReference
agentInfo *v1beta1.AntreaAgentInfo
expectedOutput string
expectedStatusCode int
}{
"AgentInfo": {
agentInfo: &antreaAgentInfo0,
expectedOutput: "{\"version\":\"1.0\",\"podRef\":{\"kind\":\"Pod\",\"namespace\":\"kube-system\",\"name\":\"antrea-agent-flx99\"},\"nodeRef\":{\"kind\":\"Node\",\"name\":\"node0-k8\"},\"ovsInfo\":{},\"networkPolicyControllerInfo\":{},\"localPodNum\":1,\"agentConditions\":[{\"type\":\"AgentHealthy\",\"status\":\"True\",\"lastHeartbeatTime\":null}]}\n",
expectedStatusCode: http.StatusOK,
},
}
for k, tc := range testcases {
t.Run(k, func(t *testing.T) {
req, err := http.NewRequest("GET", "/", nil)
assert.Nil(t, err)
recorder := httptest.NewRecorder()
aq := mockmonitor.NewMockAgentQuerier(ctrl)
aq.EXPECT().GetAgentInfo().Return(tc.agentInfo)
new(AgentInfo).Handler(aq, nil).ServeHTTP(recorder, req)
assert.Equal(t, tc.expectedStatusCode, recorder.Code, k)
assert.Equal(t, tc.expectedOutput, recorder.Body.String(), k)
})
}
}
18 changes: 11 additions & 7 deletions pkg/monitor/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,12 @@ func (monitor *controllerMonitor) Run(stopCh <-chan struct{}) {
// Then updates AntreaAgentInfo CRD every 60 seconds.
func (monitor *agentMonitor) Run(stopCh <-chan struct{}) {
klog.Info("Starting Antrea Agent Monitor")
crdName := monitor.GetSelfNode().Name
agentCRD := monitor.getAgentCRD(crdName)
agentCRD := monitor.getAgentCRD()
var err error = nil

// Initialize agent monitoring CRD.
if agentCRD == nil {
agentCRD, err = monitor.createAgentCRD(crdName)
agentCRD, err = monitor.createAgentCRD()
if err != nil {
klog.Errorf("Failed to create agent monitoring CRD %v : %v", agentCRD, err)
return
Expand Down Expand Up @@ -255,7 +254,8 @@ func (monitor *controllerMonitor) deleteAgentCRD(name string) {

// getAgentCRD is used to check the existence of agent monitoring CRD.
// So when the pod restarts, it will update this monitoring CRD instead of creating a new one.
func (monitor *agentMonitor) getAgentCRD(crdName string) *v1beta1.AntreaAgentInfo {
func (monitor *agentMonitor) getAgentCRD() *v1beta1.AntreaAgentInfo {
crdName := monitor.nodeName
agentCRD, err := monitor.client.ClusterinformationV1beta1().AntreaAgentInfos().Get(crdName, metav1.GetOptions{})
if err != nil {
klog.V(2).Infof("Agent monitoring CRD named %s doesn't exist, will create one", crdName)
Expand All @@ -264,12 +264,12 @@ func (monitor *agentMonitor) getAgentCRD(crdName string) *v1beta1.AntreaAgentInf
return agentCRD
}

func (monitor *agentMonitor) createAgentCRD(crdName string) (*v1beta1.AntreaAgentInfo, error) {
func (monitor *agentMonitor) GetAgentInfo() *v1beta1.AntreaAgentInfo {
ovsVersion := monitor.GetOVSVersion()
ovsConnected := ovsVersion != ""
agentCRD := &v1beta1.AntreaAgentInfo{
return &v1beta1.AntreaAgentInfo{
ObjectMeta: metav1.ObjectMeta{
Name: crdName,
Name: monitor.nodeName,
},
Version: version.GetFullVersion(),
PodRef: monitor.GetSelfPod(),
Expand All @@ -280,6 +280,10 @@ func (monitor *agentMonitor) createAgentCRD(crdName string) (*v1beta1.AntreaAgen
LocalPodNum: monitor.GetLocalPodNum(),
AgentConditions: monitor.GetAgentConditions(ovsConnected),
}
}

func (monitor *agentMonitor) createAgentCRD() (*v1beta1.AntreaAgentInfo, error) {
agentCRD := monitor.GetAgentInfo()
klog.V(2).Infof("Creating agent monitoring CRD %v", agentCRD)
return monitor.client.ClusterinformationV1beta1().AntreaAgentInfos().Create(agentCRD)
}
Expand Down
1 change: 1 addition & 0 deletions pkg/monitor/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type AgentQuerier interface {
Querier
GetOVSFlowTable() map[string]int32
GetLocalPodNum() int32
GetAgentInfo() *v1beta1.AntreaAgentInfo
}

type ControllerQuerier interface {
Expand Down
14 changes: 14 additions & 0 deletions pkg/monitor/testing/mock_monitor.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.