diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 08e868af..7bb6ef3b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -243,6 +243,11 @@ jobs: cat /var/snap/microceph/current/conf/ceph.conf fgrep -q "[${MON_IP}]" /var/snap/microceph/current/conf/ceph.conf + - name: API Testing + run: | + ~/actionutils.sh install_hurl + ~/actionutils.sh hurl tests/hurl/services-mon.hurl + multi-node-tests: name: Multi node testing runs-on: ubuntu-22.04 diff --git a/microceph/api/services.go b/microceph/api/services.go index 2453e765..572eacc5 100644 --- a/microceph/api/services.go +++ b/microceph/api/services.go @@ -36,6 +36,7 @@ func cmdServicesGet(s state.State, r *http.Request) response.Response { // Service endpoints. var monServiceCmd = rest.Endpoint{ Path: "services/mon", + Get: rest.EndpointAction{Handler: cmdMonGet, ProxyTarget: true}, Put: rest.EndpointAction{Handler: cmdEnableServicePut, ProxyTarget: true}, Delete: rest.EndpointAction{Handler: cmdDeleteService, ProxyTarget: true}, } @@ -60,6 +61,21 @@ var rbdMirroServiceCmd = rest.Endpoint{ Delete: rest.EndpointAction{Handler: cmdDeleteService, ProxyTarget: true}, } +// cmdMonGet returns the mon service status. +func cmdMonGet(s state.State, r *http.Request) response.Response { + + // fetch monitor addresses + monitors, err := ceph.GetMonitorAddresses(r.Context(), interfaces.CephState{State: s}) + if err != nil { + return response.InternalError(err) + } + + monStatus := types.MonitorStatus{Addresses: monitors} + + return response.SyncResponse(true, monStatus) + +} + func cmdEnableServicePut(s state.State, r *http.Request) response.Response { var payload types.EnableService diff --git a/microceph/api/types/services.go b/microceph/api/types/services.go index f45ce78b..e0ac0968 100644 --- a/microceph/api/types/services.go +++ b/microceph/api/types/services.go @@ -26,3 +26,9 @@ type RGWService struct { Port int `json:"port" yaml:"port"` Enabled bool `json:"enabled" yaml:"enabled"` } + +// MonitorStatus holds the status of all monitors +// for now, this is just the addresses of the monitors +type MonitorStatus struct { + Addresses []string `json:"addresses" yaml:"addresses"` +} diff --git a/microceph/ceph/config.go b/microceph/ceph/config.go index 6b14092e..681b1e70 100644 --- a/microceph/ceph/config.go +++ b/microceph/ceph/config.go @@ -345,7 +345,7 @@ func UpdateConfig(ctx context.Context, s interfaces.StateInterface) error { // REF: https://docs.ceph.com/en/quincy/rados/configuration/network-config-ref/#ceph-daemons // The mon host configuration option only needs to be sufficiently up to date such that a // client can reach one monitor that is currently online. - monitorAddresses := getMonitorAddresses(config) + monitorAddresses := getMonitorsFromConfig(config) // backward compat: if no mon hosts found, get them from the node addresses but don't // insert into db, as the join logic will take care of that. @@ -435,8 +435,29 @@ func GetConfigDb(ctx context.Context, s interfaces.StateInterface) (map[string]s return config, nil } -// getMonitorAddresses scans a provided config key/value map and returns a list of mon hosts found. -func getMonitorAddresses(configs map[string]string) []string { +// GetMonitorAddresses retrieves the monitor addresses from the database. +func GetMonitorAddresses(ctx context.Context, s interfaces.StateInterface) ([]string, error) { + config, err := GetConfigDb(ctx, s) + if err != nil { + return nil, fmt.Errorf("failed to get config db: %w", err) + } + + monitorAddresses := getMonitorsFromConfig(config) + + if len(monitorAddresses) == 0 { + monitorAddresses, err = backwardCompatMonitors(ctx, s) + if err != nil { + return nil, fmt.Errorf("failed to get monitor addresses: %w", err) + } + } + + // Ensure that IPv6 addresses have square brackets around them (if IPv6 is used). + monitorAddresses = formatIPv6(monitorAddresses) + return monitorAddresses, nil +} + +// getMonitorsFromConfig scans a provided config key/value map and returns a list of mon hosts found. +func getMonitorsFromConfig(configs map[string]string) []string { monHosts := []string{} for k, v := range configs { if strings.Contains(k, "mon.host.") { diff --git a/microceph/ceph/services_placement_rgw.go b/microceph/ceph/services_placement_rgw.go index 627bbb7a..50cc3cfb 100644 --- a/microceph/ceph/services_placement_rgw.go +++ b/microceph/ceph/services_placement_rgw.go @@ -36,7 +36,7 @@ func (rgw *RgwServicePlacement) ServiceInit(ctx context.Context, s interfaces.St return fmt.Errorf("failed to get config db: %w", err) } - return EnableRGW(s, rgw.Port, rgw.SSLPort, rgw.SSLCertificate, rgw.SSLPrivateKey, getMonitorAddresses(config)) + return EnableRGW(s, rgw.Port, rgw.SSLPort, rgw.SSLCertificate, rgw.SSLPrivateKey, getMonitorsFromConfig(config)) } func (rgw *RgwServicePlacement) PostPlacementCheck(s interfaces.StateInterface) error { diff --git a/tests/hurl/services-mon.hurl b/tests/hurl/services-mon.hurl new file mode 100644 index 00000000..812e7d17 --- /dev/null +++ b/tests/hurl/services-mon.hurl @@ -0,0 +1,4 @@ +GET http://localhost/1.0/services/mon +HTTP 200 +[Asserts] +jsonpath "$.metadata.addresses" count == 1 diff --git a/tests/scripts/actionutils.sh b/tests/scripts/actionutils.sh index 57ad4680..f2a745be 100755 --- a/tests/scripts/actionutils.sh +++ b/tests/scripts/actionutils.sh @@ -414,6 +414,18 @@ function install_store() { done } +function install_hurl() { + VERSION=5.0.1 + downloadurl="https://github.com/Orange-OpenSource/hurl/releases/download/$VERSION/hurl_${VERSION}_amd64.deb" + curl --location --remote-name $downloadurl + sudo dpkg -i ./hurl_${VERSION}_amd64.deb +} + +function hurl() { + echo "Running hurl $@" + sudo hurl --unix-socket /var/snap/microceph/common/state/control.socket --test /var/snap/microceph/common/state/control.socket "$@" +} + function upgrade_multinode() { # Refresh to local version, checking health for container in node-wrk0 node-wrk1 node-wrk2 node-wrk3 ; do