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 main
- import (
- "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/log_utility"
- "lib/sshutility"
- "lib/varfile"
- "strings"
- "time"
- "utils/helper"
- )
- const COLLECTING_DIR = "output/cluster"
- var (
- configFile = ""
- hostsToCheck []string
- )
- type sshChan struct {
- name string
- }
- type HostsMappingDoc struct {
- Cluster string
- Mapping map[string]interface{}
- }
- func init() {
- flag.StringVar(&configFile, "config-file", "", "the deploy config file")
- f, err := log_utility.CreateLogFile("collect")
- if err != nil {
- log.Fatalf("Error creating log file: %v", err)
- }
- log.SetOutput(f)
- log.AddHook(log_utility.NewUserFacingLogWithSpinnerHook())
- log.SetLevel(log.DebugLevel)
- }
- func main() {
- flag.Parse()
- if configFile == "" {
- log.Fatal("Missing parameter -config-file")
- }
- log.Info("Start to collect arrowcloud debug information...\n")
- configJson, err := varfile.GenerateVarfile(configFile)
- if err != nil {
- log.Fatalf("%s. Exiting...", err.Error())
- }
- // Check if the hosts section exists
- hostCtns, err := configJson.Path("user_input.hosts").Children()
- if err == nil && hostCtns != nil {
- // If arrow_cloud and arrow_db are not specified (user did not define hosts-roles mapping, instead only hosts array
- // was specified.) get configuration in database as configJson
- configJson = getConfigJsonFromDatabase(configJson)
- } else {
- log.Debugf("hosts field does not exist or unreadable. err: %v", err)
- }
- // 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,
- }
- // Create a channel for parallel execution
- ch := make(chan sshChan)
- numChannels := 0
- hostTypes := []string{"arrow_cloud", "mongodb"}
- // 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)
- // Iterate over the go map collecting key's and value's to write the hosts to a file
- for prod_component, ips := range component_ips {
- for x := 0; x < len(ips); x++ {
- ip := ips[x]
- // Run the checkHost method in parallel
- go checkHost(sshConn, configJson, ch, prod_component, ip)
- numChannels++
- }
- }
- // Store the result for each channel
- for i := 1; i <= numChannels; i++ {
- result := <-ch
- if result.name == "" {
- log.Errorf("Failed ", result.name)
- }
- }
- log.Info("Complete!")
- }
- // SSH and run the postCheck method on the current node
- func checkHost(sshConn sshutility.SSHConnection, configJson *gabs.Container, ch chan sshChan, prod_component 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)]: %v", prod_component, hostIP, err)
- }
- defer sshClient.Close()
- postCheck(sshClient, configJson, prod_component, hostIP)
- // Mark as done
- ch <- sshChan{
- name: hostIP,
- }
- }
- // 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 {
- // 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 --header \"Host: " + arrowdb_url_prefix + "." + domain_name + "\" " + hostIP + ":7000/ping.json"
- var expected = "\"ping\": \"ok\""
- runCurl(sshClient, curl, product, componentName, hostIP, expected)
- case "log_aggregator":
- case "app_haproxy":
- curl := "curl --header \"Host: " + arrowdb_url_prefix + "." + domain_name + "\" " + hostIP + "/v1/admins/ping.json"
- var expected = "\"status\":\"ok\""
- runCurl(sshClient, curl, product, componentName, hostIP, expected)
- case "admin_haproxy":
- curl := "curl --header \"Host: " + arrowdb_url_prefix + "." + domain_name + "\" " + hostIP + "/v1/admins/ping.json"
- var expected = "\"status\":\"ok\""
- runCurl(sshClient, curl, product, componentName, hostIP, expected)
- case "admin":
- case "docker_registry":
- case "container_node":
- curl := "curl --header \"Host: " + arrowdb_url_prefix + "." + domain_name + "\" " + hostIP + ":9090/ping"
- containerSession, _ := sshClient.NewSession()
- out, _ := containerSession.Output(curl)
- result := string(out[:])
- defer containerSession.Close()
- var expected = "\"success\": true"
- compareOutput(result, curl, product, componentName, hostIP, expected)
- default:
- log.Error("the hosts are unreadable")
- return false
- }
- case "arrow_db":
- switch componentName {
- case "api":
- urlSession, _ := sshClient.NewSession()
- if err := urlSession.Run("curl " + hostIP + ":8083"); err != nil {
- fmt.Println("error")
- }
- defer urlSession.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")
- }
- urlSession, _ := sshClient.NewSession()
- if err := urlSession.Run("curl " + hostIP + ":8083"); err != nil {
- fmt.Println("error")
- }
- defer urlSession.Close()
- case "admin":
- case "haproxy":
- curl := "curl --header \"Host: " + arrowdb_url_prefix + "." + domain_name + "\" " + hostIP + "/v1/admins/ping.json"
- var expected = "\"status\":\"ok\""
- runCurl(sshClient, curl, product, componentName, hostIP, expected)
- case "push":
- default:
- log.Println("the hosts are unreadable")
- return false
- }
- }
- return true
- }
- // 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) {
- result := ""
- // Check if the ssh.Client is not nil
- if sshClient != nil {
- curlSession, _ := sshClient.NewSession()
- out, _ := curlSession.Output(curl)
- result = string(out[:])
- if result == "" {
- log.Error("cannot curl : " + curl)
- }
- 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)
- }
- }
- /**
- 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(configJson *gabs.Container) *gabs.Container {
- dbUsername, _ := configJson.Path("user_input.mongodb.username").Data().(string)
- dbPassword, _ := configJson.Path("user_input.mongodb.password").Data().(string)
- var mongoHosts []string
- helper.ExtractStringArray(&mongoHosts, configJson, "user_input.mongodb.hosts")
- 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
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement