2017-03-15 22:28:03 +00:00
|
|
|
/*
|
|
|
|
Copyright 2017 The Kubernetes 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 gce
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"path"
|
|
|
|
|
|
|
|
"k8s.io/apimachinery/pkg/types"
|
|
|
|
"k8s.io/kubernetes/pkg/cloudprovider"
|
|
|
|
|
|
|
|
"github.com/golang/glog"
|
|
|
|
compute "google.golang.org/api/compute/v1"
|
|
|
|
)
|
|
|
|
|
2017-04-12 18:57:20 +00:00
|
|
|
func newRoutesMetricContext(request string) *metricContext {
|
2017-08-22 23:13:46 +00:00
|
|
|
return newGenericMetricContext("routes", request, unusedMetricLabel, unusedMetricLabel, computeV1Version)
|
2017-04-12 18:57:20 +00:00
|
|
|
}
|
|
|
|
|
2017-03-15 22:28:03 +00:00
|
|
|
func (gce *GCECloud) ListRoutes(clusterName string) ([]*cloudprovider.Route, error) {
|
|
|
|
var routes []*cloudprovider.Route
|
|
|
|
pageToken := ""
|
|
|
|
page := 0
|
|
|
|
for ; page == 0 || (pageToken != "" && page < maxPages); page++ {
|
2017-05-05 01:04:34 +00:00
|
|
|
mc := newRoutesMetricContext("list_page")
|
2017-08-24 18:06:42 +00:00
|
|
|
listCall := gce.service.Routes.List(gce.NetworkProjectID())
|
2017-03-15 22:28:03 +00:00
|
|
|
|
|
|
|
prefix := truncateClusterName(clusterName)
|
2017-08-17 18:13:34 +00:00
|
|
|
// Filter for routes starting with clustername AND belonging to the
|
|
|
|
// relevant gcp network AND having description = "k8s-node-route".
|
|
|
|
filter := "(name eq " + prefix + "-.*) "
|
2017-08-24 18:06:42 +00:00
|
|
|
filter = filter + "(network eq " + gce.NetworkURL() + ") "
|
2017-08-17 18:13:34 +00:00
|
|
|
filter = filter + "(description eq " + k8sNodeRouteTag + ")"
|
|
|
|
listCall = listCall.Filter(filter)
|
2017-03-15 22:28:03 +00:00
|
|
|
if pageToken != "" {
|
|
|
|
listCall = listCall.PageToken(pageToken)
|
|
|
|
}
|
|
|
|
res, err := listCall.Do()
|
2017-05-05 01:04:34 +00:00
|
|
|
mc.Observe(err)
|
2017-03-15 22:28:03 +00:00
|
|
|
if err != nil {
|
|
|
|
glog.Errorf("Error getting routes from GCE: %v", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
pageToken = res.NextPageToken
|
|
|
|
for _, r := range res.Items {
|
|
|
|
target := path.Base(r.NextHopInstance)
|
|
|
|
// TODO: Should we lastComponent(target) this?
|
|
|
|
targetNodeName := types.NodeName(target) // NodeName == Instance Name on GCE
|
|
|
|
routes = append(routes, &cloudprovider.Route{Name: r.Name, TargetNode: targetNodeName, DestinationCIDR: r.DestRange})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if page >= maxPages {
|
|
|
|
glog.Errorf("ListRoutes exceeded maxPages=%d for Routes.List; truncating.", maxPages)
|
|
|
|
}
|
|
|
|
return routes, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (gce *GCECloud) CreateRoute(clusterName string, nameHint string, route *cloudprovider.Route) error {
|
|
|
|
routeName := truncateClusterName(clusterName) + "-" + nameHint
|
|
|
|
|
|
|
|
instanceName := mapNodeNameToInstanceName(route.TargetNode)
|
|
|
|
targetInstance, err := gce.getInstanceByName(instanceName)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-04-12 18:57:20 +00:00
|
|
|
|
|
|
|
mc := newRoutesMetricContext("create")
|
2017-08-24 18:06:42 +00:00
|
|
|
insertOp, err := gce.service.Routes.Insert(gce.NetworkProjectID(), &compute.Route{
|
2017-03-15 22:28:03 +00:00
|
|
|
Name: routeName,
|
|
|
|
DestRange: route.DestinationCIDR,
|
|
|
|
NextHopInstance: fmt.Sprintf("zones/%s/instances/%s", targetInstance.Zone, targetInstance.Name),
|
2017-08-24 18:06:42 +00:00
|
|
|
Network: gce.NetworkURL(),
|
2017-03-15 22:28:03 +00:00
|
|
|
Priority: 1000,
|
|
|
|
Description: k8sNodeRouteTag,
|
|
|
|
}).Do()
|
|
|
|
if err != nil {
|
|
|
|
if isHTTPErrorCode(err, http.StatusConflict) {
|
2017-06-21 08:10:06 +00:00
|
|
|
glog.Infof("Route %v already exists.", routeName)
|
2017-03-15 22:28:03 +00:00
|
|
|
return nil
|
|
|
|
} else {
|
2017-04-12 18:57:20 +00:00
|
|
|
return mc.Observe(err)
|
2017-03-15 22:28:03 +00:00
|
|
|
}
|
|
|
|
}
|
2017-08-24 18:06:42 +00:00
|
|
|
return gce.waitForGlobalOpInProject(insertOp, gce.NetworkProjectID(), mc)
|
2017-03-15 22:28:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (gce *GCECloud) DeleteRoute(clusterName string, route *cloudprovider.Route) error {
|
2017-05-05 01:04:34 +00:00
|
|
|
mc := newRoutesMetricContext("delete")
|
2017-08-24 18:06:42 +00:00
|
|
|
deleteOp, err := gce.service.Routes.Delete(gce.NetworkProjectID(), route.Name).Do()
|
2017-03-15 22:28:03 +00:00
|
|
|
if err != nil {
|
2017-04-12 18:57:20 +00:00
|
|
|
return mc.Observe(err)
|
2017-03-15 22:28:03 +00:00
|
|
|
}
|
2017-08-24 18:06:42 +00:00
|
|
|
return gce.waitForGlobalOpInProject(deleteOp, gce.NetworkProjectID(), mc)
|
2017-03-15 22:28:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func truncateClusterName(clusterName string) string {
|
|
|
|
if len(clusterName) > 26 {
|
|
|
|
return clusterName[:26]
|
|
|
|
}
|
|
|
|
return clusterName
|
|
|
|
}
|