feature: tap service support (#14433)

Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
Jian Qiu
2022-06-14 17:23:52 +08:00
committed by GitHub
parent d8b97722a4
commit f1e616a671
21 changed files with 1363 additions and 64 deletions
+31
View File
@@ -0,0 +1,31 @@
// Copyright 2019 Yunion
//
// 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 compute
import (
"yunion.io/x/onecloud/cmd/climc/shell"
modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
options "yunion.io/x/onecloud/pkg/mcclient/options/compute"
)
func init() {
cmd := shell.NewResourceCmd(&modules.NetTapFlows)
cmd.Create(&options.NetTapFlowCreateOptions{})
cmd.List(&options.NetTapFlowListOptions{})
cmd.Show(&options.NetTapFlowIdOptions{})
cmd.Delete(&options.NetTapFlowIdOptions{})
cmd.Perform("enable", &options.NetTapFlowIdOptions{})
cmd.Perform("disable", &options.NetTapFlowIdOptions{})
}
@@ -0,0 +1,31 @@
// Copyright 2019 Yunion
//
// 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 compute
import (
"yunion.io/x/onecloud/cmd/climc/shell"
modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
options "yunion.io/x/onecloud/pkg/mcclient/options/compute"
)
func init() {
cmd := shell.NewResourceCmd(&modules.NetTapServices)
cmd.Create(&options.NetTapServiceCreateOptions{})
cmd.List(&options.NetTapServiceListOptions{})
cmd.Show(&options.NetTapServiceIdOptions{})
cmd.Delete(&options.NetTapServiceIdOptions{})
cmd.Perform("enable", &options.NetTapServiceIdOptions{})
cmd.Perform("disable", &options.NetTapServiceIdOptions{})
}
+84
View File
@@ -0,0 +1,84 @@
// Copyright 2019 Yunion
//
// 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 compute
import "yunion.io/x/onecloud/pkg/apis"
const (
TapFlowVSwitch = "vswitch"
TapFlowGuestNic = "vnic"
TapFlowDirectionIn = "IN"
TapFlowDirectionOut = "OUT"
TapFlowDirectionBoth = "BOTH"
TapFlowIdMin = 0x10
TapFlowIdMax = 0x7fff
)
var (
TapFlowDirections = []string{
TapFlowDirectionIn,
TapFlowDirectionOut,
TapFlowDirectionBoth,
}
)
type NetTapFlowListInput struct {
apis.EnabledStatusStandaloneResourceListInput
TapId string `json:"tap_id"`
}
type NetTapFlowDetails struct {
apis.EnabledStatusStandaloneResourceDetails
// 关联的tap服务名称
Tap string `json:"tap"`
Source string `json:"source"`
SourceIps string `json:"source_ips"`
Net string `json:"net"`
}
type NetTapFlowCreateInput struct {
apis.EnabledStatusStandaloneResourceCreateInput
TapId string `json:"tap_id" required:"true" help:"tap service id or name that this flow belongs to"`
Type string `json:"type" required:"true" choices:"vswitch|vnic" help:"type of tap flow"`
HostId string `json:"host_id" help:"id or name of host to tap with"`
WireId string `json:"wire_id" help:"id or name of wire to tap with"`
VlanId int `json:"vlan_id" help:"vlan id of vswitch to tap with"`
GuestId string `json:"guest_id" help:"id or name of vm to tap with"`
// swagger:ignore
NetId string `json:"net_id" ignore:"true"`
MacAddr string `json:"mac_addr" help:"mac address of guest nic to tap with"`
IpAddr string `json:"ip_addr" help:"ip address of guest nic to tap with"`
// swagger:ignore
SourceId string `json:"source_id" ignore:"true"`
Direction string `json:"direction" help:"flow direction" choices:"IN|OUT|BOTH"`
}
+52
View File
@@ -0,0 +1,52 @@
// Copyright 2019 Yunion
//
// 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 compute
import "yunion.io/x/onecloud/pkg/apis"
const (
TapServiceHost = "host"
TapServiceGuest = "guest"
)
type NetTapServiceListInput struct {
apis.EnabledStatusStandaloneResourceListInput
}
type NetTapServiceDetails struct {
apis.EnabledStatusStandaloneResourceDetails
// 流量镜像目标名称
Target string `json:"target"`
// 流量镜像目标IP地址
TargetIps string `json:"target_ips"`
// tap flow数量
FlowCount int `json:"flow_count"`
}
type NetTapServiceCreateInput struct {
apis.EnabledStatusStandaloneResourceCreateInput
// TAP服务类型,监听宿主机的网卡还是虚拟机的网卡, 可能值为 host|guest
Type string `json:"type" required:"true" choices:"host|guest" help:"type of tap service"`
// 资源ID,如果Type=host,该值为宿主机的ID,如果Type=guest,该值为虚拟机的ID
TargetId string `json:"target_id" required:"true" help:"id of target device"`
// 监听网卡的Mac地址
MacAddr string `json:"mac_addr" help:"mac address of the device interface for tappping"`
}
+8 -33
View File
@@ -18,7 +18,6 @@ import (
"context"
"database/sql"
"fmt"
"math/rand"
"regexp"
"time"
@@ -69,6 +68,7 @@ func init() {
}
GuestnetworkManager.SetVirtualObject(GuestnetworkManager)
GuestnetworkManager.TableSpec().AddIndex(true, "ip_addr", "guest_id")
GuestnetworkManager.TableSpec().AddIndex(false, "mac_addr", "deleted")
})
}
@@ -78,7 +78,7 @@ type SGuestnetwork struct {
NetworkId string `width:"36" charset:"ascii" nullable:"false" list:"user" `
// MAC地址
MacAddr string `width:"32" charset:"ascii" nullable:"false" list:"user"`
MacAddr string `width:"32" charset:"ascii" nullable:"false" list:"user" index:"true"`
// IPv4地址
IpAddr string `width:"16" charset:"ascii" nullable:"false" list:"user"`
// IPv6地址
@@ -209,37 +209,12 @@ func (manager *SGuestnetworkManager) fetchByRowId(
return &gns[0], nil
}
const MAX_TRIES = 10
func (manager *SGuestnetworkManager) GenerateMac(suggestion string) (string, error) {
return generateMac(suggestion)
}
func (manager *SGuestnetworkManager) GenerateMac(netId string, suggestion string) (string, error) {
for tried := 0; tried < MAX_TRIES; tried += 1 {
var mac string
if len(suggestion) > 0 && regutils.MatchMacAddr(suggestion) {
mac = suggestion
suggestion = ""
} else {
b := make([]byte, 4)
_, err := rand.Read(b)
if err != nil {
log.Errorf("generate random mac failed: %s", err)
continue
}
mac = fmt.Sprintf("%s:%02x:%02x:%02x:%02x", options.Options.GlobalMacPrefix, b[0], b[1], b[2], b[3])
}
q := manager.Query().Equals("mac_addr", mac)
if len(netId) > 0 {
q = q.Equals("network_id", netId)
}
cnt, err := q.CountWithError()
if err != nil {
log.Errorf("find mac %s error %s", mac, err)
return "", err
}
if cnt == 0 {
return mac, nil
}
}
return "", fmt.Errorf("maximal retry reached")
func (manager *SGuestnetworkManager) FilterByMac(mac string) *sqlchemy.SQuery {
return manager.Query().Equals("mac_addr", mac)
}
type newGuestNetworkArgs struct {
@@ -313,7 +288,7 @@ func (manager *SGuestnetworkManager) newGuestNetwork(
provider := vpc.GetProviderName()
macAddr, err := manager.GenerateMac(network.Id, mac)
macAddr, err := manager.GenerateMac(mac)
if err != nil {
return nil, err
}
+1 -1
View File
@@ -115,7 +115,7 @@ func (m *SLoadbalancernetworkManager) NewLoadbalancerNetwork(ctx context.Context
lockman.LockObject(ctx, network)
defer lockman.ReleaseObject(ctx, network)
if req.Loadbalancer.NetworkType == api.LB_NETWORK_TYPE_VPC {
macAddr, err := GuestnetworkManager.GenerateMac(network.Id, "")
macAddr, err := GuestnetworkManager.GenerateMac("")
if err != nil {
return nil, errors.Wrapf(err, "generate macaddr")
}
+72
View File
@@ -0,0 +1,72 @@
// Copyright 2019 Yunion
//
// 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 models
import (
"fmt"
"math/rand"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/regutils"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/httperrors"
)
type IMacGenerator interface {
FilterByMac(mac string) *sqlchemy.SQuery
}
const maxMacTries = 10
func generateMac(suggestion string) (string, error) {
for tried := 0; tried < maxMacTries; tried += 1 {
var mac string
if len(suggestion) > 0 && regutils.MatchMacAddr(suggestion) {
mac = suggestion
suggestion = ""
} else {
b := make([]byte, 4)
_, err := rand.Read(b)
if err != nil {
log.Errorf("generate random mac failed: %s", err)
continue
}
mac = fmt.Sprintf("%s:%02x:%02x:%02x:%02x", options.Options.GlobalMacPrefix, b[0], b[1], b[2], b[3])
}
found := false
for _, man := range []IMacGenerator{
GuestnetworkManager,
NetTapServiceManager,
} {
q := man.FilterByMac(mac)
cnt, err := q.CountWithError()
if err != nil {
log.Errorf("find mac %s error %s", mac, err)
return "", err
}
if cnt > 0 {
found = true
break
}
}
if !found {
return mac, nil
}
}
return "", errors.Wrap(httperrors.ErrTooManyAttempts, "maximal retry reached")
}
+15 -3
View File
@@ -144,7 +144,13 @@ func (man *SNatGatewayManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field
return q, httperrors.ErrNotFound
}
func (man *SNatGatewayManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.NatgatewayCreateInput) (api.NatgatewayCreateInput, error) {
func (man *SNatGatewayManager) ValidateCreateData(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
input api.NatgatewayCreateInput,
) (api.NatgatewayCreateInput, error) {
if len(input.NetworkId) == 0 {
return input, httperrors.NewMissingParameterError("network_id")
}
@@ -216,7 +222,13 @@ func (man *SNatGatewayManager) ValidateCreateData(ctx context.Context, userCred
return driver.ValidateCreateNatGateway(ctx, userCred, input)
}
func (self *SNatGateway) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
func (self *SNatGateway) PostCreate(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
data jsonutils.JSONObject,
) {
self.SInfrasResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
err := self.StartNatGatewayCreateTask(ctx, userCred, data.(*jsonutils.JSONDict))
@@ -348,7 +360,7 @@ func (self *SNatGateway) GetDTableSize(filter func(q *sqlchemy.SQuery) *sqlchemy
return q.CountWithError()
}
func (manager SNatGatewayManager) FetchCustomizeColumns(
func (manager *SNatGatewayManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
+337
View File
@@ -0,0 +1,337 @@
// Copyright 2019 Yunion
//
// 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 models
import (
"context"
"database/sql"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/tristate"
"yunion.io/x/pkg/utils"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SNetTapFlowManager struct {
db.SEnabledStatusStandaloneResourceBaseManager
}
var NetTapFlowManager *SNetTapFlowManager
func init() {
NetTapFlowManager = &SNetTapFlowManager{
SEnabledStatusStandaloneResourceBaseManager: db.NewEnabledStatusStandaloneResourceBaseManager(
SNetTapFlow{},
"net_tap_flows_tbl",
"tap_flow",
"tap_flows",
),
}
NetTapFlowManager.SetVirtualObject(NetTapFlowManager)
}
type SNetTapFlow struct {
db.SEnabledStatusStandaloneResourceBase
TapId string `width:"36" charset:"ascii" nullable:"false" list:"admin" create:"admin_required"`
Type string `width:"10" charset:"ascii" list:"admin" create:"admin_required"`
SourceId string `width:"36" charset:"ascii" nullable:"false" list:"admin" create:"admin_required"`
NetId string `width:"36" charset:"ascii" nullable:"false" list:"admin" create:"admin_required"`
MacAddr string `width:"18" charset:"ascii" list:"admin" create:"admin_optional"`
VlanId int `nullable:"true" list:"admin" create:"admin_optional"`
Direction string `width:"6" charset:"ascii" list:"admin" create:"admin_required" default:"BOTH"`
FlowId uint16 `nullable:"false" list:"admin"`
}
func (man *SNetTapFlowManager) ListItemFilter(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.NetTapFlowListInput,
) (*sqlchemy.SQuery, error) {
q, err := man.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ListItemFilter")
}
if len(query.TapId) > 0 {
tapObj, err := NetTapServiceManager.FetchByIdOrName(userCred, query.TapId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return nil, errors.Wrapf(httperrors.ErrResourceNotFound, "%s %s not found", NetTapServiceManager.Keyword(), query.TapId)
} else {
return nil, errors.Wrap(err, "NetTapServiceManager.FetchByIdOrName")
}
}
q = q.Equals("tap_id", tapObj.GetId())
}
return q, nil
}
func (man *SNetTapFlowManager) OrderByExtraFields(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.NetTapFlowListInput,
) (*sqlchemy.SQuery, error) {
q, err := man.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (man *SNetTapFlowManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
var err error
q, err = man.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
return q, httperrors.ErrNotFound
}
func (manager *SNetTapFlowManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []api.NetTapFlowDetails {
rows := make([]api.NetTapFlowDetails, len(objs))
stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
tapIds := make([]string, len(objs))
for i := range rows {
rows[i] = api.NetTapFlowDetails{
EnabledStatusStandaloneResourceDetails: stdRows[i],
}
flow := objs[i].(*SNetTapFlow)
tapIds[i] = flow.TapId
}
tapIdMap, err := db.FetchIdNameMap2(NetTapServiceManager, tapIds)
if err != nil {
log.Errorf("FetchIdNameMap2 fail: %s", err)
return rows
}
for i := range rows {
if name, ok := tapIdMap[tapIds[i]]; ok {
rows[i].Tap = name
}
}
return rows
}
func (flow *SNetTapFlow) getMoreDetails(ctx context.Context, details api.NetTapFlowDetails) api.NetTapFlowDetails {
switch flow.Type {
case api.TapFlowVSwitch:
host := HostManager.FetchHostById(flow.SourceId)
details.Source = host.Name
details.SourceIps = host.AccessIp
wire := WireManager.FetchWireById(flow.NetId)
details.Net = wire.Name
case api.TapFlowGuestNic:
guest := GuestManager.FetchGuestById(flow.SourceId)
details.Source = guest.Name
ret := fetchGuestIPs([]string{flow.SourceId}, tristate.False)
details.SourceIps = strings.Join(ret[flow.SourceId], ",")
netObj, _ := NetworkManager.FetchById(flow.NetId)
details.Net = netObj.GetName()
}
return details
}
func (manager *SNetTapFlowManager) ValidateCreateData(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
input api.NetTapFlowCreateInput,
) (api.NetTapFlowCreateInput, error) {
var err error
input.EnabledStatusStandaloneResourceCreateInput, err = manager.SEnabledStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledStatusStandaloneResourceCreateInput)
if err != nil {
return input, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ValidateCreateData(")
}
tapObj, err := NetTapServiceManager.FetchByIdOrName(userCred, input.TapId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return input, httperrors.NewResourceNotFoundError2(NetTapServiceManager.Keyword(), input.TapId)
} else {
return input, errors.Wrap(err, "NetTapServiceManager.FetchByIdOrName")
}
}
input.TapId = tapObj.GetId()
switch input.Type {
case api.TapFlowVSwitch:
hostObj, err := HostManager.FetchByIdOrName(userCred, input.HostId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return input, httperrors.NewResourceNotFoundError2(HostManager.Keyword(), input.HostId)
} else {
return input, errors.Wrap(err, "HostManager.FetchByIdOrName")
}
}
wireObj, err := WireManager.FetchByIdOrName(userCred, input.WireId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return input, httperrors.NewResourceNotFoundError2(WireManager.Keyword(), input.WireId)
} else {
return input, errors.Wrap(err, "WireManager.FetchByIdOrName")
}
}
host := hostObj.(*SHost)
if host.HostType != api.HOST_TYPE_HYPERVISOR {
return input, errors.Wrapf(httperrors.ErrNotSupported, "host type %s not supported", host.HostType)
}
wire := wireObj.(*SWire)
netifs := host.GetNetifsOnWire(wire)
if len(netifs) == 0 {
return input, errors.Wrapf(httperrors.ErrInvalidStatus, "host %s and wire %s not attached", input.HostId, input.WireId)
}
ipmiCnt := 0
nicCnt := 0
for _, netif := range netifs {
if netif.NicType == api.NIC_TYPE_IPMI {
ipmiCnt++
}
nicCnt++
}
if ipmiCnt == nicCnt {
return input, errors.Wrapf(httperrors.ErrInvalidStatus, "host %s and wire %s attached with IPMI links", input.HostId, input.WireId)
}
input.SourceId = host.Id
input.MacAddr = ""
input.NetId = wire.Id
if input.VlanId <= 0 || input.VlanId > 4095 {
return input, errors.Wrapf(httperrors.ErrInputParameter, "invalid vlan id %d", input.VlanId)
}
case api.TapFlowGuestNic:
guestObj, err := GuestManager.FetchByIdOrName(userCred, input.GuestId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return input, httperrors.NewResourceNotFoundError2(GuestManager.Keyword(), input.GuestId)
} else {
return input, errors.Wrap(err, "GuestManager.FetchByIdOrName")
}
}
guest := guestObj.(*SGuest)
if guest.Hypervisor != api.HYPERVISOR_KVM {
return input, errors.Wrapf(httperrors.ErrInvalidStatus, "hypervisor %s not supported", guest.Hypervisor)
}
gns, err := GuestnetworkManager.FetchByGuestId(guest.Id)
if err != nil {
return input, errors.Wrap(err, "GuestnetworkManager.FetchByGuestId")
}
var gn *SGuestnetwork
if len(input.IpAddr) == 0 && len(input.MacAddr) == 0 {
if len(gns) == 1 {
gn = &gns[0]
} else {
return input, errors.Wrap(httperrors.ErrInputParameter, "either ip_addr or mac_addr should be specified")
}
} else {
for i := range gns {
if (len(input.IpAddr) > 0 && input.IpAddr == gns[i].IpAddr) || (len(input.MacAddr) > 0 && input.MacAddr == gns[i].MacAddr) {
gn = &gns[i]
break
}
}
if gn == nil {
return input, errors.Wrap(httperrors.ErrNotFound, "Guest network not found")
}
}
input.SourceId = guest.Id
input.MacAddr = gn.MacAddr
input.NetId = gn.NetworkId
input.VlanId = 0
default:
return input, errors.Wrapf(httperrors.ErrInputParameter, "invalid flow type %s", input.Type)
}
if len(input.Direction) == 0 {
input.Direction = api.TapFlowDirectionBoth
}
if !utils.IsInStringArray(input.Direction, api.TapFlowDirections) {
return input, errors.Wrapf(httperrors.ErrNotSupported, "unsupported direction %s", input.Direction)
}
return input, nil
}
func (tap *SNetTapFlow) CustomizeCreate(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
data jsonutils.JSONObject,
) error {
// generate flowId
err := func() error {
lockman.LockClass(ctx, NetTapFlowManager, "")
defer lockman.ReleaseClass(ctx, NetTapFlowManager, "")
flowId, err := NetTapFlowManager.getFreeFlowId()
if err != nil {
return errors.Wrap(err, "getFreeFlowId")
}
tap.FlowId = flowId
return nil
}()
if err != nil {
return errors.Wrap(err, "generate flow id")
}
return tap.SEnabledStatusStandaloneResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
}
func (manager *SNetTapFlowManager) getFreeFlowId() (uint16, error) {
flowIds := make([]struct {
FlowId uint16 `json:"flow_id"`
}, 0)
q := manager.Query("flow_id").Asc("flow_id")
err := q.All(&flowIds)
if err != nil && errors.Cause(err) != sql.ErrNoRows {
return 0, errors.Wrap(err, "queryAll")
}
if len(flowIds) == 0 {
return api.TapFlowIdMin, nil
}
if flowIds[0].FlowId > api.TapFlowIdMin {
return flowIds[0].FlowId - 1, nil
}
if flowIds[len(flowIds)-1].FlowId < api.TapFlowIdMax {
return flowIds[len(flowIds)-1].FlowId + 1, nil
}
for i := 0; i < len(flowIds)-1; i++ {
if flowIds[i].FlowId+1 < flowIds[i+1].FlowId {
return flowIds[i].FlowId + 1, nil
}
}
return 0, errors.Wrap(httperrors.ErrOutOfResource, "run out of flow id!!!")
}
+325
View File
@@ -0,0 +1,325 @@
// Copyright 2019 Yunion
//
// 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 models
import (
"context"
"database/sql"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/tristate"
"yunion.io/x/pkg/util/netutils"
"yunion.io/x/sqlchemy"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/seclib2"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
type SNetTapServiceManager struct {
db.SEnabledStatusStandaloneResourceBaseManager
}
var NetTapServiceManager *SNetTapServiceManager
func init() {
NetTapServiceManager = &SNetTapServiceManager{
SEnabledStatusStandaloneResourceBaseManager: db.NewEnabledStatusStandaloneResourceBaseManager(
SNetTapService{},
"net_tap_services_tbl",
"tap_service",
"tap_services",
),
}
NetTapServiceManager.SetVirtualObject(NetTapServiceManager)
NetTapServiceManager.TableSpec().AddIndex(false, "mac_addr", "deleted")
}
type SNetTapService struct {
db.SEnabledStatusStandaloneResourceBase
// 流量采集端类型,虚拟机(guest)还是宿主机(host)
Type string `width:"10" charset:"ascii" list:"admin" create:"admin_required"`
// 接受流量的目标ID,如果type=host,是hostId,如果type=guest,是guestId
TargetId string `width:"36" charset:"ascii" nullable:"false" list:"admin" create:"admin_required"`
// 接受流量的Mac地址
MacAddr string `width:"18" charset:"ascii" list:"admin" create:"admin_optional"`
// 网卡名称
Ifname string `width:"16" charset:"ascii" nullable:"true" list:"admin"`
}
func (man *SNetTapServiceManager) ListItemFilter(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.NetTapServiceListInput,
) (*sqlchemy.SQuery, error) {
q, err := man.SEnabledStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusStandaloneResourceBaseManager.ListItemFilter")
}
return q, nil
}
func (man *SNetTapServiceManager) OrderByExtraFields(
ctx context.Context,
q *sqlchemy.SQuery,
userCred mcclient.TokenCredential,
query api.NetTapServiceListInput,
) (*sqlchemy.SQuery, error) {
q, err := man.SEnabledStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusStandaloneResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.OrderByExtraFields")
}
return q, nil
}
func (man *SNetTapServiceManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
var err error
q, err = man.SEnabledStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
return q, httperrors.ErrNotFound
}
func (manager *SNetTapServiceManager) FetchCustomizeColumns(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
objs []interface{},
fields stringutils2.SSortedStrings,
isList bool,
) []api.NetTapServiceDetails {
rows := make([]api.NetTapServiceDetails, len(objs))
stdRows := manager.SEnabledStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = api.NetTapServiceDetails{
EnabledStatusStandaloneResourceDetails: stdRows[i],
}
rows[i] = objs[i].(*SNetTapService).getMoreDetails(ctx, rows[i])
}
return rows
}
func (srv *SNetTapService) getMoreDetails(ctx context.Context, details api.NetTapServiceDetails) api.NetTapServiceDetails {
var err error
switch srv.Type {
case api.TapServiceHost:
host := HostManager.FetchHostById(srv.TargetId)
details.Target = host.Name
details.TargetIps = host.AccessIp
case api.TapServiceGuest:
guest := GuestManager.FetchGuestById(srv.TargetId)
details.Target = guest.Name
ret := fetchGuestIPs([]string{srv.TargetId}, tristate.False)
details.TargetIps = strings.Join(ret[srv.TargetId], ",")
}
details.FlowCount, err = srv.getFlowsCount()
if err != nil {
log.Errorf("getFlowsCount %s", err)
}
return details
}
func (srv *SNetTapService) getFlowsQuery() *sqlchemy.SQuery {
return NetTapFlowManager.Query().Equals("tap_id", srv.Id)
}
func (srv *SNetTapService) getFlowsCount() (int, error) {
return srv.getFlowsQuery().CountWithError()
}
func (srv *SNetTapService) getFlows() ([]SNetTapFlow, error) {
flows := make([]SNetTapFlow, 0)
q := srv.getFlowsQuery()
err := db.FetchModelObjects(NetTapFlowManager, q, &flows)
if err != nil {
return nil, errors.Wrap(err, "FetchModelObjects")
}
return flows, nil
}
func (srv *SNetTapService) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
cnt, err := srv.getFlowsCount()
if err != nil {
return errors.Wrap(err, "getFlowCount")
}
if cnt > 0 {
return httperrors.NewNotEmptyError("Tap service has associated flows")
}
return srv.SEnabledStatusStandaloneResourceBase.ValidateDeleteCondition(ctx, info)
}
func (manager *SNetTapServiceManager) ValidateCreateData(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
input api.NetTapServiceCreateInput,
) (api.NetTapServiceCreateInput, error) {
var err error
input.EnabledStatusStandaloneResourceCreateInput, err = manager.SEnabledStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledStatusStandaloneResourceCreateInput)
if err != nil {
return input, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ValidateCreateData(")
}
switch input.Type {
case api.TapServiceHost:
hostObj, err := HostManager.FetchByIdOrName(userCred, input.TargetId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return input, errors.Wrapf(httperrors.ErrResourceNotFound, "%s %s", HostManager.Keyword(), input.TargetId)
} else {
return input, errors.Wrap(err, "HostManager.FetchByIdOrName")
}
}
host := hostObj.(*SHost)
if host.HostType != api.HOST_TYPE_HYPERVISOR {
return input, errors.Wrapf(httperrors.ErrNotSupported, "host type %s not supported", host.HostType)
}
if len(input.MacAddr) > 0 {
input.MacAddr = netutils.FormatMacAddr(input.MacAddr)
nic := host.GetNetInterface(input.MacAddr)
if nic == nil {
return input, errors.Wrap(errors.ErrNotFound, "host.GetNetInterface")
}
if len(nic.WireId) > 0 {
return input, errors.Wrap(httperrors.ErrNotEmpty, "interface has been used")
}
}
_, err = manager.fetchByHostIdMac(hostObj.GetId(), input.MacAddr)
if err == nil {
return input, errors.Wrapf(httperrors.ErrNotEmpty, "host %s(%s) has been attached to tap service", input.TargetId, input.MacAddr)
} else if errors.Cause(err) != sql.ErrNoRows {
return input, errors.Wrap(err, "fetchGuestById")
}
input.TargetId = hostObj.GetId()
case api.TapServiceGuest:
guestObj, err := GuestManager.FetchByIdOrName(userCred, input.TargetId)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return input, errors.Wrapf(httperrors.ErrResourceNotFound, "%s %s", GuestManager.Keyword(), input.TargetId)
} else {
return input, errors.Wrap(err, "GuestManager.FetchByIdOrName")
}
}
guest := guestObj.(*SGuest)
if guest.Hypervisor != api.HYPERVISOR_KVM {
return input, errors.Wrapf(httperrors.ErrNotSupported, "hypervisor %s not supported", guest.Hypervisor)
}
// check the guest attach to tap
_, err = manager.fetchByGuestId(guestObj.GetId())
if err == nil {
return input, errors.Wrapf(httperrors.ErrNotEmpty, "guest %s has been attached to tap service", input.TargetId)
} else if errors.Cause(err) != sql.ErrNoRows {
return input, errors.Wrap(err, "fetchGuestById")
}
input.TargetId = guestObj.GetId()
default:
return input, errors.Wrapf(httperrors.ErrNotSupported, "unsupported type %s", input.Type)
}
return input, nil
}
func (man *SNetTapServiceManager) fetchByGuestId(guestId string) (*SNetTapService, error) {
return man.fetchByTargetMac(api.TapServiceGuest, guestId, "")
}
func (man *SNetTapServiceManager) fetchByHostIdMac(hostId, mac string) (*SNetTapService, error) {
return man.fetchByTargetMac(api.TapServiceHost, hostId, mac)
}
func (man *SNetTapServiceManager) fetchByTargetMac(tapTyep, targetId, mac string) (*SNetTapService, error) {
q := man.Query().Equals("type", api.TapServiceGuest).Equals("target_id", targetId)
if len(mac) > 0 {
q = q.Equals("mac_addr", mac)
}
tapObj, err := db.NewModelObject(man)
if err != nil {
return nil, errors.Wrap(err, "NewModelObject")
}
err = q.First(tapObj)
if err != nil {
return nil, errors.Wrap(err, "First")
}
return tapObj.(*SNetTapService), nil
}
func (tap *SNetTapService) CustomizeCreate(
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
data jsonutils.JSONObject,
) error {
input := api.NetTapServiceCreateInput{}
err := data.Unmarshal(&input)
if err != nil {
return errors.Wrap(err, "Unmarshal NetTapServiceCreateInput")
}
switch input.Type {
case api.TapServiceGuest:
err := func() error {
lockman.LockClass(ctx, NetTapServiceManager, "")
defer lockman.ReleaseClass(ctx, NetTapServiceManager, "")
// generate mac
mac, err := NetTapServiceManager.GenerateMac(input.MacAddr)
if err != nil {
return errors.Wrap(err, "GenerateMac")
}
ifname, err := NetTapServiceManager.generateIfname(mac)
if err != nil {
return errors.Wrap(err, "generateIfname")
}
tap.Ifname = ifname
tap.MacAddr = mac
return nil
}()
if err != nil {
return errors.Wrap(err, "generate mac and ifname")
}
}
return tap.SEnabledStatusStandaloneResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
}
func (manager *SNetTapServiceManager) generateIfname(seed string) (string, error) {
for tried := 0; tried < maxMacTries; tried++ {
ifname := "tap" + seclib2.HashId(seed, byte(tried), 6)
cnt, err := manager.Query().Equals("ifname", ifname).CountWithError()
if err != nil {
return "", errors.Wrap(err, "CountWithError")
}
if cnt == 0 {
return ifname, nil
}
}
return "", errors.Wrap(httperrors.ErrTooManyAttempts, "maximal retry reached")
}
func (manager *SNetTapServiceManager) GenerateMac(suggestion string) (string, error) {
return generateMac(suggestion)
}
func (manager *SNetTapServiceManager) FilterByMac(mac string) *sqlchemy.SQuery {
return manager.Query().Equals("mac_addr", mac)
}
+3
View File
@@ -243,6 +243,9 @@ func InitHandlers(app *appsrv.Application) {
models.InstanceBackupManager,
models.IPv6GatewayManager,
models.NetTapServiceManager,
models.NetTapFlowManager,
} {
db.RegisterModelManager(manager)
handler := db.NewModelHandler(manager)
+63 -26
View File
@@ -40,6 +40,7 @@ import (
identityapi "yunion.io/x/onecloud/pkg/apis/identity"
napi "yunion.io/x/onecloud/pkg/apis/notify"
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/hostman/guestfs/fsdriver"
"yunion.io/x/onecloud/pkg/hostman/host_health"
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
@@ -1337,6 +1338,18 @@ func (h *SHostInfo) getNetworkInfo() {
}
func (h *SHostInfo) uploadNetworkInfo() {
phyNics, err := sysutils.Nics()
if err != nil {
h.onFail(errors.Wrap(err, "parse physical nics info"))
return
}
for _, pnic := range phyNics {
err := h.doSendPhysicalNicInfo(pnic)
if err != nil {
h.onFail(errors.Wrapf(err, "doSendPhysicalNicInfo %s", pnic.Dev))
return
}
}
for _, nic := range h.Nics {
if len(nic.WireId) == 0 {
if len(nic.Network) == 0 {
@@ -1352,30 +1365,57 @@ func (h *SHostInfo) uploadNetworkInfo() {
return
} else {
nic.Network, _ = wireInfo.GetString("name")
h.doUploadNicInfo(nic)
err := h.doUploadNicInfo(nic)
if err != nil {
h.onFail(errors.Wrapf(err, "doUploadNicInfo %s", nic.Inter))
return
}
}
} else {
h.doUploadNicInfo(nic)
err := h.doUploadNicInfo(nic)
if err != nil {
h.onFail(errors.Wrapf(err, "doUploadNicInfo %s", nic.Inter))
return
}
}
} else {
h.doSyncNicInfo(nic)
err := h.doSyncNicInfo(nic)
if err != nil {
h.onFail(errors.Wrapf(err, "doSyncNicInfo %s", nic.Inter))
return
}
}
}
h.getStoragecacheInfo()
}
func (h *SHostInfo) doUploadNicInfo(nic *SNIC) {
log.Infof("Upload NIC br:%s if:%s", nic.Bridge, nic.Inter)
func (h *SHostInfo) doSendPhysicalNicInfo(nic *types.SNicDevInfo) error {
return h.doUploadNicInfoInternal(nic.Dev, nic.Mac.String(), "", "", "", nic.Up != nil && *nic.Up)
}
func (h *SHostInfo) doUploadNicInfo(nic *SNIC) error {
err := h.doUploadNicInfoInternal(nic.Inter, nic.BridgeDev.GetMac(), nic.Network, nic.Bridge, nic.Ip, true)
if err != nil {
return errors.Wrap(err, "doUploadNicInfoInternal")
}
return h.onUploadNicInfoSucc(nic)
}
func (h *SHostInfo) doUploadNicInfoInternal(ifname, mac, net, bridge, ipaddr string, isUp bool) error {
log.Infof("Upload NIC br:%s if:%s", bridge, ifname)
content := jsonutils.NewDict()
content.Set("mac", jsonutils.NewString(nic.BridgeDev.GetMac()))
content.Set("wire", jsonutils.NewString(nic.Network))
content.Set("bridge", jsonutils.NewString(nic.Bridge))
content.Set("interface", jsonutils.NewString(nic.Inter))
content.Set("link_up", jsonutils.JSONTrue)
if len(nic.Ip) > 0 {
content.Set("ip_addr", jsonutils.NewString(nic.Ip))
if nic.Ip == h.GetMasterIp() {
content.Set("mac", jsonutils.NewString(mac))
content.Set("wire", jsonutils.NewString(net))
content.Set("bridge", jsonutils.NewString(bridge))
content.Set("interface", jsonutils.NewString(ifname))
if isUp {
content.Set("link_up", jsonutils.JSONTrue)
} else {
content.Set("link_up", jsonutils.JSONFalse)
}
if len(ipaddr) > 0 {
content.Set("ip_addr", jsonutils.NewString(ipaddr))
if ipaddr == h.GetMasterIp() {
content.Set("nic_type", jsonutils.NewString(api.NIC_TYPE_ADMIN))
}
// always try to allocate from reserved pool
@@ -1384,14 +1424,12 @@ func (h *SHostInfo) doUploadNicInfo(nic *SNIC) {
_, err := modules.Hosts.PerformAction(h.GetSession(),
h.HostId, "add-netif", content)
if err != nil {
h.onFail(err)
return
} else {
h.onUploadNicInfoSucc(nic)
return errors.Wrap(err, "modules.Hosts.PerformAction add-netif")
}
return nil
}
func (h *SHostInfo) doSyncNicInfo(nic *SNIC) {
func (h *SHostInfo) doSyncNicInfo(nic *SNIC) error {
content := jsonutils.NewDict()
content.Set("bridge", jsonutils.NewString(nic.Bridge))
content.Set("interface", jsonutils.NewString(nic.Inter))
@@ -1400,16 +1438,15 @@ func (h *SHostInfo) doSyncNicInfo(nic *SNIC) {
_, err := modules.Hostwires.Update(h.GetSession(),
h.HostId, nic.WireId, query, content)
if err != nil {
h.onFail(err)
return
return errors.Wrap(err, "modules.Hostwires.Update")
}
return nil
}
func (h *SHostInfo) onUploadNicInfoSucc(nic *SNIC) {
func (h *SHostInfo) onUploadNicInfoSucc(nic *SNIC) error {
res, err := modules.Hostwires.Get(h.GetSession(), h.HostId, nic.Network, nil)
if err != nil {
h.onFail(err)
return
return errors.Wrap(err, "modules.Hostwires.Get")
} else {
bridge, _ := res.GetString("bridge")
iface, _ := res.GetString("interface")
@@ -1424,10 +1461,10 @@ func (h *SHostInfo) onUploadNicInfoSucc(nic *SNIC) {
}
nic.SetWireId(wire, wireId, bandwidth)
} else {
h.onFail("GetMatchNic failed!!!")
return
return errors.Error("GetMatchNic failed!!!")
}
}
return nil
}
func (h *SHostInfo) getStoragecacheInfo() {
@@ -0,0 +1,35 @@
// Copyright 2019 Yunion
//
// 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 compute
import (
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
"yunion.io/x/onecloud/pkg/mcclient/modules"
)
var (
NetTapFlows modulebase.ResourceManager
)
func init() {
NetTapFlows = modules.NewComputeManager("tap_flow", "tap_flows",
[]string{
"id", "name", "enabled", "type", "tap", "tap_id", "source_id", "source", "source_ips", "net_id", "net", "vlan_id", "mac_addr", "direction",
},
[]string{},
)
modules.RegisterCompute(&NetTapFlows)
}
@@ -0,0 +1,35 @@
// Copyright 2019 Yunion
//
// 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 compute
import (
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
"yunion.io/x/onecloud/pkg/mcclient/modules"
)
var (
NetTapServices modulebase.ResourceManager
)
func init() {
NetTapServices = modules.NewComputeManager("tap_service", "tap_services",
[]string{
"id", "name", "enabled", "type", "target_id", "target", "target_ips", "mac_addr", "flow_count",
},
[]string{},
)
modules.RegisterCompute(&NetTapServices)
}
@@ -0,0 +1,52 @@
// Copyright 2019 Yunion
//
// 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 compute
import (
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type NetTapFlowCreateOptions struct {
api.NetTapFlowCreateInput
}
func (o *NetTapFlowCreateOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(o), nil
}
type NetTapFlowListOptions struct {
options.BaseListOptions
TapId string `help:"filter by tap id" json:"tap_id"`
}
func (o *NetTapFlowListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(o)
}
type NetTapFlowIdOptions struct {
ID string `json:"-" help:"Id or name of net tap service"`
}
func (o *NetTapFlowIdOptions) GetId() string {
return o.ID
}
func (o *NetTapFlowIdOptions) Params() (jsonutils.JSONObject, error) {
return options.StructToParams(o)
}
@@ -0,0 +1,50 @@
// Copyright 2019 Yunion
//
// 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 compute
import (
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/mcclient/options"
)
type NetTapServiceCreateOptions struct {
api.NetTapServiceCreateInput
}
func (o *NetTapServiceCreateOptions) Params() (jsonutils.JSONObject, error) {
return jsonutils.Marshal(o), nil
}
type NetTapServiceListOptions struct {
options.BaseListOptions
}
func (o *NetTapServiceListOptions) Params() (jsonutils.JSONObject, error) {
return options.ListStructToParams(o)
}
type NetTapServiceIdOptions struct {
ID string `json:"-" help:"Id or name of net tap service"`
}
func (o *NetTapServiceIdOptions) GetId() string {
return o.ID
}
func (o *NetTapServiceIdOptions) Params() (jsonutils.JSONObject, error) {
return options.StructToParams(o)
}
+35
View File
@@ -0,0 +1,35 @@
// Copyright 2019 Yunion
//
// 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 seclib2
import (
"crypto/sha256"
"encoding/binary"
"fmt"
)
func HashId(seed string, idx byte, width int) string {
h := sha256.New()
h.Write([]byte(seed))
if idx > 0 {
h.Write([]byte{idx})
}
sum := h.Sum(nil)
numStr := fmt.Sprintf(fmt.Sprintf("%%0%dx", width), binary.BigEndian.Uint64(sum[:8]))
if len(numStr) > width {
numStr = numStr[:width]
}
return numStr
}
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2019 Yunion
//
// 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 seclib2
import "testing"
func TestHashId(t *testing.T) {
for i := 0; i < 256; i++ {
t.Log(HashId("test", byte(i), 6))
}
}
+5 -1
View File
@@ -182,6 +182,10 @@ func unloadKvmModule(name string) bool {
func GetKernelModuleParameter(name, moduel string) string {
pa := path.Join("/sys/module/", strings.Replace(name, "-", "_", -1), "/parameters/", moduel)
return GetSysConfig(pa)
}
func GetSysConfig(pa string) string {
if f, err := os.Stat(pa); err == nil {
if f.IsDir() {
return ""
@@ -218,7 +222,7 @@ func SetSysConfig(cpath, val string) bool {
log.Errorln(err)
return false
}
if string(oval) != val {
if strings.TrimSpace(string(oval)) != val {
err = fileutils2.FilePutContents(cpath, val, false)
if err == nil {
return true
+76
View File
@@ -0,0 +1,76 @@
// Copyright 2019 Yunion
//
// 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 sysutils
import (
"io/ioutil"
"net"
"os"
"path/filepath"
"strconv"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/httperrors"
)
const (
sysNetPath = "/sys/class/net"
)
func Nics() ([]*types.SNicDevInfo, error) {
if _, err := os.Stat(sysNetPath); !os.IsNotExist(err) {
nicDevs, err := ioutil.ReadDir(sysNetPath)
if err != nil {
log.Errorf("ReadDir %s error: %s", sysNetPath, err)
return nil, errors.Wrapf(err, "ioutil.ReadDir(%s)", sysNetPath)
}
nics := make([]*types.SNicDevInfo, 0)
for _, nic := range nicDevs {
netPath := filepath.Join(sysNetPath, nic.Name())
if _, err := os.Stat(filepath.Join(netPath, "device")); os.IsNotExist(err) {
continue
}
speedStr := GetSysConfig(filepath.Join(netPath, "speed"))
speed := 0
if len(speedStr) > 0 {
speed, _ = strconv.Atoi(speedStr)
}
carrier := GetSysConfig(filepath.Join(netPath, "carrier"))
up := false
if carrier == "1" {
up = true
}
mac, _ := net.ParseMAC(GetSysConfig(filepath.Join(netPath, "address")))
mtuStr := GetSysConfig(filepath.Join(netPath, "mtu"))
mtu := 0
if len(mtuStr) > 0 {
mtu, _ = strconv.Atoi(mtuStr)
}
nicInfo := &types.SNicDevInfo{
Dev: nic.Name(),
Mac: mac,
Speed: speed,
Up: &up,
Mtu: mtu,
}
nics = append(nics, nicInfo)
}
return nics, nil
}
return nil, errors.Wrapf(httperrors.ErrNotSupported, "no such dir %s", sysNetPath)
}
+30
View File
@@ -0,0 +1,30 @@
// Copyright 2019 Yunion
//
// 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 sysutils
import (
"testing"
"yunion.io/x/jsonutils"
)
func TestNics(t *testing.T) {
nics, err := Nics()
if err != nil {
t.Errorf("error %s", err)
} else {
t.Logf("%s", jsonutils.Marshal(nics))
}
}