Skip to content

List available server types per datacenter #1322

@guettli

Description

@guettli

TL;DR

It would be great, if I could see which server-types are available in which datacenter.

I once wrote that - see below.

Are you interested in adding something like that the hcloud cli?

Example output:

go run ./hcloud-server-types per-datacenter per-type
cax11: hel1-dc2 nbg1-dc3
cax21: hel1-dc2 nbg1-dc3
cax31: hel1-dc2 nbg1-dc3
cax41: hel1-dc2 nbg1-dc3
ccx13: ash-dc1 hel1-dc2 hil-dc1 nbg1-dc3 sin-dc1
ccx23: ash-dc1 hel1-dc2 hil-dc1 nbg1-dc3 sin-dc1
ccx33: ash-dc1 hel1-dc2 hil-dc1 nbg1-dc3 sin-dc1
ccx43: ash-dc1 hel1-dc2 hil-dc1 nbg1-dc3 sin-dc1
ccx53: ash-dc1 hel1-dc2 hil-dc1 nbg1-dc3 sin-dc1
ccx63: ash-dc1 hel1-dc2 hil-dc1 nbg1-dc3 sin-dc1
cpx11: ash-dc1 hil-dc1
cpx12: sin-dc1
cpx21: ash-dc1 hil-dc1
cpx22: hel1-dc2 nbg1-dc3 sin-dc1
cpx31: ash-dc1 hil-dc1
cpx32: hel1-dc2 nbg1-dc3 sin-dc1
cpx41: ash-dc1 hil-dc1
cpx42: hel1-dc2 nbg1-dc3 sin-dc1
cpx51: ash-dc1 hil-dc1
cpx52: hel1-dc2 nbg1-dc3 sin-dc1
cpx62: hel1-dc2 nbg1-dc3 sin-dc1
cx23: nbg1-dc3
cx33: nbg1-dc3
cx43: nbg1-dc3
go run ./hcloud-server-types per-datacenter
ash-dc1: ccx13 ccx23 ccx33 ccx43 ccx53 ccx63 cpx11 cpx21 cpx31 cpx41 cpx51
hel1-dc2: cax11 cax21 cax31 cax41 ccx13 ccx23 ccx33 ccx43 ccx53 ccx63 cpx22 cpx32 cpx42 cpx52 cpx62
hil-dc1: ccx13 ccx23 ccx33 ccx43 ccx53 ccx63 cpx11 cpx21 cpx31 cpx41 cpx51
nbg1-dc3: cax11 cax21 cax31 cax41 ccx13 ccx23 ccx33 ccx43 ccx53 ccx63 cpx22 cpx32 cpx42 cpx52 cpx62 cx23 cx33 cx43
sin-dc1: ccx13 ccx23 ccx33 ccx43 ccx53 ccx63 cpx12 cpx22 cpx32 cpx42 cpx52 cpx62

Example Code

// package main initializes hcloud-server-types.
package main

import (
	"context"
	"fmt"
	"maps"
	"os"
	"slices"
	"strings"

	"github.com/hetznercloud/hcloud-go/v2/hcloud"
)

func usage() {
	fmt.Printf(`Usage: %s [list | per-datacenter | per-type ]
List available HCloud server types. You can return a list, or server types per datacenter,
or datacenters per server type
`, os.Args[0])
}

func main() {
	if len(os.Args) != 2 {
		usage()
		os.Exit(1)
	}
	command := os.Args[1]

	if !slices.Contains([]string{"list", "per-datacenter", "per-type"}, command) {
		fmt.Println("Invalid command. Use 'list', 'per-datacenter', or 'per-type'.")
		usage()
		os.Exit(1)
	}

	datacenterToTypes, err := getDatacenterToTypes()
	if err != nil {
		fmt.Println("Error:", err)
		os.Exit(1)
	}

	switch command {
	case "list":
		datacenters := maps.Keys(datacenterToTypes)
		for _, loc := range slices.Sorted(datacenters) {
			types := datacenterToTypes[loc]
			slices.Sort(types)
			for _, serverType := range types {
				fmt.Printf("%s: %s\n", loc, serverType)
			}
		}
		return
	case "per-datacenter":
		datacenters := maps.Keys(datacenterToTypes)
		for _, loc := range slices.Sorted(datacenters) {
			types := datacenterToTypes[loc]
			slices.Sort(types)
			fmt.Printf("%s: %s\n", loc, strings.Join(types, " "))
		}
		return
	case "per-type":
		typesToDatacenters := make(map[string][]string)
		for datacenter, types := range datacenterToTypes {
			for _, serverType := range types {
				typesToDatacenters[serverType] = append(typesToDatacenters[serverType], datacenter)
			}
		}
		types := maps.Keys(typesToDatacenters)
		for _, t := range slices.Sorted(types) {
			datacenters := typesToDatacenters[t]
			slices.Sort(datacenters)
			fmt.Printf("%s: %s\n", t, strings.Join(datacenters, " "))
		}
	default:
		panic("unknown command: " + command)
	}
}

func getDatacenterToTypes() (map[string][]string, error) {
	token := os.Getenv("HCLOUD_TOKEN")
	if token == "" {
		return nil, fmt.Errorf("HCLOUD_TOKEN environment variable is not set")
	}
	client := hcloud.NewClient(
		hcloud.WithToken(token),
	)
	ctx := context.Background()
	serverTypes, err := client.ServerType.All(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to get server types: %w", err)
	}

	serverNamesMap := make(map[int64]string)
	for _, st := range serverTypes {
		name := st.Name
		if st.IsDeprecated() {
			name = fmt.Sprintf("(%s)", name)
		}
		serverNamesMap[st.ID] = name
	}
	dsList, err := client.Datacenter.All(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed to get server types: %w", err)
	}
	serverTypesMap := make(map[string][]string)
	for _, ds := range dsList {
		for _, st := range ds.ServerTypes.Available {
			serverTypesMap[ds.Name] = append(serverTypesMap[ds.Name], serverNamesMap[st.ID])
		}
	}
	return serverTypesMap, nil
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions