Skip to content

Commit

Permalink
Implement antctl agent-info
Browse files Browse the repository at this point in the history
  • Loading branch information
lzhecheng committed Jan 17, 2020
1 parent 36e5e35 commit 35c3274
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 0 deletions.
17 changes: 17 additions & 0 deletions pkg/antctl/antctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ type transformedVersionResponse struct {
AntctlVersion string `json:"antctlVersion" yaml:"antctlVersion"`
}

type transformedAgentInfoResponse struct {
handlers.ComponentAgentInfoResponse `json:",inline" yaml:",inline"`
}

// versionTransform is the AddonTransform for the version command. This function
// will try to parse the response as a ComponentVersionResponse and then populate
// it with the version of antctl to a transformedVersionResponse object.
Expand Down Expand Up @@ -76,6 +80,19 @@ var CommandList = &commandList{
CommandGroup: flat,
AddonTransform: versionTransform,
},
{
Use: "agent-info",
Short: "Print agent's basic information",
Long: "Print agent's basic information including some connections and node subnet.",
HandlerFactory: new(handlers.AgentInfo),
GroupVersion: &systemGroup,
TransformedResponse: reflect.TypeOf(transformedAgentInfoResponse{}),
Agent: true,
Controller: false,
SingleObject: true,
CommandGroup: flat,
AddonTransform: nil,
},
},
codec: scheme.Codecs,
}
58 changes: 58 additions & 0 deletions pkg/antctl/handlers/agentinfo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// 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"

"k8s.io/klog"

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

var _ Factory = new(AgentInfo)

// ComponentAgentInfoResponse describes the internal response struct of agent-info command.
// The first three fields refer to connection between the agent and controller, OVSDB and
// openflow. Subnet refers to the subnet range from the Pod CIDR allocated to the Node.
type ComponentAgentInfoResponse struct {
ControllerConn monitor.ConnStatus `json:"controllerConn,omitempty" yaml:"controllerConn,omitempty"`
OVSDBConn monitor.ConnStatus `json:"ovsdbConn,omitempty" yaml:"ovsdbConn,omitempty"`
OFConn monitor.ConnStatus `json:"ofConn,omitempty" yaml:"ofConn,omitempty"`
Subnet string `json:"subnet,omitempty" yaml:"subnet,omitempty"`
}

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

// Handler returns the function which can handle queries issued by agent-info commands,
// the handler function populate component's agent-info to the ComponentAgentInfoResponse.
func (v *AgentInfo) Handler(aq monitor.AgentQuerier, cq monitor.ControllerQuerier) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var m ComponentAgentInfoResponse
if aq != nil {
m.ControllerConn = aq.GetControllerConnection()
m.OVSDBConn = aq.GetOVSDBConnection()
m.OFConn = aq.GetOFConnection()
m.Subnet = aq.GetNodeSubnet()
}
err := json.NewEncoder(w).Encode(m)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
klog.Errorf("Error when encoding ComponentAgentInfoResponse to json: %v", err)
}
}
}
65 changes: 65 additions & 0 deletions pkg/antctl/handlers/agentinfo_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// 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"

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

"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
)

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

testcases := map[string]struct {
controllerConn monitor.ConnStatus
ovsdbConn monitor.ConnStatus
ofConn monitor.ConnStatus
subnet string
expectedOutput string
expectedStatusCode int
}{
"AgentInfo": {
controllerConn: monitor.ConnStatusUp,
ovsdbConn: monitor.ConnStatusUp,
ofConn: monitor.ConnStatusUp,
subnet: "192.168.1.0/24",
expectedOutput: "{\"controllerConn\":\"UP\",\"ovsdbConn\":\"UP\",\"ofConn\":\"UP\",\"subnet\":\"192.168.1.0/24\"}\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().GetControllerConnection().Return(tc.controllerConn)
aq.EXPECT().GetOVSDBConnection().Return(tc.ovsdbConn)
aq.EXPECT().GetOFConnection().Return(tc.ofConn)
aq.EXPECT().GetNodeSubnet().Return(tc.subnet)
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)
})
}
}
40 changes: 40 additions & 0 deletions pkg/monitor/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ const (
nodeName = "NODE_NAME"
)

type ConnStatus string

const (
ConnStatusUp ConnStatus = "UP"
ConnStatusDown ConnStatus = "DOWN"
)

// Querier provides interface for both monitor CRD and CLI to consume controller and agent status.
type Querier interface {
GetSelfPod() v1.ObjectReference
Expand All @@ -45,6 +52,10 @@ type AgentQuerier interface {
Querier
GetOVSFlowTable() map[string]int32
GetLocalPodNum() int32
GetOVSDBConnection() ConnStatus
GetOFConnection() ConnStatus
GetControllerConnection() ConnStatus
GetNodeSubnet() string
}

type ControllerQuerier interface {
Expand Down Expand Up @@ -151,6 +162,35 @@ func (monitor *agentMonitor) GetAgentConditions(ovsConnected bool) []v1beta1.Age
}
}

// GetOVSDBConnection tells if OVSDB is connected.
func (monitor *agentMonitor) GetOVSDBConnection() ConnStatus {
if _, err := monitor.ovsBridgeClient.GetOVSVersion(); err != nil {
return ConnStatusDown
}
return ConnStatusUp
}

// GetOFConnection tells if openflow is connected.
func (monitor *agentMonitor) GetOFConnection() ConnStatus {
if monitor.ofClient.IsConnected() {
return ConnStatusUp
}
return ConnStatusDown
}

// GetControllerConnection tells if controller is connected.
func (monitor *agentMonitor) GetControllerConnection() ConnStatus {
if !monitor.networkPolicyInfoQuerier.GetControllerConnectionStatus() {
return ConnStatusDown
}
return ConnStatusUp
}

// GetNodeSubnet gets the node subnet.
func (monitor *agentMonitor) GetNodeSubnet() string {
return monitor.nodeSubnet
}

func (monitor *agentMonitor) GetVersion() string {
return version.GetFullVersion()
}
Expand Down
57 changes: 57 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.

0 comments on commit 35c3274

Please sign in to comment.