Skip to content

Commit

Permalink
feat(service): add the discovered devices and change the connection s…
Browse files Browse the repository at this point in the history
…tatus to unavailable for failed devices (#54)

* feat: add the discovered devices and change the connection status to unavailable for failed ones

* revert: revert the error handling

* feat: add the failed devices after creating session and NewDevices

* refactor: change all the FOUND status to UNAVAILABLE

* refactor: change the locations for GetBladeDatumByIp and GetHostDatumByIp

---------

Signed-off-by: Mengling Ding <[email protected]>
  • Loading branch information
Meng-20 authored Nov 22, 2024
1 parent bf8b702 commit 211a099
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 28 deletions.
12 changes: 9 additions & 3 deletions cmd/cfm-service/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import (
"strings"
"sync"

"github.com/rs/cors"
"k8s.io/klog/v2"

"cfm/pkg/api"
"cfm/pkg/common"
"cfm/pkg/common/datastore"
"cfm/pkg/openapi"
"cfm/pkg/redfishapi"
"cfm/services"

"github.com/rs/cors"
"k8s.io/klog/v2"
)

var Version = "1.x.x"
Expand Down Expand Up @@ -68,6 +68,12 @@ func main() {
defaultRedfishController := redfishapi.NewDefaultAPIController(defaultRedfishService)
api.AddRedfishRouter(ctx, router, defaultRedfishController)

// Discover devices before loading datastore
bladeDevices, _ := services.DiscoverDevices(ctx, defaultApiService, "blade")
hostDevices, _ := services.DiscoverDevices(ctx, defaultApiService, "cxl-host")
// Add the discovered devices into datastore
services.AddDiscoveredDevices(ctx, defaultApiService, bladeDevices, hostDevices)

// Load datastore
datastore.DStore().Restore()
data := datastore.DStore().GetDataStore()
Expand Down
38 changes: 35 additions & 3 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,42 @@
package common

import "cfm/pkg/openapi"

type ConnectionStatus string

const (
ONLINE ConnectionStatus = "online"
FOUND ConnectionStatus = "found"
OFFLINE ConnectionStatus = "offline"
ONLINE ConnectionStatus = "online" // avahi-found, found root service, created backend session, added to service map
UNAVAILABLE ConnectionStatus = "unavailable" // avahi-found AND detect root service AND !created backend session AND !added to service map
OFFLINE ConnectionStatus = "offline" // !avahi-found (after previously adding it)
NOT_APPLICABLE ConnectionStatus = "n\\a"
)

var DefaultApplianceCredentials = &openapi.Credentials{
Username: "root",
Password: "0penBmc",
IpAddress: "127.0.0.1",
Port: 8443,
Insecure: true,
Protocol: "https",
CustomId: "CMA_Discovered_Blades",
}

var DefaultBladeCredentials = &openapi.Credentials{
Username: "root",
Password: "0penBmc",
IpAddress: "127.0.0.1",
Port: 443,
Insecure: true,
Protocol: "https",
CustomId: "Discoverd_Blade_",
}

var DefaultHostCredentials = &openapi.Credentials{
Username: "admin",
Password: "admin12345",
IpAddress: "127.0.0.1",
Port: 8082,
Insecure: true,
Protocol: "http",
CustomId: "Discoverd_Host_",
}
44 changes: 28 additions & 16 deletions pkg/common/datastore/datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import (
"context"
"fmt"

"k8s.io/klog/v2"

"cfm/pkg/common"
"cfm/pkg/openapi"

"k8s.io/klog/v2"
)

const (
Expand Down Expand Up @@ -58,6 +58,28 @@ func (c *DataStore) GetApplianceDatumById(applianceId string) (*ApplianceDatum,
return datum, nil
}

// Verify if the blade exists using the ipAddress
func (c *DataStore) GetBladeDatumByIp(IpAddress string) (*string, bool) {
for _, appliance := range c.ApplianceData {
for bladeId, blade := range appliance.BladeData {
if blade.Credentials.IpAddress == IpAddress {
return &bladeId, true
}
}
}
return nil, false
}

// Verify if the host exists using the ipAddress
func (c *DataStore) GetHostDatumByIp(IpAddress string) (*string, bool) {
for hostId, host := range c.HostData {
if host.Credentials.IpAddress == IpAddress {
return &hostId, true
}
}
return nil, false
}

// GetHostDatumById: Retrieve a host datum from the data store
func (c *DataStore) GetHostDatumById(hostId string) (*HostDatum, error) {
datum, exists := c.HostData[hostId]
Expand Down Expand Up @@ -158,31 +180,21 @@ func ReloadDataStore(ctx context.Context, s openapi.DefaultAPIServicer, c *DataS
logger := klog.FromContext(ctx)

logger.V(2).Info("cfm-service: restoring saved appliances")
var appliancesToDelete []string

for applianceId, applianceDatum := range c.ApplianceData {
_, err = s.AppliancesPost(ctx, *applianceDatum.Credentials)
if err != nil {
logger.V(2).Info("cfm-service: appliance restore failure", "applianceId", applianceId)
appliancesToDelete = append(appliancesToDelete, applianceId)
continue
}

bladesToDelete := make(map[string]string)
for bladeId, bladeDatum := range applianceDatum.BladeData {
_, err = s.BladesPost(ctx, applianceId, *bladeDatum.Credentials)
if err != nil {
_, postErr := s.BladesPost(ctx, applianceId, *bladeDatum.Credentials)
if postErr != nil {
logger.V(2).Info("cfm-service: blade restore failure", "bladeId", bladeId, "applianceId", applianceId)
bladesToDelete[applianceId] = bladeId
continue
}
}

for applianceId, bladeId := range bladesToDelete {
delete(c.ApplianceData[applianceId].BladeData, bladeId)
}
}

for _, applianceId := range appliancesToDelete {
delete(c.ApplianceData, applianceId)
}

logger.V(2).Info("cfm-service: restoring saved hosts")
Expand Down
34 changes: 33 additions & 1 deletion pkg/manager/appliance.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,22 @@ func (a *Appliance) AddBlade(ctx context.Context, c *openapi.Credentials) (*Blad
if err != nil || response == nil {
newErr := fmt.Errorf("create session failure at [%s:%d] using interface [%s]: %w", c.IpAddress, c.Port, backendName, err)
logger.Error(newErr, "failure: add blade")

// Continue adding the failed blade to the datastore, but update the connection status to unavailable
newBlade := &Blade{
Id: c.CustomId,
Uri: GetCfmUriBladeId(a.Id, c.CustomId),
Status: common.UNAVAILABLE,
ApplianceId: a.Id,
}
a.Blades[newBlade.Id] = newBlade

applianceDatum, _ := datastore.DStore().GetDataStore().GetApplianceDatumById(newBlade.ApplianceId)
applianceDatum.AddBladeDatum(c)
unavailabelBlade, _ := applianceDatum.GetBladeDatumById(ctx, c.CustomId)
unavailabelBlade.ConnectionStatus = common.UNAVAILABLE
datastore.DStore().Store()

return nil, &common.RequestError{StatusCode: common.StatusBladeCreateSessionFailure, Err: newErr}
}

Expand Down Expand Up @@ -148,6 +164,22 @@ func (a *Appliance) AddBlade(ctx context.Context, c *openapi.Credentials) (*Blad

newErr := fmt.Errorf("appliance [%s] new blade object creation failure: %w", a.Id, err)
logger.Error(newErr, "failure: add blade")

// Continue adding the failed blade to the datastore, but update the connection status to unavailable
newBlade := &Blade{
Id: c.CustomId,
Uri: GetCfmUriBladeId(a.Id, c.CustomId),
Status: common.UNAVAILABLE,
ApplianceId: a.Id,
}
a.Blades[newBlade.Id] = newBlade

applianceDatum, _ := datastore.DStore().GetDataStore().GetApplianceDatumById(newBlade.ApplianceId)
applianceDatum.AddBladeDatum(c)
unavailabelBlade, _ := applianceDatum.GetBladeDatumById(ctx, c.CustomId)
unavailabelBlade.ConnectionStatus = common.UNAVAILABLE
datastore.DStore().Store()

return nil, &common.RequestError{StatusCode: common.StatusManagerInitializationFailure, Err: newErr}
}

Expand Down Expand Up @@ -346,7 +378,7 @@ func (a *Appliance) GetBladeById(ctx context.Context, bladeId string) (*Blade, e
if blade.CheckSync(ctx) {
logger.V(4).Info("initiating auto-resync check", "bladeId", bladeId, "applianceId", a.Id)
blade.UpdateConnectionStatusBackend(ctx)
if blade.Status == common.FOUND { // good power, bad session
if blade.Status == common.UNAVAILABLE { // good power, bad session
blade, err = a.ResyncBladeById(ctx, bladeId)
if err != nil {
newErr := fmt.Errorf("failed to resync blade by id [%s]: %w", bladeId, err)
Expand Down
2 changes: 1 addition & 1 deletion pkg/manager/blade.go
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ func (b *Blade) UpdateConnectionStatusBackend(ctx context.Context) {
if status.FoundSession {
b.Status = common.ONLINE
} else {
b.Status = common.FOUND
b.Status = common.UNAVAILABLE
}
} else {
b.Status = common.OFFLINE
Expand Down
6 changes: 3 additions & 3 deletions pkg/manager/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import (
"strings"
"time"

"k8s.io/klog/v2"

"cfm/pkg/backend"
"cfm/pkg/common"
"cfm/pkg/common/datastore"
"cfm/pkg/openapi"

"k8s.io/klog/v2"
)

const ID_PREFIX_HOST_DFLT string = "host"
Expand Down Expand Up @@ -507,7 +507,7 @@ func (h *Host) UpdateConnectionStatusBackend(ctx context.Context) {
if status.FoundSession {
h.Status = common.ONLINE
} else {
h.Status = common.FOUND
h.Status = common.UNAVAILABLE
}
} else {
h.Status = common.OFFLINE
Expand Down
30 changes: 29 additions & 1 deletion pkg/manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,20 @@ func AddHost(ctx context.Context, c *openapi.Credentials) (*Host, error) {
if err != nil || response == nil {
newErr := fmt.Errorf("create session failure at [%s:%d] using interface [%s]: %w", c.IpAddress, c.Port, backendName, err)
logger.Error(newErr, "failure: add host")

// Continue adding the failed host to the datastore, but update the connection status to unavailable
host := &Host{
Id: c.CustomId,
Uri: GetCfmUriHostId(c.CustomId),
Status: common.UNAVAILABLE,
}
deviceCache.AddHost(host, false)

datastore.DStore().GetDataStore().AddHostDatum(c)
unavailableHost, _ := datastore.DStore().GetDataStore().GetHostDatumById(c.CustomId)
unavailableHost.ConnectionStatus = common.UNAVAILABLE
datastore.DStore().Store()

return nil, &common.RequestError{StatusCode: common.StatusHostCreateSessionFailure, Err: newErr}
}

Expand Down Expand Up @@ -331,6 +345,20 @@ func AddHost(ctx context.Context, c *openapi.Credentials) (*Host, error) {

newErr := fmt.Errorf("new host object creation failure: %w", err)
logger.Error(newErr, "failure: add host")

// Continue adding the failed host to the datastore, but update the connection status to unavailable
host := &Host{
Id: c.CustomId,
Uri: GetCfmUriHostId(c.CustomId),
Status: common.UNAVAILABLE,
}
deviceCache.AddHost(host, false)

datastore.DStore().GetDataStore().AddHostDatum(c)
unavailableHost, _ := datastore.DStore().GetDataStore().GetHostDatumById(c.CustomId)
unavailableHost.ConnectionStatus = common.UNAVAILABLE
datastore.DStore().Store()

return nil, &common.RequestError{StatusCode: common.StatusManagerInitializationFailure, Err: newErr}
}

Expand Down Expand Up @@ -533,7 +561,7 @@ func GetHostById(ctx context.Context, hostId string) (*Host, error) {
if host.CheckSync(ctx) {
logger.V(4).Info("initiating auto-resync check", "hostId", hostId)
host.UpdateConnectionStatusBackend(ctx)
if host.Status == common.FOUND { // good power, bad session
if host.Status == common.UNAVAILABLE { // good power, bad session
host, err = ResyncHostById(ctx, hostId)
if err != nil {
newErr := fmt.Errorf("failed to resync host by id [%s]: %w", hostId, err)
Expand Down
74 changes: 74 additions & 0 deletions services/discovery.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package services

import (
"log"

"golang.org/x/net/context"

"cfm/pkg/common"
"cfm/pkg/common/datastore"
"cfm/pkg/openapi"
)

// discoverDevices function to call the DiscoverDevices API
func DiscoverDevices(ctx context.Context, apiService openapi.DefaultAPIServicer, deviceType string) (openapi.ImplResponse, error) {
resp, err := apiService.DiscoverDevices(ctx, deviceType)
if err != nil {
log.Printf("Error discovering devices of type %s: %v", deviceType, err)
return resp, err
} else {
log.Printf("Discovered devices of type %s: %v", deviceType, resp)
return resp, nil
}
}

func AddDiscoveredDevices(ctx context.Context, apiService openapi.DefaultAPIServicer, blades openapi.ImplResponse, hosts openapi.ImplResponse) {
// Verify the existence of the default appliance; if it doesn't exist, add it
datastore.DStore().Restore()
data := datastore.DStore().GetDataStore()
_, err := datastore.DStore().GetDataStore().GetApplianceDatumById(common.DefaultApplianceCredentials.CustomId)
if err != nil {
datastore.DStore().GetDataStore().AddApplianceDatum(common.DefaultApplianceCredentials)
datastore.DStore().Store()
}

// Add blades
// Convert data type
bladeBodyBytes, ok := blades.Body.([]*openapi.DiscoveredDevice)
if !ok {
log.Fatalf("Response body is not []byte")
}
applianceDatum, _ := datastore.DStore().GetDataStore().GetApplianceDatumById(common.DefaultApplianceCredentials.CustomId)
for _, bladeDevice := range bladeBodyBytes {
_, exist := data.GetBladeDatumByIp(bladeDevice.Address)
if !exist {
newCredentials := *common.DefaultBladeCredentials
newCredentials.IpAddress = bladeDevice.Address
//Assign the actual ipAddress to customId to ensure its uniqueness
newCredentials.CustomId = newCredentials.CustomId + bladeDevice.Address

applianceDatum.AddBladeDatum(&newCredentials)
datastore.DStore().Store()
}
}

// Add cxl-hosts
// Convert data type
hostBodyBytes, ok := hosts.Body.([]*openapi.DiscoveredDevice)
if !ok {
log.Fatalf("Response body is not []byte")
}
for _, hostDevice := range hostBodyBytes {
_, exist := data.GetHostDatumByIp(hostDevice.Address)
if !exist {
newCredentials := *common.DefaultHostCredentials
newCredentials.IpAddress = hostDevice.Address
//Assign the actual ipAddress to customId to ensure its uniqueness
newCredentials.CustomId = newCredentials.CustomId + hostDevice.Address

datastore.DStore().GetDataStore().AddHostDatum(&newCredentials)
datastore.DStore().Store()
}

}
}

0 comments on commit 211a099

Please sign in to comment.