Skip to content

Commit

Permalink
Add tencent cloud VPC network support
Browse files Browse the repository at this point in the history
  • Loading branch information
dragonorloong authored and boblong committed Mar 24, 2021
1 parent 36a227d commit fdef594
Show file tree
Hide file tree
Showing 22 changed files with 19,062 additions and 5 deletions.
16 changes: 16 additions & 0 deletions Documentation/backends.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ For more information on configuration options for cloud components, see:
* [AliCloud VPC Backend for Flannel][alicloud-vpc]
* [Amazon VPC Backend for Flannel][amazon-vpc]
* [GCE Backend for Flannel][gce-backend]
* [TencentCloud VPC Backend for Flannel][tencentcloud-vpc]

## Recommended backends

Expand Down Expand Up @@ -102,10 +103,25 @@ Command to create a compute instance with the correct permissions and IP forward

Route Limits: GCE [limits](https://cloud.google.com/compute/docs/resource-quotas) the number of routes for every *project* to 100 by default.

### TencentCloud VPC

Use TencentCloud VPC to create IP routes in a [TencentCloud VPC route table](https://intl.cloud.tencent.com/product/vpc) when running in an TencentCloud VPC. This mitigates the need to create a separate flannel interface.

Requirements:
* Running on an CVM instance that is in an TencentCloud VPC.
* Permission require `accessid` and `keysecret`.
* `Type` (string): `tencent-vpc`
* `AccessKeyID` (string): API access key ID. Can also be configured with environment ACCESS_KEY_ID.
* `AccessKeySecret` (string): API access key secret. Can also be configured with environment ACCESS_KEY_SECRET.

Route Limits: TencentCloud VPC limits the number of entries per route table to 50.



[alicloud-vpc]: https://github.com/flannel-io/flannel/blob/master/Documentation/alicloud-vpc-backend.md
[amazon-vpc]: https://github.com/flannel-io/flannel/blob/master/Documentation/aws-vpc-backend.md
[gce-backend]: https://github.com/flannel-io/flannel/blob/master/Documentation/gce-backend.md
[tencentcloud-vpc]: https://github.com/flannel-io/flannel/blob/master/Documentation/tencentcloud-vpc-backend.md


### IPIP
Expand Down
7 changes: 7 additions & 0 deletions Documentation/tencentcloud-vpc-backend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# TencentCloud VPC Backend for Flannel

There are only two differences between the usage method and Alibaba Cloud:
1. Tencent Cloud needs to create a routing table, while Alibaba Cloud creates a switch
2. In network/config, backend-type is "tencent-vpc"


6 changes: 3 additions & 3 deletions backend/alivpc/alivpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ import (
"os"
"sync"

"github.com/flannel-io/flannel/backend"
"github.com/flannel-io/flannel/pkg/ip"
"github.com/flannel-io/flannel/subnet"
"github.com/denverdino/aliyungo/common"
"github.com/denverdino/aliyungo/ecs"
"github.com/denverdino/aliyungo/metadata"
"github.com/flannel-io/flannel/backend"
"github.com/flannel-io/flannel/pkg/ip"
"github.com/flannel-io/flannel/subnet"
log "k8s.io/klog"
)

Expand Down
211 changes: 211 additions & 0 deletions backend/tencentvpc/tencentvpc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
// Copyright 2015 flannel 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.
// +build !windows

package tencentvpc

import (
"encoding/json"
"fmt"
"github.com/flannel-io/flannel/backend"
"github.com/flannel-io/flannel/pkg/ip"
"github.com/flannel-io/flannel/subnet"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
vpc "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/vpc/v20170312"
"golang.org/x/net/context"
"io/ioutil"
log "k8s.io/klog"
"net/http"
"os"
"sync"
)

func init() {
backend.Register("tencent-vpc", New)
}

type TencentVpcBackend struct {
sm subnet.Manager
extIface *backend.ExternalInterface
}

func New(sm subnet.Manager, extIface *backend.ExternalInterface) (backend.Backend, error) {
be := TencentVpcBackend{
sm: sm,
extIface: extIface,
}
return &be, nil
}

func get_vm_metadata(url string) (string, error) {
resp, err := http.Get(url)

if err != nil || resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("get vm region error: %v", err)
}

defer resp.Body.Close()

metadata, _ := ioutil.ReadAll(resp.Body)
return string(metadata), nil
}

func get_vm_region() (string, error) {
url := "http://metadata.tencentyun.com/latest/meta-data/placement/region"
return get_vm_metadata(url)
}

func get_vm_vpcid() (string, error) {
macUrl := "http://metadata.tencentyun.com/latest/meta-data/mac"
mac, err := get_vm_metadata(macUrl)

if err != nil {
return "", fmt.Errorf("get vm mac error: %v", err)
}

vpcUrl := fmt.Sprintf("http://metadata.tencentyun.com/latest/meta-data/network/interfaces/macs/%s/vpc-id", mac)
vpcid, err := get_vm_metadata(vpcUrl)

if err != nil {
return "", fmt.Errorf("get vm vpcid error: %v", err)
}

return vpcid, nil
}

func (be *TencentVpcBackend) RegisterNetwork(ctx context.Context, wg *sync.WaitGroup, config *subnet.Config) (backend.Network, error) {
// 1. Parse our configuration
cfg := struct {
AccessKeyID string
AccessKeySecret string
}{}

if len(config.Backend) > 0 {
if err := json.Unmarshal(config.Backend, &cfg); err != nil {
return nil, fmt.Errorf("error decoding VPC backend config: %v", err)
}
}
log.Infof("Unmarshal Configure : %v\n", cfg)

// 2. Acquire the lease form subnet manager
attrs := subnet.LeaseAttrs{
PublicIP: ip.FromIP(be.extIface.ExtAddr),
}

l, err := be.sm.AcquireLease(ctx, &attrs)
switch err {
case nil:

case context.Canceled, context.DeadlineExceeded:
return nil, err

default:
return nil, fmt.Errorf("failed to acquire lease: %v", err)
}
if cfg.AccessKeyID == "" || cfg.AccessKeySecret == "" {
cfg.AccessKeyID = os.Getenv("ACCESS_KEY_ID")
cfg.AccessKeySecret = os.Getenv("ACCESS_KEY_SECRET")

if cfg.AccessKeyID == "" || cfg.AccessKeySecret == "" {
return nil, fmt.Errorf("ACCESS_KEY_ID and ACCESS_KEY_SECRET must be provided! ")
}
}

region, err := get_vm_region()
if err != nil {
return nil, err
}
vpcid, err := get_vm_vpcid()
if err != nil {
return nil, err
}

c, _ := vpc.NewClientWithSecretId(cfg.AccessKeyID, cfg.AccessKeySecret, region)
request := vpc.NewDescribeRouteTablesRequest()
request.Filters = []*vpc.Filter{
&vpc.Filter{
Name: common.StringPtr("vpc-id"),
Values: common.StringPtrs([]string{vpcid}),
},
}

res, err := c.DescribeRouteTables(request)
if _, ok := err.(*errors.TencentCloudSDKError); ok {
return nil, fmt.Errorf("describe route table error: %v", ok)
}

if err != nil {
return nil, err
}

response := res.Response

if len(response.RouteTableSet) <= 0 {
return nil, fmt.Errorf("No suitable routing table found")
}

routeTable := response.RouteTableSet[0]
exists := false
gatewayType := "NORMAL_CVM"
routeType := "USER"

for _, route := range routeTable.RouteSet {
if *route.DestinationCidrBlock == l.Subnet.String() &&
*route.GatewayId == be.extIface.ExtAddr.String() &&
*route.GatewayType == gatewayType &&
*route.RouteType == routeType {
if *route.Enabled {
exists = true
} else {
delRouteRequest := vpc.NewDeleteRoutesRequest()
delRouteRequest.RouteTableId = routeTable.RouteTableId
delRouteRequest.Routes = []*vpc.Route{
&vpc.Route{
RouteId: route.RouteId,
},
}

_, err := c.DeleteRoutes(delRouteRequest)
if err != nil {
return nil, err
}
}
}
}

if !exists {
createRouteRequest := vpc.NewCreateRoutesRequest()
createRouteRequest.RouteTableId = routeTable.RouteTableId
createRouteRequest.Routes = []*vpc.Route{
&vpc.Route{
DestinationCidrBlock: common.StringPtr(l.Subnet.String()),
GatewayType: &gatewayType,
GatewayId: common.StringPtr(be.extIface.ExtAddr.String()),
Enabled: common.BoolPtr(true),
},
}

_, err := c.CreateRoutes(createRouteRequest)

if err != nil {
return nil, err
}
}

return &backend.SimpleNetwork{
SubnetLease: l,
ExtIface: be.extIface,
}, nil
}
23 changes: 23 additions & 0 deletions backend/tencentvpc/tencentvpc_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2015 flannel 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 tencentvpc

import (
log "k8s.io/klog"
)

func init() {
log.Infof("TencentVpc is not supported on this platform")
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/stretchr/testify v1.6.1 // indirect
github.com/tencentcloud/tencentcloud-sdk-go v1.0.67
github.com/ugorji/go v0.0.0-20170107133203-ded73eae5db7 // indirect
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf
github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tencentcloud/tencentcloud-sdk-go v1.0.67 h1:fKSwJ7hrvHTxr33EcmrbKcavYJ/U2zNIH8Lvsj2FNTE=
github.com/tencentcloud/tencentcloud-sdk-go v1.0.67/go.mod h1:asUz5BPXxgoPGaRgZaVm1iGcUAuHyYUo1nXqKa83cvI=
github.com/ugorji/go v0.0.0-20170107133203-ded73eae5db7 h1:BPPUhSq7uU6E9lFzyb81vjwVOhiWwMXp0EpKL75NX+8=
github.com/ugorji/go v0.0.0-20170107133203-ded73eae5db7/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf h1:3J37+NPjNyGW/dbfXtj3yWuF9OEepIdGOXRaJGbORV8=
Expand Down
3 changes: 2 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import (
"github.com/joho/godotenv"

// Backends need to be imported for their init() to get executed and them to register
"github.com/coreos/go-systemd/daemon"
"github.com/flannel-io/flannel/backend"
_ "github.com/flannel-io/flannel/backend/alivpc"
_ "github.com/flannel-io/flannel/backend/alloc"
Expand All @@ -53,9 +54,9 @@ import (
_ "github.com/flannel-io/flannel/backend/hostgw"
_ "github.com/flannel-io/flannel/backend/ipip"
_ "github.com/flannel-io/flannel/backend/ipsec"
_ "github.com/flannel-io/flannel/backend/tencentvpc"
_ "github.com/flannel-io/flannel/backend/udp"
_ "github.com/flannel-io/flannel/backend/vxlan"
"github.com/coreos/go-systemd/daemon"
)

type flagSlice []string
Expand Down
2 changes: 1 addition & 1 deletion network/iptables.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ import (
"strings"
"time"

"github.com/coreos/go-iptables/iptables"
"github.com/flannel-io/flannel/pkg/ip"
"github.com/flannel-io/flannel/subnet"
"github.com/coreos/go-iptables/iptables"
log "k8s.io/klog"
)

Expand Down

0 comments on commit fdef594

Please sign in to comment.