-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement automatic failure domain management on scale-up. Start out with failure domain OSD, upgrade to Host failure domain once we reach 3 nodes with OSDs. Signed-off-by: Peter Sabaini <peter.sabaini@canonical.com>
- Loading branch information
Showing
4 changed files
with
230 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package ceph | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"github.com/tidwall/gjson" | ||
"strings" | ||
) | ||
|
||
// removeCrushRule removes a named crush rule | ||
func removeCrushRule(name string) error { | ||
_, err := processExec.RunCommand("ceph", "osd", "crush", "rule", "rm", name) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// addCrushRule creates a new default crush rule with a given name and failure domain | ||
func addCrushRule(name string, failureDomain string) error { | ||
_, err := processExec.RunCommand("ceph", "osd", "crush", "rule", "create-replicated", name, "default", failureDomain) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// listCrushRules returns a list of crush rule names | ||
func listCrushRules() ([]string, error) { | ||
output, err := processExec.RunCommand("ceph", "osd", "crush", "rule", "ls") | ||
if err != nil { | ||
return nil, err | ||
} | ||
rules := strings.Split(strings.TrimSpace(output), "\n") | ||
return rules, nil | ||
} | ||
|
||
// haveCrushRule returns true if a crush rule with the given name exists | ||
func haveCrushRule(name string) bool { | ||
rules, err := listCrushRules() | ||
if err != nil { | ||
return false | ||
} | ||
for _, rule := range rules { | ||
if rule == name { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
// getCrushRuleID returns the id of a crush rule with the given name | ||
func getCrushRuleID(name string) (string, error) { | ||
output, err := processExec.RunCommand("ceph", "osd", "crush", "rule", "dump", name) | ||
if err != nil { | ||
return "", err | ||
} | ||
var jsond map[string]any | ||
err = json.Unmarshal([]byte(output), &jsond) | ||
val, ok := jsond["rule_id"] | ||
if !ok { | ||
return "", fmt.Errorf("rule_id not found in crush rule dump") | ||
} | ||
return fmt.Sprintf("%v", val), nil // convert to string | ||
} | ||
|
||
// getPoolsForDomain returns a list of pools that use a given crush failure domain | ||
func getPoolsForDomain(domain string) ([]string, error) { | ||
var pools []string | ||
|
||
ruleID, err := getCrushRuleID(fmt.Sprintf("microceph_auto_%s", domain)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
output, err := processExec.RunCommand("ceph", "osd", "pool", "ls", "detail", "--format=json") | ||
if err != nil { | ||
return nil, err | ||
} | ||
poolobjs := gjson.Get(output, fmt.Sprintf("#(crush_rule==%s)#.pool_name", ruleID)) | ||
for _, poolobj := range poolobjs.Array() { | ||
pools = append(pools, poolobj.String()) | ||
} | ||
return pools, nil | ||
} | ||
|
||
// setPoolCrushRule sets the crush rule for a given pool | ||
func setPoolCrushRule(pool string, rule string) error { | ||
_, err := processExec.RunCommand("ceph", "osd", "pool", "set", pool, "crush_rule", rule) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package database | ||
|
||
import ( | ||
"context" | ||
"database/sql" | ||
"fmt" | ||
"github.com/canonical/microcluster/cluster" | ||
"github.com/lxc/lxd/lxd/db/query" | ||
"github.com/lxc/lxd/shared/api" | ||
) | ||
|
||
type MemberDisk struct { | ||
Member string `db:"member"` | ||
NumDisks int `db:"num_disks"` | ||
} | ||
|
||
var _ = api.ServerEnvironment{} | ||
|
||
var membersDiskCnt = cluster.RegisterStmt(` | ||
SELECT internal_cluster_members.name AS member, count(disks.id) AS num_disks | ||
FROM disks | ||
JOIN internal_cluster_members ON disks.member_id = internal_cluster_members.id | ||
GROUP BY internal_cluster_members.id | ||
`) | ||
|
||
// MembersDiskCnt returns the number of disks per member for all members that have at least one disk | ||
func MembersDiskCnt(ctx context.Context, tx *sql.Tx) ([]MemberDisk, error) { | ||
var err error | ||
var sqlStmt *sql.Stmt | ||
|
||
objects := make([]MemberDisk, 0) | ||
|
||
sqlStmt, err = cluster.Stmt(tx, membersDiskCnt) | ||
if err != nil { | ||
return nil, fmt.Errorf("Failed to get \"membersDiskCnt\" prepared statement: %w", err) | ||
} | ||
|
||
dest := func(scan func(dest ...any) error) error { | ||
m := MemberDisk{} | ||
err := scan(&m.Member, &m.NumDisks) | ||
if err != nil { | ||
return err | ||
} | ||
objects = append(objects, m) | ||
return nil | ||
} | ||
|
||
err = query.SelectObjects(ctx, sqlStmt, dest) | ||
if err != nil { | ||
return nil, fmt.Errorf("Failed to get \"membersDiskCnt\" objects: %w", err) | ||
} | ||
|
||
return objects, err | ||
} |