2019-02-14 15:01:33 +03:00
package main
import (
2019-02-14 19:18:43 +03:00
"encoding/json"
2019-02-19 15:46:00 +03:00
"fmt"
2019-02-14 15:01:33 +03:00
"log"
2019-02-14 17:35:18 +03:00
"math/rand"
2019-02-19 18:26:52 +03:00
"strings"
2019-02-14 19:18:43 +03:00
"time"
2019-02-14 15:01:33 +03:00
)
2019-02-19 18:26:52 +03:00
//future feature
2019-02-19 15:46:00 +03:00
func makepreudorandom ( ) {
a := make ( [ ] int , 0 , 4096 / 4 )
for i := 0 ; i < 4096 ; i += 4 {
a = append ( a , i )
}
rand . Shuffle ( len ( a ) , func ( i , j int ) {
a [ i ] , a [ j ] = a [ j ] , a [ i ]
} )
fmt . Println ( a )
}
func MakeMonQuery ( cephconn * Cephconnection , query map [ string ] string ) [ ] byte {
monjson , err := json . Marshal ( query )
2019-02-15 20:04:32 +03:00
if err != nil {
log . Fatalf ( "Can't marshal json mon query. Error: %v" , err )
}
monrawanswer , _ , err := cephconn . conn . MonCommand ( monjson )
if err != nil {
log . Fatalf ( "Failed exec monCommand. Error: %v" , err )
}
2019-02-19 15:46:00 +03:00
return monrawanswer
}
2019-02-15 20:04:32 +03:00
2019-02-19 15:46:00 +03:00
func GetPoolSize ( cephconn * Cephconnection , params Params ) Poolinfo {
monrawanswer := MakeMonQuery ( cephconn , map [ string ] string { "prefix" : "osd pool get" , "pool" : params . pool ,
"format" : "json" , "var" : "size" } )
2019-02-19 10:16:11 +03:00
monanswer := Poolinfo { }
2019-02-15 20:04:32 +03:00
if err := json . Unmarshal ( [ ] byte ( monrawanswer ) , & monanswer ) ; err != nil {
log . Fatalf ( "Can't parse monitor answer. Error: %v" , err )
}
2019-02-19 10:16:11 +03:00
return monanswer
2019-02-15 20:04:32 +03:00
2019-02-14 19:18:43 +03:00
}
2019-02-15 20:04:32 +03:00
2019-02-19 15:46:00 +03:00
func GetPgByPool ( cephconn * Cephconnection , params Params ) [ ] PlacementGroup {
monrawanswer := MakeMonQuery ( cephconn , map [ string ] string { "prefix" : "pg ls-by-pool" , "poolstr" : params . pool ,
"format" : "json" } )
2019-02-19 18:26:52 +03:00
var monanswer [ ] PlacementGroup
2019-02-19 15:46:00 +03:00
if err := json . Unmarshal ( [ ] byte ( monrawanswer ) , & monanswer ) ; err != nil {
log . Fatalf ( "Can't parse monitor answer. Error: %v" , err )
2019-02-15 20:04:32 +03:00
}
2019-02-19 15:46:00 +03:00
return monanswer
}
2019-02-15 20:04:32 +03:00
2019-02-19 15:46:00 +03:00
func GetOsdCrushDump ( cephconn * Cephconnection ) OsdCrushDump {
monrawanswer := MakeMonQuery ( cephconn , map [ string ] string { "prefix" : "osd crush dump" , "format" : "json" } )
2019-02-19 18:26:52 +03:00
var monanswer OsdCrushDump
2019-02-15 20:04:32 +03:00
if err := json . Unmarshal ( [ ] byte ( monrawanswer ) , & monanswer ) ; err != nil {
log . Fatalf ( "Can't parse monitor answer. Error: %v" , err )
}
2019-02-19 10:16:11 +03:00
return monanswer
2019-02-14 19:18:43 +03:00
}
2019-02-19 15:46:00 +03:00
func GetOsdDump ( cephconn * Cephconnection ) OsdDump {
monrawanswer := MakeMonQuery ( cephconn , map [ string ] string { "prefix" : "osd dump" , "format" : "json" } )
2019-02-19 18:26:52 +03:00
var monanswer OsdDump
2019-02-19 15:46:00 +03:00
if err := json . Unmarshal ( [ ] byte ( monrawanswer ) , & monanswer ) ; err != nil {
log . Fatalf ( "Can't parse monitor answer. Error: %v" , err )
}
return monanswer
}
2019-02-19 10:16:11 +03:00
2019-02-19 18:26:52 +03:00
func GetCrushHostBuckets ( buckets [ ] Bucket , itemid int64 ) [ ] Bucket {
var rootbuckets [ ] Bucket
for _ , bucket := range buckets {
if bucket . ID == itemid {
if bucket . TypeName == "host" {
rootbuckets = append ( rootbuckets , bucket )
for _ , item := range bucket . Items {
result := GetCrushHostBuckets ( buckets , item . ID )
for _ , it := range result {
rootbuckets = append ( rootbuckets , it )
}
}
} else {
for _ , item := range bucket . Items {
result := GetCrushHostBuckets ( buckets , item . ID )
for _ , it := range result {
rootbuckets = append ( rootbuckets , it )
}
}
}
}
}
return rootbuckets
}
func GetOsdForLocations ( params Params , osdcrushdump OsdCrushDump , osddump OsdDump , poolinfo Poolinfo ) map [ string ] [ ] Device {
2019-02-19 15:46:00 +03:00
var crushrule int64
2019-02-19 18:26:52 +03:00
var crushrulename string
2019-02-19 15:46:00 +03:00
for _ , pool := range osddump . Pools {
if pool . Pool == poolinfo . PoolId {
crushrule = pool . CrushRule
}
}
2019-02-19 18:26:52 +03:00
var rootid int64
2019-02-19 15:46:00 +03:00
for _ , rule := range osdcrushdump . Rules {
if rule . RuleID == crushrule {
2019-02-19 18:26:52 +03:00
crushrulename = rule . RuleName
2019-02-19 15:46:00 +03:00
for _ , step := range rule . Steps {
if step . Op == "take" {
2019-02-19 18:26:52 +03:00
rootid = step . Item
}
}
}
}
osdhosts := make ( map [ string ] [ ] Device )
bucketitems := GetCrushHostBuckets ( osdcrushdump . Buckets , rootid )
if params . define != "" {
if strings . HasPrefix ( params . define , "osd." ) {
for _ , hostbucket := range bucketitems {
for _ , item := range hostbucket . Items {
for _ , device := range osdcrushdump . Devices {
if device . ID == item . ID && params . define == device . Name {
osdhosts [ hostbucket . Name ] = append ( osdhosts [ hostbucket . Name ] , device )
}
}
}
}
2019-02-19 18:33:56 +03:00
if len ( osdhosts ) == 0 {
2019-02-19 18:26:52 +03:00
log . Fatalf ( "Defined osd not exist in root for rule: %v pool: %v.\nYou should define osd like osd.X" ,
crushrulename , poolinfo . Pool )
}
} else {
for _ , hostbucket := range bucketitems {
2019-02-19 18:39:34 +03:00
if strings . Split ( hostbucket . Name , "~" ) [ 0 ] == strings . Split ( params . define , "~" ) [ 0 ] { //purge device class
2019-02-19 18:26:52 +03:00
for _ , item := range hostbucket . Items {
for _ , device := range osdcrushdump . Devices {
if device . ID == item . ID {
osdhosts [ hostbucket . Name ] = append ( osdhosts [ hostbucket . Name ] , device )
}
}
}
2019-02-19 15:46:00 +03:00
}
}
2019-02-19 18:33:56 +03:00
if len ( osdhosts ) == 0 {
2019-02-19 18:26:52 +03:00
log . Fatalf ( "Defined host not exist in root for rule: %v pool: %v" , crushrulename , poolinfo . Pool )
}
}
} else {
for _ , hostbucket := range bucketitems {
for _ , item := range hostbucket . Items {
for _ , device := range osdcrushdump . Devices {
if device . ID == item . ID {
osdhosts [ hostbucket . Name ] = append ( osdhosts [ hostbucket . Name ] , device )
}
}
}
}
2019-02-19 18:33:56 +03:00
if len ( osdhosts ) == 0 {
2019-02-19 18:26:52 +03:00
log . Fatalf ( "Osd not exist in root for rule: %v pool: %v" , crushrulename , poolinfo . Pool )
2019-02-19 15:46:00 +03:00
}
}
2019-02-19 18:26:52 +03:00
return osdhosts
2019-02-19 15:46:00 +03:00
}
2019-02-19 10:16:11 +03:00
2019-02-14 15:01:33 +03:00
func main ( ) {
2019-02-14 17:35:18 +03:00
params := Route ( )
2019-02-15 20:04:32 +03:00
cephconn := connectioninit ( params )
2019-02-14 17:35:18 +03:00
defer cephconn . conn . Shutdown ( )
2019-02-14 17:59:40 +03:00
2019-02-14 19:18:43 +03:00
// https://tracker.ceph.com/issues/24114
time . Sleep ( time . Millisecond * 100 )
2019-02-14 17:35:18 +03:00
var buffs [ ] [ ] byte
2019-02-14 17:59:40 +03:00
for i := 0 ; i < 2 * params . threadsCount ; i ++ {
buffs = append ( buffs , make ( [ ] byte , params . blocksize ) )
2019-02-14 17:35:18 +03:00
}
2019-02-14 19:18:43 +03:00
2019-02-14 17:35:18 +03:00
for num := range buffs {
_ , err := rand . Read ( buffs [ num ] )
if err != nil {
log . Fatalln ( err )
}
}
2019-02-19 15:46:00 +03:00
poolinfo := GetPoolSize ( cephconn , params )
2019-02-19 10:16:11 +03:00
if poolinfo . Size != 1 {
2019-02-14 19:18:43 +03:00
log . Fatalf ( "Pool size must be 1. Current size for pool %v is %v. Don't forget that it must be useless pool (not production). Do:\n # ceph osd pool set %v min_size 1\n # ceph osd pool set %v size 1" ,
2019-02-19 10:16:11 +03:00
poolinfo . Pool , poolinfo . Size , poolinfo . Pool , poolinfo . Pool )
2019-02-14 19:18:43 +03:00
}
2019-02-14 17:35:18 +03:00
2019-02-19 15:46:00 +03:00
//placementGroups := GetPgByPool(cephconn, params)
//for _, value := range placementGroups {
// log.Printf("%+v\n", value)
//}
crushosddump := GetOsdCrushDump ( cephconn )
osddump := GetOsdDump ( cephconn )
2019-02-19 18:26:52 +03:00
osddevices := GetOsdForLocations ( params , crushosddump , osddump , poolinfo )
log . Printf ( "%+v" , osddevices )
2019-02-15 20:04:32 +03:00
2019-02-14 15:01:33 +03:00
}
2019-02-19 10:16:11 +03:00
//TODO получить список PG, если не все находятся на нужных OSD выкинуть эксепшн.