Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- This is a post checking tool that performs role specific tests on the roles to ensure that everything
- is installed and running correctly
- */
- package postcheck
- import (
- "errors"
- "flag"
- "fmt"
- log "github.com/Sirupsen/logrus"
- "github.com/jeffail/gabs"
- "golang.org/x/crypto/ssh"
- "gopkg.in/mgo.v2"
- "gopkg.in/mgo.v2/bson"
- "lib/check"
- "lib/sshutility"
- "strings"
- "time"
- "utils/helper"
- )
- var (
- hostIps = ""
- username = ""
- configJson *gabs.Container
- password = ""
- hostsToCheck []string
- postCheckErr error
- )
- type HostsMappingDoc struct {
- Cluster string
- Mapping map[string]interface{}
- }
- func init() {
- flag.StringVar(&hostIps, "mongo_hosts", "", "mongodb IP's")
- flag.StringVar(&username, "username", "", "mongodb username")
- flag.StringVar(&password, "password", "", "mongodb password")
- }
- // Method to check if the mongodb details are not empty
- func checkInfo(hostIps string, username string, password string) error {
- if hostIps == "" || username == "" || password == "" {
- return errors.New("Please provide the mongodb IP/s, mongodb username and password")
- }
- return nil
- }
- func Exec(configJsonDeploy *gabs.Container) {
- flag.Parse()
- // Check if the input config is used
- if configJsonDeploy != nil {
- // Collect mongodb information and retrieve the config form the database
- mongoUsername, _ := configJsonDeploy.Path("user_input.mongodb.username").Data().(string)
- mongoPassword, _ := configJsonDeploy.Path("user_input.mongodb.password").Data().(string)
- var mongoIps []string
- helper.ExtractStringArray(&mongoIps, configJsonDeploy, "user_input.mongodb.hosts")
- var IPstring string
- // Check if a replica set is used
- if len(mongoIps) == 3 {
- IPstring = mongoIps[0] + "," + mongoIps[1] + "," + mongoIps[2]
- } else {
- IPstring = mongoIps[0]
- }
- configJson = getConfigJsonFromDatabase(IPstring, mongoUsername, mongoPassword)
- } else {
- // Check if mongodb details are provided
- err := checkInfo(hostIps, username, password)
- if err != nil {
- log.Fatal(err)
- }
- // Get the config from the mongo database
- configJson = getConfigJsonFromDatabase(hostIps, username, password)
- }
- //fmt.Println(configJson)
- log.Info("Running checks...")
- //fmt.Println(configJson)
- // Get in the username and password for ssh
- sshUsername := check.GetUser(configJson)
- sshPassword, _ := configJson.Path("user_input.ssh.password").Data().(string)
- sshPem, okSshPem := configJson.Path("user_input.ssh.pem").Data().(string)
- sshPort := configJson.Path("user_input.ssh.port").Data()
- sshPortStr := fmt.Sprintf("%v", sshPort)
- sshConn := sshutility.SSHConnection{
- UserName: sshUsername,
- PassWord: sshPassword,
- PemFileName: sshPem,
- UsePem: okSshPem,
- DefaultPort: sshPortStr,
- }
- hostTypes := []string{"arrow_cloud"}
- // Check if the arrowdb cluster is present
- arrow_dbCnts, err := configJson.Path("user_input.arrow_db").Children()
- if err == nil && arrow_dbCnts != nil {
- hostTypes = append(hostTypes, "arrow_db")
- }
- var component_ips map[string][]string = check.GetMap(configJson, hostTypes)
- var channelArray []<-chan string
- //var Duplicate []string
- // Iterate over the go map collecting key's and value's to write the hosts to a file
- var doneIPS []string
- for _, ips := range component_ips {
- for x := 0; x < len(ips); x++ {
- if !stringInSlice(ips[x], doneIPS) {
- //Duplicate = append(Duplicate, prod_component2)
- var Duplicate []string
- for prod_component2, ips2 := range component_ips {
- for y := 0; y < len(ips2); y++ {
- ip2 := ips2[y]
- if ip2 == ips[x] {
- Duplicate = append(Duplicate, prod_component2)
- }
- // if stringInSlice(ip2, Duplicate) {
- // Duplicate = append(Duplicate, prod_component2)
- // }
- }
- }
- doneIPS = append(doneIPS, ips[x])
- //log.Error("duplicated are ", Duplicate, " for the ip ", ips[x])
- // Run the checkHost method in parallel
- result := connectHost2(sshConn, configJson, Duplicate, ips[x])
- channelArray = append(channelArray, result)
- }
- }
- }
- //log.Fatal("done")
- var passed = true
- for x := 0; x < len(channelArray); x++ {
- //select {
- chanResult := <-channelArray[x]
- boolResult := strings.Split(chanResult, "--")
- result := boolResult[1]
- fmt.Println("result for "+boolResult[0]+" is ", result)
- if result == "failed" && postCheckErr == nil {
- postCheckErr = errors.New("Postcheck failed!")
- }
- }
- fmt.Println("passed = ", passed)
- if postCheckErr != nil {
- fmt.Println("postcheck failed")
- } else {
- fmt.Println("postcheck passed")
- }
- }
- // SSH and run the postCheck method on the current node
- func connectHost2(sshConn sshutility.SSHConnection, configJson *gabs.Container, prod_components []string, hostIP string) <-chan string {
- c := make(chan string)
- go connectHost(sshConn, configJson, c, prod_components, hostIP)
- //fmt.Println("returning channel : ", <-c)
- return c
- }
- // SSH and run the postCheck method on the current node
- func connectHost(sshConn sshutility.SSHConnection, configJson *gabs.Container, c chan string, prod_components []string, hostIP string) {
- node := map[string]string{
- "host": hostIP,
- }
- // Point towards the client in the ssh library
- sshClient, err := sshConn.Connect(node)
- if err != nil {
- log.Fatalf("Error when connecting to node/s[%s(%s)]: %v", prod_components, hostIP, err)
- }
- var finalPass = true
- for x := 0; x < len(prod_components); x++ {
- passed := postCheck(sshClient, configJson, prod_components[x], hostIP)
- //var name = prod_component + "." + hostIP
- //var result = ""
- if passed != true {
- finalPass = false
- }
- }
- defer sshClient.Close()
- if finalPass == true {
- c <- hostIP + "--passed"
- } else {
- c <- hostIP + "--failed"
- }
- }
- // Method that runs role specific checks to ensure certain tasks/services are running
- func postCheck(sshClient *ssh.Client, configJson *gabs.Container, prod_component string, hostIP string) bool {
- var passed = true
- // Split up the component names into cluster and role
- prodCompArray := strings.Split(prod_component, ".")
- product, componentName := prodCompArray[0], prodCompArray[1]
- // Get the arrowdb_url_prefix and domain_name form the user_input
- arrowdb_url_prefix, _ := configJson.Path("user_input.arrowdb_url_prefix").Data().(string)
- domain_name, _ := configJson.Path("user_input.domain_name").Data().(string)
- // Switch cases to distinguish between the roles
- switch product {
- case "arrow_cloud":
- switch componentName {
- case "stratus":
- curl := "curl " + hostIP + ":7000/ping.json"
- var expected = "\"ping\": \"ok\""
- passed = runCurl(sshClient, curl, product, componentName, hostIP, expected)
- case "log_aggregator":
- case "app_haproxy":
- case "admin_haproxy":
- case "admin":
- case "docker_registry":
- case "container_node":
- curlSession, _ := sshClient.NewSession()
- curl := "curl " + hostIP + ":9090/ping"
- if err := curlSession.Run(curl); err != nil {
- passed = false
- log.Error("cannot '"+curl+"' from <"+product+"."+componentName+">, IP : ", hostIP)
- } else {
- defer curlSession.Close()
- }
- default:
- log.Error("the hosts are unreadable")
- return false
- }
- case "arrow_db":
- switch componentName {
- case "api":
- curlSession, _ := sshClient.NewSession()
- curl := "curl " + hostIP + ":8082"
- if err := curlSession.Run(curl); err != nil {
- passed = false
- log.Error("cannot '"+curl+"' from <"+product+"."+componentName+">, IP : ", hostIP)
- } else {
- defer curlSession.Close()
- }
- case "upload":
- delayed_jobSession, _ := sshClient.NewSession()
- output, _ := delayed_jobSession.Output("ps -ef")
- outputString := string(output[:])
- defer delayed_jobSession.Close()
- if !strings.Contains(outputString, "delayed_job") {
- log.Error("delayed_job is not running on " + hostIP + " \n")
- passed = false
- }
- curlSession, _ := sshClient.NewSession()
- curl := "curl " + hostIP + ":8082"
- if err := curlSession.Run(curl); err != nil {
- passed = false
- log.Error("cannot '"+curl+"' from <"+product+"."+componentName+">, IP : ", hostIP)
- } else {
- defer curlSession.Close()
- }
- case "admin":
- case "haproxy":
- curl := "curl --header \"Host: " + arrowdb_url_prefix + "." + domain_name + "\" " + hostIP + "/v1/admins/ping.json"
- var expected = "\"code\":200"
- passed = runCurl(sshClient, curl, product, componentName, hostIP, expected)
- case "push":
- default:
- log.Println("the hosts are unreadable")
- return false
- }
- }
- return passed
- }
- // Method to cmpare the output of the test with the expected result
- func compareOutput(result string, curl string, product string, componentName string, hostIP string, expected string) bool {
- // Check if the output contains the result
- if !strings.Contains(result, expected) {
- return false
- }
- return true
- }
- // Method that ssh's into the host and runs a curl command
- func runCurl(sshClient *ssh.Client, curl string, product string, componentName string, hostIP string, expected string) bool {
- result := ""
- // Check if the ssh.Client is not nil
- if sshClient != nil {
- curlSession, _ := sshClient.NewSession()
- out, _ := curlSession.Output(curl)
- result = string(out[:])
- // Make sure the output is not empty
- if result == "" {
- log.Error("cannot curl : " + curl)
- } else {
- defer curlSession.Close()
- }
- }
- // Compare the output with the expected result
- var output = compareOutput(result, curl, product, componentName, hostIP, expected)
- if output == false {
- log.Error("cannot '"+curl+"' from <"+product+"."+componentName+">, IP : ", hostIP)
- return false
- }
- return true
- }
- /**
- If user specifies hosts array in user_input only (does not assign hosts to arrowcloud/DB roles) we should get
- configuration from database which was saved when setting up the cluster.
- */
- func getConfigJsonFromDatabase(hostIps string, dbUsername string, dbPassword string) *gabs.Container {
- mongoHosts := strings.Split(hostIps, ",")
- // Append the port to each IP
- var mongoHostPorts []string
- for x := 0; x < len(mongoHosts); x++ {
- mongoHostPorts = append(mongoHostPorts, mongoHosts[x]+":27017")
- }
- log.Infof("Retrieving configuration from database: %v", mongoHostPorts)
- // Initialize info using the username, password and Host
- mongoDBDialInfo := &mgo.DialInfo{
- Addrs: mongoHostPorts,
- Timeout: 10 * time.Second,
- Database: "deployment_stacks",
- Username: dbUsername,
- Password: dbPassword,
- }
- // Dial into mongo db using the replica set
- session, err := mgo.DialWithInfo(mongoDBDialInfo)
- if err != nil {
- log.Fatalf("Failed to connect to mongo nodes: %s\n", err)
- }
- session.SetMode(mgo.Monotonic, true)
- // Select the host_mapping collection
- c := session.DB("deployment_stacks").C("hosts_mapping")
- result := HostsMappingDoc{}
- // Find the record
- err = c.Find(bson.M{}).One(&result)
- if err != nil {
- log.Fatalf("Failed to get configuration from database. %v", err)
- }
- // Create a json object for the host map
- configInMongo, err := gabs.Consume(result.Mapping)
- if err != nil {
- log.Fatalf("Failed to parsing configuration got from database. %v", err)
- }
- return configInMongo
- }
- // Method to check if a string contain's a specified string
- func stringInSlice(a string, list []string) bool {
- for _, b := range list {
- if b == a {
- return true
- }
- }
- return false
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement