forked from tfukushima/mm-ctl
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add the initial binding/unbinding capability
This patch adds the basic binding and unbinding capability for MidoNet BEFORE v5. Signed-off-by: Taku Fukushima <tfukushima@midokura.com>
- Loading branch information
Taku Fukushima
committed
Nov 16, 2015
1 parent
1f38771
commit 1d5dbe5
Showing
7 changed files
with
556 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
// Copyright 2015 Midokura SARL | ||
// | ||
// 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 main | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"flag" | ||
"fmt" | ||
"log" | ||
"os" | ||
"strings" | ||
"time" | ||
|
||
"github.com/samuel/go-zookeeper/zk" | ||
) | ||
|
||
// The address of the NSDB. | ||
var nsdbAddresses = flag.String("zookeeper_hosts", "127.0.0.1:2181", | ||
"The Addresses of ZooKeeper nodes separated by commas") | ||
|
||
// The timout for the NSDB session in seconds. | ||
const sessionTimeoutSec = 10 | ||
|
||
// The key for the ZOOM topology lock path. | ||
const lockKey = "zoom-topology" | ||
|
||
func connect() (*zk.Conn, <-chan zk.Event, error) { | ||
addresses := strings.Split(*nsdbAddresses, ",") | ||
for i := range addresses { | ||
addresses[i] = strings.TrimSpace(addresses[i]) | ||
} | ||
return zk.Connect(addresses, | ||
time.Duration(sessionTimeoutSec)*time.Second) | ||
} | ||
|
||
func binding(portUuid, hostUuid, interfaceName string) error { | ||
log.Println("binding port " + portUuid + " to " + interfaceName) | ||
|
||
conn, _, err := connect() | ||
if err != nil { | ||
return err | ||
} | ||
defer conn.Close() | ||
|
||
lock := zk.NewLock(conn, GetLockPath(lockKey), zk.WorldACL(zk.PermAll)) | ||
if err = lock.Lock(); err != nil { | ||
return err | ||
} | ||
defer lock.Unlock() | ||
|
||
portPath := GetPortPath(portUuid) | ||
var data []byte | ||
if data, _, err = conn.Get(portPath); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on getting port: %s\n", err.Error()) | ||
return err | ||
} | ||
port := &WrappedPort{} | ||
if err = json.Unmarshal(data, port); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on deserializing port: %s\n", err.Error()) | ||
return err | ||
} | ||
|
||
port.Data.HostId = hostUuid | ||
port.Data.InterfaceName = interfaceName | ||
|
||
updatedPort, err := json.Marshal(port) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on serializing port: %s\n", err.Error()) | ||
return err | ||
} | ||
|
||
if _, err = conn.Set(portPath, updatedPort, -1); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on setting port: %s\n", err.Error()) | ||
return err | ||
} | ||
|
||
vrnMappingPath := GetVrnMappingPath(hostUuid, portUuid) | ||
var exists bool | ||
if exists, _, err = conn.Exists(vrnMappingPath); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on examining vrnMapping %s\n", err.Error()) | ||
return err | ||
} | ||
var vrnMappingData []byte | ||
vrnMapping := &WrappedVrnMapping{} | ||
if exists { | ||
if vrnMappingData, _, err = conn.Get(vrnMappingPath); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on getting vrnMapping %s\n", err.Error()) | ||
return err | ||
} | ||
log.Println(fmt.Sprintf("Got vrnMapping data: %s", vrnMappingData)) | ||
if err = json.Unmarshal(vrnMappingData, vrnMapping); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on deserializing vrnMapping: %s\n", err.Error()) | ||
return err | ||
} | ||
} else { | ||
data := &VrnMapping{} | ||
data.VirtualPortId = portUuid | ||
data.LocalDeviceName = interfaceName | ||
vrnMapping.Data = data | ||
vrnMapping.Version = port.Version | ||
} | ||
updatedVrnMapping, err := json.Marshal(vrnMapping) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on deserializing vrnMapping: %s\n", err.Error()) | ||
return err | ||
} | ||
if exists { | ||
if _, err = conn.Set(vrnMappingPath, updatedVrnMapping, -1); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on setting vrnMapping: %s\n", err.Error()) | ||
return err | ||
} | ||
} else { | ||
if _, err = conn.Create(vrnMappingPath, updatedVrnMapping, 0, zk.WorldACL(zk.PermAll)); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on creating a new vrnMapping: %s\n", err.Error()) | ||
return err | ||
} | ||
} | ||
|
||
log.Println("Succeded to bind the port") | ||
|
||
return nil | ||
} | ||
|
||
func unbinding(portUuid, hostUuid string) error { | ||
log.Println("unbinding port " + portUuid) | ||
|
||
conn, _, err := connect() | ||
if err != nil { | ||
return err | ||
} | ||
defer conn.Close() | ||
|
||
lock := zk.NewLock(conn, GetLockPath(lockKey), zk.WorldACL(zk.PermAll)) | ||
if err = lock.Lock(); err != nil { | ||
return err | ||
} | ||
defer lock.Unlock() | ||
|
||
portPath := GetPortPath(portUuid) | ||
var data []byte | ||
if data, _, err = conn.Get(portPath); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on getting port: %s\n", err.Error()) | ||
return err | ||
} | ||
port := &WrappedPort{} | ||
if err = json.Unmarshal(data, port); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on deserializing port: %s\n", err.Error()) | ||
return err | ||
} | ||
|
||
if port.Data.HostId != hostUuid { | ||
return errors.New("The given host ID didn't match with one in NSDB") | ||
} | ||
port.Data.InterfaceName = "" | ||
|
||
updatedPort, err := json.Marshal(port) | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on serializing port: %s\n", err.Error()) | ||
return err | ||
} | ||
|
||
if _, err = conn.Set(portPath, updatedPort, -1); err != nil { | ||
return err | ||
} | ||
|
||
vrnMappingPath := GetVrnMappingPath(hostUuid, portUuid) | ||
var exists bool | ||
if exists, _, err = conn.Exists(vrnMappingPath); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on examining vrnMapping %s\n", err.Error()) | ||
return err | ||
} | ||
if exists { | ||
if err = conn.Delete(vrnMappingPath, -1); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on deleging vrnMapping %s\n", err.Error()) | ||
return err | ||
} | ||
} | ||
log.Println("Succeded to unbind the port") | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
// Copyright 2015 Midokura SARL | ||
// | ||
// 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 main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/mitchellh/cli" | ||
ini "gopkg.in/ini.v1" | ||
) | ||
|
||
// const HostUuid = "b53b82f3-ebe5-4e8d-9088-8b3ae4ade76e"w | ||
var hostUuid = flag.String("host_uuid", "", "The UUID of the host (required).") | ||
|
||
// the name of the command. | ||
const CommandName = "mm-ctl" | ||
|
||
func loadConfig() error { | ||
midolmanConfigPath := flag.String("config", "/etc/midolman/midolman.conf", | ||
"The location of the Midolamn config file") | ||
hostConfigPath := flag.String("host-config", "/etc/midonet_host_id.properties", | ||
"The location of the host UUID config file") | ||
flag.Parse() | ||
|
||
cfg, err := ini.Load(*midolmanConfigPath, *hostConfigPath) | ||
if err != nil { | ||
return err | ||
} | ||
zkSection, err := cfg.GetSection("zookeeper") | ||
if err != nil { | ||
return err | ||
} | ||
*rootPath = zkSection.Key("root_key").String() | ||
*nsdbAddresses = zkSection.Key("zookeeper_hosts").String() | ||
*hostUuid = cfg.Section("").Key("host_uuid").String() | ||
|
||
return nil | ||
} | ||
|
||
// The "binding" command. | ||
type Binding struct{} | ||
|
||
func (b *Binding) Help() string { | ||
return fmt.Sprintf(`Usage: %s bind c5951b28-0d72-41fa-9f29-650bbeae2ed3 8a1c0540-veth" | ||
binding takes the Neutron port UUID and the interface name and binds the port to | ||
the interface. | ||
`, CommandName) | ||
} | ||
|
||
func (b *Binding) Run(args []string) int { | ||
bindCmdFlag := flag.NewFlagSet("bind", flag.ContinueOnError) | ||
if *hostUuid == "" { | ||
bindCmdFlag.StringVar(hostUuid, "host_uuid", "", "The UUID of the host (required).") | ||
} | ||
// bindCmdFlag.StringVar(nsdbAddresses, "zookeeper_hosts", "127.0.0.1:2181", | ||
// "The Addresses of ZooKeeper nodes separated by commas") | ||
// bindCmdFlag.StringVar(rootPath, "root_key", "/midonet/v1", "The root path of the NSDB") | ||
|
||
bindCmdFlag.Parse(args) | ||
|
||
if bindCmdFlag.NArg() != 2 { | ||
fmt.Fprintf(os.Stderr, "bind takes exactly 2 args but %d args are given.\n", bindCmdFlag.NArg()) | ||
return 1 | ||
} | ||
portUuid := bindCmdFlag.Arg(0) | ||
fmt.Printf("host_uuid: %s\n", *hostUuid) | ||
if *hostUuid == "" { | ||
fmt.Fprintf(os.Stderr, "Host UUID is required.\n") | ||
return 1 | ||
} | ||
interfaceName := bindCmdFlag.Arg(1) | ||
|
||
if err := binding(portUuid, *hostUuid, interfaceName); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on binding the port: %s\n", err.Error()) | ||
return 1 | ||
} | ||
|
||
return 0 | ||
} | ||
|
||
func (b *Binding) Synopsis() string { | ||
return "bind <port-uuid> <interface-name>" | ||
} | ||
|
||
// The "unbinding" command. | ||
type Unbinding struct{} | ||
|
||
func (u *Unbinding) Help() string { | ||
return fmt.Sprintf(`Usage: %s unbind c5951b28-0d72-41fa-9f29-650bbeae2ed3 | ||
unbinding takes the Neutron port UUID and unbinds the port. | ||
`, CommandName) | ||
} | ||
|
||
func (u *Unbinding) Run(args []string) int { | ||
unbindCmdFlag := flag.NewFlagSet("unbind", flag.ContinueOnError) | ||
if *hostUuid == "" { | ||
unbindCmdFlag.StringVar(hostUuid, "host_uuid", "", "The UUID of the host (required).") | ||
} | ||
// unbindCmdFlag.StringVar(nsdbAddresses, "zookeeper_hosts", "127.0.0.1:2181", | ||
// "The Addresses of ZooKeeper nodes separated by commas") | ||
// unbindCmdFlag.StringVar(rootPath, "root_key", "/midonet/v1", "The root path of the NSDB") | ||
|
||
unbindCmdFlag.Parse(args) | ||
|
||
if unbindCmdFlag.NArg() != 1 { | ||
fmt.Fprintf(os.Stderr, "unbind takes exactly 1 arg but %d args are given.\n", unbindCmdFlag.NArg()) | ||
return 1 | ||
} | ||
portUuid := unbindCmdFlag.Arg(0) | ||
|
||
if err := unbinding(portUuid, *hostUuid); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error on unbinding the port: %s\n", err.Error()) | ||
return 1 | ||
} | ||
|
||
return 0 | ||
} | ||
|
||
func (u *Unbinding) Synopsis() string { | ||
return "unbind <port-uuid>" | ||
} | ||
|
||
func bindingCommand() (cli.Command, error) { | ||
return &Binding{}, nil | ||
} | ||
|
||
func unbindingCommand() (cli.Command, error) { | ||
return &Unbinding{}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// Copyright 2015 Midokura SARL | ||
// | ||
// 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 main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/mitchellh/cli" | ||
) | ||
|
||
func runCommand() int { | ||
// iniflags.Parse() | ||
if err := loadConfig(); err != nil { | ||
fmt.Fprintf(os.Stderr, "Failed to load the config files: %s\n", err.Error()) | ||
return 1 | ||
} | ||
|
||
c := cli.NewCLI(CommandName, Version) | ||
c.Args = flag.Args() | ||
|
||
c.Commands = map[string]cli.CommandFactory{ | ||
"bind": bindingCommand, | ||
"unbind": unbindingCommand, | ||
} | ||
exitStatus, err := c.Run() | ||
if err != nil { | ||
fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err.Error()) | ||
return 1 | ||
} | ||
|
||
return exitStatus | ||
} | ||
|
||
func main() { | ||
os.Exit(runCommand()) | ||
} |
Oops, something went wrong.