<commit_before>package saltboot

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/sequenceiq/salt-bootstrap/saltboot/model"
	"gopkg.in/yaml.v2"
)

type SaltActionRequest struct {
	Master  SaltMaster   `json:"master,omitempty"`
	Minions []SaltMinion `json:"minions,omitempty"`
	Action  string       `json:"action"`
}

type SaltAuth struct {
	Password string `json:"password,omitempty"`
}

type SaltMaster struct {
	Address string     `json:"address"`
	Auth    SaltAuth   `json:"auth,omitempty"`
}

type SaltMinion struct {
	Address   string   `json:"address"`
	Roles     []string `json:"roles,omitempty"`
	Server    string   `json:"server,omitempty"`
	HostGroup string   `json:"hostGroup,omitempty"`
}

type SaltPillar struct {
	Path string                 `json:"path"`
	Json map[string]interface{} `json:"json"`
}

func (saltMinion SaltMinion) AsByteArray() []byte {
	b, _ := json.Marshal(saltMinion)
	return b
}

func (saltMaster SaltMaster) AsByteArray() []byte {
	b, _ := json.Marshal(saltMaster)
	return b
}

type GrainConfig struct {
	HostGroup string   `json:"hostgroup" yaml:"hostgroup"`
	Roles     []string `json:"roles" yaml:"roles"`
}

func (r SaltActionRequest) String() string {
	b, _ := json.Marshal(r)
	return fmt.Sprintf(string(b))
}

func (r SaltActionRequest) distributeAction(user string, pass string) (result []model.Response) {
	log.Printf("[distributeAction] distribute salt state command to targets: %s", r.String())

	var targets []string
	var minionPayload []Payload
	for _, minion := range r.Minions {
		targets = append(targets, minion.Address)
		if minion.Server == "" {
			minion.Server = r.Master.Address
		}
		minionPayload = append(minionPayload, minion)
	}

	for res := range DistributePayload(targets, minionPayload, SaltMinionEp + "/" + r.Action, user, pass) {
		result = append(result, res)
	}
	if len(r.Master.Address) > 0 {
		result = append(result, <-DistributePayload([]string{r.Master.Address}, []Payload{r.Master}, SaltServerEp + "/" + r.Action, user, pass))
	}
	return result
}

func SaltMinionRunRequestHandler(w http.ResponseWriter, req *http.Request) {
	log.Printf("[SaltMinionRunRequestHandler] execute salt run request")

	decoder := json.NewDecoder(req.Body)
	var saltMinion SaltMinion
	err := decoder.Decode(&saltMinion)
	if err != nil {
		log.Printf("[SaltMinionRunRequestHandler] [ERROR] couldn't decode json: %s", err)
		model.Response{Status: err.Error()}.WriteBadRequestHttp(w)
		return
	}

	grainConfig := GrainConfig{Roles: saltMinion.Roles, HostGroup: saltMinion.HostGroup}
	grainYaml, err := yaml.Marshal(grainConfig)
	var resp model.Response
	if err != nil {
		resp = model.Response{ErrorText: err.Error(), StatusCode: http.StatusInternalServerError}
		resp.WriteHttp(w)
		return
	}

	err = os.MkdirAll("/etc/salt/minion.d", 0755)
	if err != nil {
		resp = model.Response{ErrorText: err.Error(), StatusCode: http.StatusInternalServerError}
		resp.WriteHttp(w)
		return
	}

	masterConf := []byte("master: " + saltMinion.Server)
	err = ioutil.WriteFile("/etc/salt/minion.d/master.conf", masterConf, 0644)
	if err != nil {
		resp = model.Response{ErrorText: err.Error(), StatusCode: http.StatusInternalServerError}
		resp.WriteHttp(w)
		return
	}

	err = ioutil.WriteFile("/etc/salt/grains", grainYaml, 0644)
	if err != nil {
		resp = model.Response{ErrorText: err.Error(), StatusCode: http.StatusInternalServerError}
		resp.WriteHttp(w)
		return
	}
	resp, _ = LaunchService("salt-minion")
	resp.WriteHttp(w)
}

func SaltMinionStopRequestHandler(w http.ResponseWriter, req *http.Request) {
	log.Printf("[SaltMinionStopRequestHandler] execute salt minion stop request")

	decoder := json.NewDecoder(req.Body)
	var saltMinion SaltMinion
	err := decoder.Decode(&saltMinion)
	if err != nil {
		log.Printf("[SaltMinionRunRequestHandler] [ERROR] couldn't decode json: %s", err)
		model.Response{Status: err.Error()}.WriteBadRequestHttp(w)
		return
	}
<commit_msg>CLOUD-67234 Sysv scripts starts the salt minion twice<commit_after>package saltboot

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/sequenceiq/salt-bootstrap/saltboot/model"
	"gopkg.in/yaml.v2"
)

type SaltActionRequest struct {
	Master  SaltMaster   `json:"master,omitempty"`
	Minions []SaltMinion `json:"minions,omitempty"`
	Action  string       `json:"action"`
}

type SaltAuth struct {
	Password string `json:"password,omitempty"`
}

type SaltMaster struct {
	Address string     `json:"address"`
	Auth    SaltAuth   `json:"auth,omitempty"`
}

type SaltMinion struct {
	Address   string   `json:"address"`
	Roles     []string `json:"roles,omitempty"`
	Server    string   `json:"server,omitempty"`
	HostGroup string   `json:"hostGroup,omitempty"`
}

type SaltPillar struct {
	Path string                 `json:"path"`
	Json map[string]interface{} `json:"json"`
}

func (saltMinion SaltMinion) AsByteArray() []byte {
	b, _ := json.Marshal(saltMinion)
	return b
}

func (saltMaster SaltMaster) AsByteArray() []byte {
	b, _ := json.Marshal(saltMaster)
	return b
}

type GrainConfig struct {
	HostGroup string   `json:"hostgroup" yaml:"hostgroup"`
	Roles     []string `json:"roles" yaml:"roles"`
}

func (r SaltActionRequest) String() string {
	b, _ := json.Marshal(r)
	return fmt.Sprintf(string(b))
}

func (r SaltActionRequest) distributeAction(user string, pass string) (result []model.Response) {
	log.Printf("[distributeAction] distribute salt state command to targets: %s", r.String())

	var targets []string
	var minionPayload []Payload
	for _, minion := range r.Minions {
		targets = append(targets, minion.Address)
		if minion.Server == "" {
			minion.Server = r.Master.Address
		}
		minionPayload = append(minionPayload, minion)
	}

	for res := range DistributePayload(targets, minionPayload, SaltMinionEp + "/" + r.Action, user, pass) {
		result = append(result, res)
	}
	if len(r.Master.Address) > 0 {
		result = append(result, <-DistributePayload([]string{r.Master.Address}, []Payload{r.Master}, SaltServerEp + "/" + r.Action, user, pass))
	}
	return result
}

func SaltMinionRunRequestHandler(w http.ResponseWriter, req *http.Request) {
	log.Printf("[SaltMinionRunRequestHandler] execute salt-minion run request")

	decoder := json.NewDecoder(req.Body)
	var saltMinion SaltMinion
	err := decoder.Decode(&saltMinion)
	if err != nil {
		log.Printf("[SaltMinionRunRequestHandler] [ERROR] couldn't decode json: %s", err)
		model.Response{Status: err.Error()}.WriteBadRequestHttp(w)
		return
	}
	log.Printf("[SaltMinionRunRequestHandler] received json: %s", saltMinion.AsByteArray())

	grainConfig := GrainConfig{Roles: saltMinion.Roles, HostGroup: saltMinion.HostGroup}
	grainYaml, err := yaml.Marshal(grainConfig)
	var resp model.Response
	if err != nil {
		resp = model.Response{ErrorText: err.Error(), StatusCode: http.StatusInternalServerError}
		resp.WriteHttp(w)
		return
	}

	err = os.MkdirAll("/etc/salt/minion.d", 0755)
	if err != nil {
		resp = model.Response{ErrorText: err.Error(), StatusCode: http.StatusInternalServerError}
		resp.WriteHttp(w)
		return
	}

	masterConf := []byte("master: " + saltMinion.Server)
	err = ioutil.WriteFile("/etc/salt/minion.d/master.conf", masterConf, 0644)
	if err != nil {
		resp = model.Response{ErrorText: err.Error(), StatusCode: http.StatusInternalServerError}
		resp.WriteHttp(w)
		return
	}

	err = ioutil.WriteFile("/etc/salt/grains", grainYaml, 0644)
	if err != nil {
		resp = model.Response{ErrorText: err.Error(), StatusCode: http.StatusInternalServerError}
		resp.WriteHttp(w)
		return
	}
	psOutput, err := ExecCmd("ps", "aux")
	alreadyRunning := strings.Contains(psOutput, "salt-minion")

	if alreadyRunning {
		log.Printf("[SaltMinionRunRequestHandler] salt-minion is already running %s", psOutput)
		resp = model.Response{StatusCode: http.StatusOK, Status: "salt-minion already running"}
		resp.WriteHttp(w)
		return
	} else {
		log.Printf("[SaltMinionRunRequestHandler] salt-minion is not running and will be started")
	}
	resp, _ = LaunchService("salt-minion")
	log.Printf("[SaltMinionRunRequestHandler] execute salt-minion run request")
	resp.WriteHttp(w)
}

func SaltMinionStopRequestHandler(w http.ResponseWriter, req *http.Request) {
	log.Printf("[SaltMinionStopRequestHandler] execute salt-minion stop request")

	decoder := json.NewDecoder(req.Body)
	var saltMinion SaltMinion
	err := decoder.Decode(&saltMinion)
	if err != nil {
		log.Printf("[SaltMinionRunRequestHandler] [ERROR] couldn't decode json: %s", err)
		model.Response{Status: err.Error()}.WriteBadRequestHttp(w)
		return
	}
	log.Printf("[SaltMinionRunRequestHandler] received json: %s", saltMinion.AsByteArray())

{'fraction_non_alphanumeric': 0.1371666089366124, 'fraction_numerical': 0.0038101835815725666, 'mean_word_length': 4.957359009628611, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4898318', 'n_tokens_mistral': 3063, 'n_tokens_neox': 2917, 'n_words': 642}