Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

golang based watcher for ovn-kubernetes #110

Merged
merged 5 commits into from
Apr 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions go-controller/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_output
17 changes: 17 additions & 0 deletions go-controller/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

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/

install:
cp ${OUT_DIR}/go/bin/* /usr/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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hack/build-go.sh seems satisfied with 1.6. I suppose that needs a change.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a reason, but now I cannot recall it.
Will fix if I cannot recollect soon.


```
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.
111 changes: 111 additions & 0 deletions go-controller/cmd/ovnkube/ovnkube.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
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")
}

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

// CreateConfig creates the restclient.Config object from token, ca file and the apiserver
// (similar to what is obtainable from kubeconfig file)
func CreateConfig(server, token, rootCAFile string) (*restclient.Config, error) {
tlsClientConfig := restclient.TLSClientConfig{}
if rootCAFile != "" {
if _, err := certutil.NewPool(rootCAFile); err != nil {
return nil, err
}
tlsClientConfig.CAFile = rootCAFile
}

return &restclient.Config{
Host: server,
BearerToken: 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


Loading