Skip to content

Commit

Permalink
golang based watcher for ovn-kubernetes
Browse files Browse the repository at this point in the history
  • Loading branch information
Rajat Chopra committed Apr 10, 2017
1 parent 8575743 commit 7a86535
Show file tree
Hide file tree
Showing 1,309 changed files with 604,028 additions and 0 deletions.
1 change: 1 addition & 0 deletions go-controller/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_output
14 changes: 14 additions & 0 deletions go-controller/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

OUT_DIR = _output
export OUT_DIR

# Example:
# make
# make all
all build:
hack/build-go.sh cmd/ovnkube/ovnkube.go
cp -f pkg/cluster/bin/ovnkube-setup-* ${OUT_DIR}/go/bin/

clean:
rm -rf ${OUT_DIR}
.PHONY: all build
83 changes: 83 additions & 0 deletions go-controller/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# ovn kubernetes go-controller

The golang based ovn controller is a reliable way to deploy the OVN SDN using kubernetes clients and watchers based on golang.

### Build

Ensure go version >= 1.8

```
cd go-controller
make clean
make
```

Then find the executable here : go-controller/_output/go/bin/ovnkube

'ovnkube' is the single all-in-one executable useful for deploying the ovn cni plugin for a kubernetes deployment

### Usage

Run the 'ovnkube' executable to initialize master, node(s) and as the central all-in-one controller that builds the network as pods/services/ingress objects are born in kubernetes.

```
Usage:
-alsologtostderr
log to standard error as well as files
-apiserver string
url to the kubernetes apiserver (default "https://localhost:8443")
-ca-cert string
CA cert for the api server
-cluster-subnet string
Cluster wide IP subnet to use (default "11.11.0.0/16")
-init-master string
initialize master, requires the hostname as argument
-init-node string
initialize node, requires the name that node is registered with in kubernetes cluster
-log_backtrace_at value
when logging hits line file:N, emit a stack trace
-log_dir string
If non-empty, write log files in this directory
-logtostderr
log to standard error instead of files
-net-controller
Flag to start the central controller that watches pods/services/policies
-stderrthreshold value
logs at or above this threshold go to stderr
-token string
Bearer token to use for establishing ovn infrastructure
-v value
log level for V logs
-vmodule value
comma-separated list of pattern=N settings for file-filtered logging
```

## Example

#### Initialize the master and run the main controller

```
ovnkube --init-master <master-host-name> \
--ca-cert <path to the cacert file> \
--token <token string for authentication with kube apiserver> \
--apiserver <url to the kube apiserver e.g. https://10.11.12.13.8443> \
--cluster-subnet <cidr representing the global pod network e.g. 192.168.0.0/16> \
--net-controller
```

With the above the master ovnkube controller will initialize the central master logical router and establish the watcher loops for the following:
- nodes: as new nodes are born and init-node is called, the logical switches will be created automatically by giving out IPAM for the respective nodes
- pods: as new pods are born, allocate the logical port with dynamic addressing from the switch it belongs to
- services/endpoints: as new endpoints of services are born, create/update the logical load balancer on all logical switches


#### Initialize a newly added node for the OVN network

```
ovnkube --init-node <name of the node as identified in kubernetes> \
--ca-cert <path to the cacert file> \
--token <token string for authentication with kube apiserver> \
--apiserver <url to the kube apiserver e.g. https://10.11.12.13.8443>
```

With the above command, the node will get initialized for all OVN communication and a logical switch will be created for it.
105 changes: 105 additions & 0 deletions go-controller/cmd/ovnkube/ovnkube.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package main

import (
"flag"
"fmt"
"net"
"strings"

"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
certutil "k8s.io/client-go/util/cert"

ovnfactory "github.com/openvswitch/ovn-kubernetes/go-controller/pkg/factory"
)

func main() {
// auth flags
kubeconfig := flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
server := flag.String("apiserver", "https://localhost:8443", "url to the kubernetes apiserver")
rootCAFile := flag.String("ca-cert", "", "CA cert for the api server")
token := flag.String("token", "", "Bearer token to use for establishing ovn infrastructure")
clusterSubnet := flag.String("cluster-subnet", "11.11.0.0/16", "Cluster wide IP subnet to use")

// mode flags
netController := flag.Bool("net-controller", false, "Flag to start the central controller that watches pods/services/policies")
master := flag.String("init-master", "", "initialize master, requires the hostname as argument")
node := flag.String("init-node", "", "initialize node, requires the name that node is registered with in kubernetes cluster")

flag.Parse()

// Process auth flags
var config *restclient.Config
var err error
if *kubeconfig != "" {
// uses the current context in kubeconfig
config, err = clientcmd.BuildConfigFromFlags("", *kubeconfig)
} else if *server != "" && *token != "" && ((*rootCAFile != "") || !strings.HasPrefix(*server, "https")) {
config, err = CreateConfig(*server, *token, *rootCAFile)
} else {
err = fmt.Errorf("Provide kubeconfig file or give server/token/tls credentials")
}
if err != nil {
panic(err.Error())
}

// creates the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}

// create factory and start the controllers asked for
factory := ovnfactory.NewDefaultFactory(clientset)
clusterController := factory.CreateClusterController()

if *master != "" || *node != "" {
clusterController.KubeServer = *server
clusterController.CACert = *rootCAFile
clusterController.Token = *token
clusterController.HostSubnetLength = 8
_, clusterController.ClusterIPNet, err = net.ParseCIDR(*clusterSubnet)
if err != nil {
panic(err.Error)
}
}
ovnController := factory.CreateOvnController()

if *node != "" {
if *token == "" {
panic("Cannot initialize node without service account 'token'. Please provide one with --token argument")
return
}

clusterController.StartClusterNode(*node)
}
if *master != "" {
// run the cluster controller to init the master
clusterController.StartClusterMaster(*master)
}
if *netController {
ovnController.Run()
}
if *master != "" || *netController {
// run forever
select {}
}
}

func CreateConfig(server, token, rootCAFile string) (*restclient.Config, error) {
tlsClientConfig := restclient.TLSClientConfig{}
if rootCAFile != "" {
if _, err := certutil.NewPool(rootCAFile); err != nil {
return nil, err
} else {
tlsClientConfig.CAFile = rootCAFile
}
}

return &restclient.Config{
Host: server,
BearerToken: string(token),
TLSClientConfig: tlsClientConfig,
}, nil
}
96 changes: 96 additions & 0 deletions go-controller/hack/build-go.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/bin/bash

source "$(dirname "${BASH_SOURCE}")/init.sh"

OUT_DIR=${OUT_DIR:-_output}

init_source="$( dirname "${BASH_SOURCE}" )/.."
OVN_KUBE_ROOT="$( os::util::absolute_path "${init_source}" )"
export OVN_KUBE_ROOT
cd ${OVN_KUBE_ROOT}
OVN_KUBE_GO_PACKAGE="github.com/openvswitch/ovn-kubernetes/go-controller"
OVN_KUBE_OUTPUT=${OVN_KUBE_ROOT}/${OUT_DIR}

# Output Vars:
# export GOPATH - A modified GOPATH to our created tree along with extra
# stuff.
# export GOBIN - This is actively unset if already set as we want binaries
# placed in a predictable place.
function setup_env() {
if [[ -z "$(which go)" ]]; then
cat <<EOF
Can't find 'go' in PATH, please fix and retry.
See http://golang.org/doc/install for installation instructions.
EOF
exit 2
fi

# Travis continuous build uses a head go release that doesn't report
# a version number, so we skip this check on Travis. It's unnecessary
# there anyway.
if [[ "${TRAVIS:-}" != "true" ]]; then
local go_version
go_version=($(go version))
if [[ "${go_version[2]}" < "go1.5" ]]; then
cat <<EOF
Detected Go version: ${go_version[*]}.
ovn-kube builds require Go version 1.6 or greater.
EOF
exit 2
fi
fi

unset GOBIN

# create a local GOPATH in _output
GOPATH="${OVN_KUBE_OUTPUT}/go"
OVN_KUBE_OUTPUT_BINPATH=${GOPATH}/bin
local go_pkg_dir="${GOPATH}/src/${OVN_KUBE_GO_PACKAGE}"
local go_pkg_basedir=$(dirname "${go_pkg_dir}")

mkdir -p "${go_pkg_basedir}"
rm -f "${go_pkg_dir}"

# TODO: This symlink should be relative.
ln -s "${OVN_KUBE_ROOT}" "${go_pkg_dir}"

# lots of tools "just don't work" unless we're in the GOPATH
cd "${go_pkg_dir}"

export GOPATH
}
readonly -f setup_env

# Build binary targets specified. Should always be run in a sub-shell so we don't leak GOBIN
#
# Input:
# $@ - targets and go flags. If no targets are set then all binaries targets
# are built.
build_binaries() {
# Check for `go` binary and set ${GOPATH}.
setup_env

mkdir -p "${OVN_KUBE_OUTPUT_BINPATH}"
export GOBIN="${OVN_KUBE_OUTPUT_BINPATH}"

go install "${OVN_KUBE_BINARIES[@]}"
}

test() {
for test in "${tests[@]:+${tests[@]}}"; do
local outfile="${OVN_KUBE_OUTPUT_BINPATH}/${platform}/$(basename ${test})"
# disabling cgo allows use of delve
CGO_ENABLED=0 go test \
-i -c -o "${outfile}" \
"${goflags[@]:+${goflags[@]}}" \
"$(dirname ${test})"
done
}

OVN_KUBE_BINARIES=("$@")
build_binaries

32 changes: 32 additions & 0 deletions go-controller/hack/init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/bash


# os::build::binaries_from_targets take a list of build targets and return the
# full go package to be built
function os::build::binaries_from_targets() {
local target
for target; do
echo "${OS_GO_PACKAGE}/${target}"
done
}
readonly -f os::build::binaries_from_targets

# os::util::absolute_path returns the absolute path to the directory provided
function os::util::absolute_path() {
local relative_path="$1"
local absolute_path

pushd "${relative_path}" >/dev/null
relative_path="$( pwd )"
if [[ -h "${relative_path}" ]]; then
absolute_path="$( readlink "${relative_path}" )"
else
absolute_path="${relative_path}"
fi
popd >/dev/null

echo "${absolute_path}"
}
readonly -f os::util::absolute_path


48 changes: 48 additions & 0 deletions go-controller/pkg/cluster/bin/ovnkube-setup-master
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash

# Fixed argument set

API_TOKEN=$1
K8S_API_SERVER_IP=${2-https://localhost:8443}
MASTER_SWITCH_SUBNET=${3-11.11.1.0/24}
CLUSTER_IP_SUBNET=${4-11.11.0.0/16}
hostname=`hostname`
NODE_NAME=${5-$hostname}

if [[ "${API_TOKEN}" == "" ]]; then
echo "Supply kube access secret as the argument"
exit 1
fi

install() {
# Add a repo for where we can get OVS 2.6 packages
if [ ! -f /etc/yum.repos.d/delorean-deps.repo ] ; then
curl http://trunk.rdoproject.org/centos7/delorean-deps.repo | sudo tee /etc/yum.repos.d/delorean-deps.repo
fi
sudo yum install -y openvswitch openvswitch-ovn-central openvswitch-ovn-host
}

init() {
systemctl start openvswitch
systemctl start ovn-northd
}

ovnsetup() {
ovs-vsctl set Open_vSwitch . \
external_ids:k8s-api-server="${K8S_API_SERVER_IP}" \
external_ids:k8s-api-token="${API_TOKEN}"

echo "ovn-k8s-overlay master-init \
--cluster-ip-subnet=${CLUSTER_IP_SUBNET} \
--master-switch-subnet=${MASTER_SWITCH_SUBNET}\
--node-name=${NODE_NAME}"

ovn-k8s-overlay master-init \
--cluster-ip-subnet=${CLUSTER_IP_SUBNET} \
--master-switch-subnet="${MASTER_SWITCH_SUBNET}" \
--node-name="${NODE_NAME}"
}

install
init
ovnsetup
Loading

0 comments on commit 7a86535

Please sign in to comment.