Skip to content
This repository has been archived by the owner on Sep 30, 2024. It is now read-only.

Add topology tags command #942

Merged
merged 8 commits into from
Dec 4, 2019
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions go/app/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -1072,7 +1072,7 @@ func Cli(command string, strict bool, instance string, destination string, owner
case registerCliCommand("topology", "Information", `Show an ascii-graph of a replication topology, given a member of that topology`):
{
clusterName := getClusterName(clusterAlias, instanceKey)
output, err := inst.ASCIITopology(clusterName, pattern, false)
output, err := inst.ASCIITopology(clusterName, pattern, false, false)
if err != nil {
log.Fatale(err)
}
Expand All @@ -1081,7 +1081,16 @@ func Cli(command string, strict bool, instance string, destination string, owner
case registerCliCommand("topology-tabulated", "Information", `Show an ascii-graph of a replication topology, given a member of that topology`):
{
clusterName := getClusterName(clusterAlias, instanceKey)
output, err := inst.ASCIITopology(clusterName, pattern, true)
output, err := inst.ASCIITopology(clusterName, pattern, true, false)
if err != nil {
log.Fatale(err)
}
fmt.Println(output)
}
case registerCliCommand("topology-tags", "Information", `Show an ascii-graph of a replication topology and instance tags, given a member of that topology`):
{
clusterName := getClusterName(clusterAlias, instanceKey)
output, err := inst.ASCIITopology(clusterName, pattern, false, true)
if err != nil {
log.Fatale(err)
}
Expand Down
15 changes: 11 additions & 4 deletions go/http/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1645,14 +1645,14 @@ func (this *HttpAPI) KillQuery(params martini.Params, r render.Render, req *http
}

// AsciiTopology returns an ascii graph of cluster's instances
func (this *HttpAPI) asciiTopology(params martini.Params, r render.Render, req *http.Request, tabulated bool) {
func (this *HttpAPI) asciiTopology(params martini.Params, r render.Render, req *http.Request, tabulated bool, printTags bool) {
clusterName, err := figureClusterName(getClusterHint(params))
if err != nil {
Respond(r, &APIResponse{Code: ERROR, Message: fmt.Sprintf("%+v", err)})
return
}

asciiOutput, err := inst.ASCIITopology(clusterName, "", tabulated)
asciiOutput, err := inst.ASCIITopology(clusterName, "", tabulated, printTags)
if err != nil {
Respond(r, &APIResponse{Code: ERROR, Message: fmt.Sprintf("%+v", err)})
return
Expand All @@ -1674,12 +1674,17 @@ func (this *HttpAPI) SnapshotTopologies(params martini.Params, r render.Render,

// AsciiTopology returns an ascii graph of cluster's instances
func (this *HttpAPI) AsciiTopology(params martini.Params, r render.Render, req *http.Request) {
this.asciiTopology(params, r, req, false)
this.asciiTopology(params, r, req, false, false)
}

// AsciiTopology returns an ascii graph of cluster's instances
func (this *HttpAPI) AsciiTopologyTabulated(params martini.Params, r render.Render, req *http.Request) {
this.asciiTopology(params, r, req, true)
this.asciiTopology(params, r, req, true, false)
}

// AsciiTopologyTags returns an ascii graph of cluster's instances and instance tags
func (this *HttpAPI) AsciiTopologyTags(params martini.Params, r render.Render, req *http.Request) {
this.asciiTopology(params, r, req, false, true)
}

// Cluster provides list of instances in given cluster
Expand Down Expand Up @@ -3645,6 +3650,8 @@ func (this *HttpAPI) RegisterRequests(m *martini.ClassicMartini) {
this.registerAPIRequest(m, "topology/:host/:port", this.AsciiTopology)
this.registerAPIRequest(m, "topology-tabulated/:clusterHint", this.AsciiTopologyTabulated)
this.registerAPIRequest(m, "topology-tabulated/:host/:port", this.AsciiTopologyTabulated)
this.registerAPIRequest(m, "topology-tags/:clusterHint", this.AsciiTopologyTags)
this.registerAPIRequest(m, "topology-tags/:host/:port", this.AsciiTopologyTags)
this.registerAPIRequest(m, "snapshot-topologies", this.SnapshotTopologies)

// Key-value:
Expand Down
18 changes: 13 additions & 5 deletions go/inst/instance_topology.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ var MaxConcurrentReplicaOperations = 5

// getASCIITopologyEntry will get an ascii topology tree rooted at given instance. Ir recursively
// draws the tree
func getASCIITopologyEntry(depth int, instance *Instance, replicationMap map[*Instance]([]*Instance), extendedOutput bool, fillerCharacter string, tabulated bool) []string {
func getASCIITopologyEntry(depth int, instance *Instance, replicationMap map[*Instance]([]*Instance), extendedOutput bool, fillerCharacter string, tabulated bool, printTags bool) []string {
if instance == nil {
return []string{}
}
Expand All @@ -73,17 +73,25 @@ func getASCIITopologyEntry(depth int, instance *Instance, replicationMap map[*In
} else {
entry = fmt.Sprintf("%s%s%s", entry, fillerCharacter, instance.HumanReadableDescription())
}
if printTags {
tags, _ := ReadInstanceTags(&instance.Key)
tagsString := make([]string, len(tags))
for idx, tag := range tags {
tagsString[idx] = tag.Display()
}
entry = fmt.Sprintf("%s [%s]", entry, strings.Join(tagsString, ","))
}
}
result := []string{entry}
for _, replica := range replicationMap[instance] {
replicasResult := getASCIITopologyEntry(depth+1, replica, replicationMap, extendedOutput, fillerCharacter, tabulated)
replicasResult := getASCIITopologyEntry(depth+1, replica, replicationMap, extendedOutput, fillerCharacter, tabulated, printTags)
result = append(result, replicasResult...)
}
return result
}

// ASCIITopology returns a string representation of the topology of given cluster.
func ASCIITopology(clusterName string, historyTimestampPattern string, tabulated bool) (result string, err error) {
func ASCIITopology(clusterName string, historyTimestampPattern string, tabulated bool, printTags bool) (result string, err error) {
fillerCharacter := asciiFillerCharacter
var instances [](*Instance)
if historyTimestampPattern == "" {
Expand Down Expand Up @@ -119,12 +127,12 @@ func ASCIITopology(clusterName string, historyTimestampPattern string, tabulated
var entries []string
if masterInstance != nil {
// Single master
entries = getASCIITopologyEntry(0, masterInstance, replicationMap, historyTimestampPattern == "", fillerCharacter, tabulated)
entries = getASCIITopologyEntry(0, masterInstance, replicationMap, historyTimestampPattern == "", fillerCharacter, tabulated, printTags)
} else {
// Co-masters? For visualization we put each in its own branch while ignoring its other co-masters.
for _, instance := range instances {
if instance.IsCoMaster {
entries = append(entries, getASCIITopologyEntry(1, instance, replicationMap, historyTimestampPattern == "", fillerCharacter, tabulated)...)
entries = append(entries, getASCIITopologyEntry(1, instance, replicationMap, historyTimestampPattern == "", fillerCharacter, tabulated, printTags)...)
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions go/inst/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ func (tag *Tag) String() string {
return fmt.Sprintf("%s=%s", tag.TagName, tag.TagValue)
}

func (tag *Tag) Display() string {
if tag.TagValue == "" {
return fmt.Sprintf("%s", tag.TagName)
} else {
return fmt.Sprintf("%s=%s", tag.TagName, tag.TagValue)
}
}

func ParseIntersectTags(tagsString string) (tags [](*Tag), err error) {
for _, tagString := range strings.Split(tagsString, ",") {
tag, err := ParseTag(tagString)
Expand Down
7 changes: 7 additions & 0 deletions resources/bin/orchestrator-client
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,12 @@ function ascii_topology_tabulated {
echo "$api_response" | jq -r '.Details'
}

function ascii_topology_tags {
assert_nonempty "instance|alias" "${alias:-$instance}"
api "topology-tags/${alias:-$instance}"
echo "$api_response" | jq -r '.Details'
}

function snapshot_topologies {
api "snapshot-topologies"
echo "$api_response" | jq -r '.Details'
Expand Down Expand Up @@ -875,6 +881,7 @@ function run_command {

"topology") ascii_topology ;; # Show an ascii-graph of a replication topology, given a member of that topology
"topology-tabulated") ascii_topology_tabulated ;; # Show an ascii-graph of a replication topology, given a member of that topology, in tabulated format
"topology-tags") ascii_topology_tags ;; # Show an ascii-graph of a replication topology and instance tags, given a member of that topology
"snapshot-topologies") snapshot_topologies ;; # Trigger topology snapshot (recording host/master settings for all hosts)
"clusters") clusters ;; # List all clusters known to orchestrator
"clusters-alias") clusters_alias ;; # List all clusters known to orchestrator
Expand Down
7 changes: 7 additions & 0 deletions tests/integration/topology-tags/create.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
insert into database_instance_tags (
hostname, port, tag_name, tag_value
) values
('testhost', 22293, 'role', 'backup'),
('testhost', 22293, 'in_service', ''),
('testhost', 22294, 'role', 'delayed'),
('testhost', 22295, 'in_service', '');
5 changes: 5 additions & 0 deletions tests/integration/topology-tags/expect_output
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
testhost:22293 [unknown,unchecked,5.6.28-log,rw,STATEMENT,>>,P-GTID] [in_service,role=backup]
- testhost:22294 [unknown,unchecked,5.6.28-log,rw,STATEMENT,>>,P-GTID] [role=delayed]
- testhost:22295 [unknown,unchecked,5.6.28-log,rw,STATEMENT,>>,P-GTID] [in_service]
- testhost:22296 [unknown,unchecked,5.6.28,rw,nobinlog,P-GTID] []
- testhost:22297 [unknown,unchecked,5.6.28-log,rw,STATEMENT,>>,P-GTID] []
1 change: 1 addition & 0 deletions tests/integration/topology-tags/extra_args
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-c topology-tags -i testhost:22294