Skip to content

Commit d140840

Browse files
committed
feat(browser): fixed visual of loadbalancer
Signed-off-by: olivier dubo <olivier.dubo@ovhcloud.com>
1 parent d5ed059 commit d140840

1 file changed

Lines changed: 141 additions & 9 deletions

File tree

  • internal/services/browser

internal/services/browser/api.go

Lines changed: 141 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,22 +1397,80 @@ func (m Model) fetchFloatingIPsData() dataLoadedMsg {
13971397
return dataLoadedMsg{data: floatingIPs, err: nil}
13981398
}
13991399

1400-
// fetchLoadBalancersData fetches load balancers at project level
1400+
// fetchLoadBalancersData fetches load balancers from octavia-capable regions
14011401
func (m Model) fetchLoadBalancersData() dataLoadedMsg {
14021402
if m.cloudProject == "" {
1403-
return dataLoadedMsg{
1404-
err: fmt.Errorf("no cloud project selected"),
1403+
return dataLoadedMsg{err: fmt.Errorf("no cloud project selected")}
1404+
}
1405+
1406+
regionEndpoint := fmt.Sprintf("/v1/cloud/project/%s/region", m.cloudProject)
1407+
1408+
// Get region names then filter by octavialoadbalancer feature
1409+
var allNames []string
1410+
if err := httpLib.Client.Get(regionEndpoint, &allNames); err != nil {
1411+
return dataLoadedMsg{err: err}
1412+
}
1413+
ids := make([]any, len(allNames))
1414+
for i, n := range allNames {
1415+
ids[i] = n
1416+
}
1417+
details, _ := httpLib.FetchObjectsParallel[map[string]any](regionEndpoint+"/%s", ids, true)
1418+
1419+
var regions []any
1420+
var regionNames []string
1421+
for i, r := range details {
1422+
if r == nil {
1423+
continue
14051424
}
1425+
if services, ok := r["services"].([]interface{}); ok {
1426+
for _, svc := range services {
1427+
if sm, ok := svc.(map[string]interface{}); ok {
1428+
if sm["name"] == "octavialoadbalancer" && sm["status"] == "UP" {
1429+
regions = append(regions, allNames[i])
1430+
regionNames = append(regionNames, allNames[i])
1431+
break
1432+
}
1433+
}
1434+
}
1435+
}
1436+
}
1437+
1438+
if len(regions) == 0 {
1439+
return dataLoadedMsg{data: nil, err: nil}
14061440
}
14071441

1408-
var loadbalancers []map[string]interface{}
1409-
endpoint := fmt.Sprintf("/v1/cloud/project/%s/networkloadbalancer", m.cloudProject)
1410-
err := httpLib.Client.Get(endpoint, &loadbalancers)
1442+
allRegionLBs, _ := httpLib.FetchObjectsParallel[[]map[string]any](regionEndpoint+"/%s/loadbalancing/loadbalancer", regions, true)
14111443

1412-
return dataLoadedMsg{
1413-
data: loadbalancers,
1414-
err: err,
1444+
// Build flavorId -> name map per region in parallel
1445+
allRegionFlavors, _ := httpLib.FetchObjectsParallel[[]map[string]any](regionEndpoint+"/%s/loadbalancing/flavor", regions, true)
1446+
flavorNameMap := make(map[string]string)
1447+
for _, flavors := range allRegionFlavors {
1448+
for _, f := range flavors {
1449+
if id, ok := f["id"].(string); ok {
1450+
if name, ok := f["name"].(string); ok {
1451+
flavorNameMap[id] = name
1452+
}
1453+
}
1454+
}
14151455
}
1456+
1457+
var lbs []map[string]interface{}
1458+
for i, regionLBs := range allRegionLBs {
1459+
for _, lb := range regionLBs {
1460+
if r, _ := lb["region"].(string); r == "" {
1461+
lb["region"] = regionNames[i]
1462+
}
1463+
// Replace flavorId with flavor name
1464+
if fid, ok := lb["flavorId"].(string); ok {
1465+
if fname, found := flavorNameMap[fid]; found {
1466+
lb["_flavorName"] = fname
1467+
}
1468+
}
1469+
lbs = append(lbs, lb)
1470+
}
1471+
}
1472+
1473+
return dataLoadedMsg{data: lbs, err: nil}
14161474
}
14171475

14181476
// fetchGatewaysData fetches gateways from network-capable regions
@@ -1654,6 +1712,8 @@ func (m Model) handleDataLoaded(msg dataLoadedMsg) (tea.Model, tea.Cmd) {
16541712
m.table = createFloatingIPsTable(msg.data, m.width, m.height)
16551713
case ProductNetworkGateway:
16561714
m.table = createGatewaysTable(msg.data, m.width, m.height)
1715+
case ProductNetworkLB:
1716+
m.table = createLoadBalancersTable(msg.data, m.width, m.height)
16571717
default:
16581718
m.table = createGenericTable(msg.data, m.width, m.height)
16591719
}
@@ -2123,6 +2183,78 @@ func createPrivateNetworksTable(data []map[string]interface{}, width, height int
21232183
return t
21242184
}
21252185

2186+
// createLoadBalancersTable creates a table for load balancers.
2187+
func createLoadBalancersTable(data []map[string]interface{}, width, height int) table.Model {
2188+
columns := []table.Column{
2189+
{Title: "Name", Width: 22},
2190+
{Title: "Region", Width: 16},
2191+
{Title: "Size", Width: 14},
2192+
{Title: "Private Network", Width: 36},
2193+
{Title: "Public IP", Width: 18},
2194+
{Title: "Private IP", Width: 16},
2195+
{Title: "Supply Status", Width: 14},
2196+
{Title: "Status", Width: 12},
2197+
}
2198+
2199+
var rows []table.Row
2200+
for _, lb := range data {
2201+
name := getString(lb, "name")
2202+
region := getString(lb, "region")
2203+
size := getString(lb, "_flavorName")
2204+
if size == "" {
2205+
size = getString(lb, "flavorId")
2206+
}
2207+
privateNetwork := getString(lb, "vipNetworkId")
2208+
privateIP := getString(lb, "vipAddress")
2209+
provisioning := getString(lb, "provisioningStatus")
2210+
status := getString(lb, "operatingStatus")
2211+
2212+
publicIP := "-"
2213+
if fi, ok := lb["floatingIp"].(map[string]interface{}); ok {
2214+
if v := getString(fi, "ip"); v != "" {
2215+
publicIP = v
2216+
}
2217+
}
2218+
if privateNetwork == "" {
2219+
privateNetwork = "-"
2220+
}
2221+
if privateIP == "" {
2222+
privateIP = "-"
2223+
}
2224+
2225+
rows = append(rows, table.Row{name, region, size, privateNetwork, publicIP, privateIP, provisioning, status})
2226+
}
2227+
2228+
tableHeight := height - 15
2229+
if tableHeight < 5 {
2230+
tableHeight = 5
2231+
}
2232+
if tableHeight > 20 {
2233+
tableHeight = 20
2234+
}
2235+
2236+
t := table.New(
2237+
table.WithColumns(columns),
2238+
table.WithRows(rows),
2239+
table.WithFocused(true),
2240+
table.WithHeight(tableHeight),
2241+
)
2242+
2243+
s := table.DefaultStyles()
2244+
s.Header = s.Header.
2245+
BorderStyle(lipgloss.NormalBorder()).
2246+
BorderForeground(lipgloss.Color("240")).
2247+
BorderBottom(true).
2248+
Bold(true)
2249+
s.Selected = s.Selected.
2250+
Foreground(lipgloss.Color("229")).
2251+
Background(lipgloss.Color("57")).
2252+
Bold(false)
2253+
t.SetStyles(s)
2254+
2255+
return t
2256+
}
2257+
21262258
// createGatewaysTable creates a table for gateways.
21272259
func createGatewaysTable(data []map[string]interface{}, width, height int) table.Model {
21282260
columns := []table.Column{

0 commit comments

Comments
 (0)