diff --git a/app_cluster.go b/app_cluster.go index 76b25e3..87243d6 100644 --- a/app_cluster.go +++ b/app_cluster.go @@ -53,6 +53,7 @@ type ClusterState struct { } NextIndex uint64 MatchIndex uint64 + ElectionTimer uint64 NotCommittedEntries uint64 NotAppliedEntries uint64 Peers map[string]*ClusterPeer @@ -216,6 +217,12 @@ func (cli *OvnClient) GetAppClusteringInfo(db string) (ClusterState, error) { if i, err := strconv.ParseUint(s, 10, 64); err == nil { server.NotAppliedEntries = i } + } else if strings.HasPrefix(line, "Election timer:") { + s := strings.TrimLeft(line, "Election timer:") + s = strings.Join(strings.Fields(s), " ") + if i, err := strconv.ParseUint(s, 10, 64); err == nil { + server.ElectionTimer = i + } } else if strings.HasPrefix(line, "Connections:") { s := strings.TrimLeft(line, "Connections:") s = strings.Join(strings.Fields(s), " ") diff --git a/ovn_acl.go b/ovn_acl.go index 877040f..3dc826f 100644 --- a/ovn_acl.go +++ b/ovn_acl.go @@ -22,14 +22,13 @@ import ( // OvnACL holds ACL information. type OvnACL struct { UUID string `json:"uuid" yaml:"uuid"` - ExternalIDs map[string]string } // GetACL returns a list of OVN ACLs. func (cli *OvnClient) GetACL() ([]*OvnACL, error) { acls := []*OvnACL{} // First, get basic information about OVN logical switches. - query := "SELECT _uuid, external_ids FROM ACL" + query := "SELECT _uuid FROM ACL" result, err := cli.Database.Northbound.Client.Transact(cli.Database.Northbound.Name, query) if err != nil { return nil, fmt.Errorf("%s: '%s' table error: %s", cli.Database.Northbound.Name, "ACL", err) @@ -47,13 +46,6 @@ func (cli *OvnClient) GetACL() ([]*OvnACL, error) { } acl.UUID = r.(string) } - if r, dt, err := row.GetColumnValue("external_ids", result.Columns); err != nil { - acl.ExternalIDs = make(map[string]string) - } else { - if dt == "map[string]string" { - acl.ExternalIDs = r.(map[string]string) - } - } acls = append(acls, acl) } return acls, nil diff --git a/ovn_chassis.go b/ovn_chassis.go index 4d7ecca..b6fbdbb 100644 --- a/ovn_chassis.go +++ b/ovn_chassis.go @@ -23,21 +23,24 @@ import ( type OvnChassis struct { UUID string Name string + HostName string IPAddress net.IP Encaps struct { UUID string Proto string } - Up int - Ports []string - Switches []string + NB_CFG int64 + NB_CFG_Timestamp int64 + Up int + Ports []string + Switches []string } // GetChassis returns a list of OVN chassis. func (cli *OvnClient) GetChassis() ([]*OvnChassis, error) { chassis := []*OvnChassis{} // First, get the names and UUIDs of chassis. - query := "SELECT _uuid, name, encaps FROM Chassis" + query := "SELECT _uuid, name, encaps, hostname FROM Chassis" result, err := cli.Database.Southbound.Client.Transact(cli.Database.Southbound.Name, query) if err != nil { return nil, fmt.Errorf("%s: '%s' table error: %s", cli.Database.Southbound.Name, "Chassis", err) @@ -65,6 +68,14 @@ func (cli *OvnClient) GetChassis() ([]*OvnChassis, error) { } c.Name = r.(string) } + if r, dt, err := row.GetColumnValue("hostname", result.Columns); err != nil { + continue + } else { + if dt != "string" { + continue + } + c.HostName = r.(string) + } if r, dt, err := row.GetColumnValue("encaps", result.Columns); err != nil { continue } else { @@ -134,6 +145,62 @@ func (cli *OvnClient) GetChassis() ([]*OvnChassis, error) { break } } + + // Third, get the nb_cfg of the chassis + query = "SELECT _uuid, name, nb_cfg, nb_cfg_timestamp FROM Chassis_Private" + result, err = cli.Database.Southbound.Client.Transact(cli.Database.Southbound.Name, query) + if err != nil { + return nil, fmt.Errorf("%s: '%s' table error: %s", cli.Database.Southbound.Name, "Chassis_Private", err) + } + if len(result.Rows) == 0 { + return nil, fmt.Errorf("%s: no chassis found", cli.Database.Southbound.Name) + } + for _, row := range result.Rows { + // var privateUUID string + var privateName string + var privateNBCFG int64 + var privateNBCFGTimestamp int64 + // if r, dt, err := row.GetColumnValue("_uuid", result.Columns); err != nil { + // continue + // } else { + // if dt != "string" { + // continue + // } + // privateUUID = r.(string) + // } + if r, dt, err := row.GetColumnValue("name", result.Columns); err != nil { + continue + } else { + if dt != "string" { + continue + } + privateName = r.(string) + } + if r, dt, err := row.GetColumnValue("nb_cfg", result.Columns); err != nil { + continue + } else { + if dt != "int64" { + // continue + } + privateNBCFG = r.(int64) + } + if r, dt, err := row.GetColumnValue("nb_cfg_timestamp", result.Columns); err != nil { + continue + } else { + if dt != "int64" { + // continue + } + privateNBCFGTimestamp = r.(int64) + } + for _, c := range chassis { + if c.Name != privateName { + continue + } + c.NB_CFG = privateNBCFG + c.NB_CFG_Timestamp = privateNBCFGTimestamp + break + } + } return chassis, nil } diff --git a/ovn_lflow.go b/ovn_lflow.go new file mode 100644 index 0000000..3c124cb --- /dev/null +++ b/ovn_lflow.go @@ -0,0 +1,51 @@ +// Copyright 2018 Paul Greenberg (greenpau@outlook.com) +// +// 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 ovsdb + +import ( + "fmt" + //"github.com/davecgh/go-spew/spew" +) + +// OvnLFlow holds Logical_Flow information. +type OvnLFlow struct { + UUID string `json:"uuid" yaml:"uuid"` +} + +// GetLFlow returns a list of OVN LFlows. +func (cli *OvnClient) GetLFlow() ([]*OvnLFlow, error) { + lflows := []*OvnLFlow{} + query := "SELECT _uuid FROM Logical_Flow" + result, err := cli.Database.Southbound.Client.Transact(cli.Database.Southbound.Name, query) + if err != nil { + return nil, fmt.Errorf("%s: '%s' table error: %s", cli.Database.Southbound.Name, "Logical_Flow", err) + } + if len(result.Rows) == 0 { + return nil, fmt.Errorf("%s: no lflow found", cli.Database.Southbound.Name) + } + for _, row := range result.Rows { + lflow := &OvnLFlow{} + if r, dt, err := row.GetColumnValue("_uuid", result.Columns); err != nil { + continue + } else { + if dt != "string" { + continue + } + lflow.UUID = r.(string) + } + lflows = append(lflows, lflow) + } + return lflows, nil +} diff --git a/ovn_nb_global.go b/ovn_nb_global.go new file mode 100644 index 0000000..40693c6 --- /dev/null +++ b/ovn_nb_global.go @@ -0,0 +1,115 @@ +// Copyright 2018 Paul Greenberg (greenpau@outlook.com) +// +// 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 ovsdb + +import ( + "fmt" + //"github.com/davecgh/go-spew/spew" +) + +// OvnACL holds ACL information. +type OvnNBGlobal struct { + UUID string `json:"uuid" yaml:"uuid"` + ExternalIDs map[string]string + HV_CFG int64 + HV_CFG_Timestamp int64 + NB_CFG int64 + NB_CFG_Timestamp int64 + Options map[string]string + SB_CFG int64 + SB_CFG_Timestamp int64 +} + +// GetACL returns a list of OVN ACLs. +func (cli *OvnClient) GetNBGlobal() (*OvnNBGlobal, error) { + nbglobal := &OvnNBGlobal{} + // First, get basic information about OVN logical switches. + query := "SELECT _uuid,external_ids,hv_cfg,hv_cfg_timestamp,nb_cfg,nb_cfg_timestamp,options,sb_cfg,sb_cfg_timestamp FROM NB_Global" + result, err := cli.Database.Northbound.Client.Transact(cli.Database.Northbound.Name, query) + if err != nil { + return nil, fmt.Errorf("%s: '%s' table error: %s", cli.Database.Northbound.Name, "NB_Global", err) + } + if len(result.Rows) == 0 { + return nil, fmt.Errorf("%s: nb global is empty!", cli.Database.Northbound.Name) + } + if len(result.Rows) > 1 { + return nil, fmt.Errorf("%s: nb global has more than 1 Rows!", cli.Database.Northbound.Name) + } + for _, row := range result.Rows { + if r, dt, err := row.GetColumnValue("nb_cfg", result.Columns); err != nil { + continue + } else { + if dt != "int64" { + // continue + } + nbglobal.NB_CFG = r.(int64) + } + if r, dt, err := row.GetColumnValue("nb_cfg_timestamp", result.Columns); err != nil { + continue + } else { + if dt != "int64" { + // continue + } + nbglobal.NB_CFG_Timestamp = r.(int64) + } + if r, dt, err := row.GetColumnValue("hv_cfg", result.Columns); err != nil { + continue + } else { + if dt != "int64" { + // continue + } + nbglobal.HV_CFG = r.(int64) + } + if r, dt, err := row.GetColumnValue("hv_cfg_timestamp", result.Columns); err != nil { + continue + } else { + if dt != "int64" { + // continue + } + nbglobal.HV_CFG_Timestamp = r.(int64) + } + if r, dt, err := row.GetColumnValue("sb_cfg", result.Columns); err != nil { + continue + } else { + if dt != "int64" { + // continue + } + nbglobal.SB_CFG = r.(int64) + } + if r, dt, err := row.GetColumnValue("sb_cfg_timestamp", result.Columns); err != nil { + continue + } else { + if dt != "int64" { + // continue + } + nbglobal.SB_CFG_Timestamp = r.(int64) + } + if r, dt, err := row.GetColumnValue("external_ids", result.Columns); err != nil { + nbglobal.ExternalIDs = make(map[string]string) + } else { + if dt == "map[string]string" { + nbglobal.ExternalIDs = r.(map[string]string) + } + } + if r, dt, err := row.GetColumnValue("options", result.Columns); err != nil { + nbglobal.Options = make(map[string]string) + } else { + if dt == "map[string]string" { + nbglobal.Options = r.(map[string]string) + } + } + } + return nbglobal, nil +} diff --git a/ovn_sb_global.go b/ovn_sb_global.go new file mode 100644 index 0000000..df79365 --- /dev/null +++ b/ovn_sb_global.go @@ -0,0 +1,70 @@ +// Copyright 2018 Paul Greenberg (greenpau@outlook.com) +// +// 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 ovsdb + +import ( + "fmt" + //"github.com/davecgh/go-spew/spew" +) + +// OvnACL holds ACL information. +type OvnSBGlobal struct { + UUID string `json:"uuid" yaml:"uuid"` + ExternalIDs map[string]string + NB_CFG int64 + Options map[string]string +} + +// GetACL returns a list of OVN ACLs. +func (cli *OvnClient) GetSBGlobal() (*OvnSBGlobal, error) { + sbglobal := &OvnSBGlobal{} + // First, get basic information about OVN logical switches. + query := "SELECT _uuid,external_ids,nb_cfg,options FROM SB_Global" + result, err := cli.Database.Southbound.Client.Transact(cli.Database.Southbound.Name, query) + if err != nil { + return nil, fmt.Errorf("%s: '%s' table error: %s", cli.Database.Southbound.Name, "SB_Global", err) + } + if len(result.Rows) == 0 { + return nil, fmt.Errorf("%s: sb global is empty!", cli.Database.Southbound.Name) + } + if len(result.Rows) > 1 { + return nil, fmt.Errorf("%s: sb global has more than 1 Rows!", cli.Database.Southbound.Name) + } + for _, row := range result.Rows { + if r, dt, err := row.GetColumnValue("nb_cfg", result.Columns); err != nil { + continue + } else { + if dt != "int64" { + // continue + } + sbglobal.NB_CFG = r.(int64) + } + if r, dt, err := row.GetColumnValue("external_ids", result.Columns); err != nil { + sbglobal.ExternalIDs = make(map[string]string) + } else { + if dt == "map[string]string" { + sbglobal.ExternalIDs = r.(map[string]string) + } + } + if r, dt, err := row.GetColumnValue("options", result.Columns); err != nil { + sbglobal.Options = make(map[string]string) + } else { + if dt == "map[string]string" { + sbglobal.Options = r.(map[string]string) + } + } + } + return sbglobal, nil +}