From 7591bff9ff998bbc2be32672972cc6777f05ec3c Mon Sep 17 00:00:00 2001 From: AdheipSingh Date: Wed, 15 Jan 2025 16:41:03 +0530 Subject: [PATCH 1/6] add set domain --- hossted/utils.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/hossted/utils.go b/hossted/utils.go index 92eaad9..dfecf00 100644 --- a/hossted/utils.go +++ b/hossted/utils.go @@ -394,15 +394,22 @@ func stopTraefik(appDir string) error { fmt.Println("traefik stopeed") return nil } + func dockerUp(appDir string) error { fmt.Println("Restarting service...") - command := []string{"sudo docker compose up -d"} - err, _, stderr := Shell(appDir, command) + // Construct the docker compose command + cmd := exec.Command("sudo", "docker", "compose", "up", "-d") + cmd.Dir = appDir // Set the working directory for the command + + // Run the command and capture stdout and stderr + output, err := cmd.CombinedOutput() if err != nil { - return err + return fmt.Errorf("error running docker compose: %v\nOutput: %s", err, string(output)) } - fmt.Println(trimOutput(stderr)) + + // Print the trimmed output for debugging + fmt.Println(string(output)) return nil } From 87eda762cbf20d622ab64a87a52d4f647993fbd1 Mon Sep 17 00:00:00 2001 From: AdheipSingh Date: Wed, 15 Jan 2025 18:20:31 +0530 Subject: [PATCH 2/6] update utils --- hossted/utils.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/hossted/utils.go b/hossted/utils.go index dfecf00..8c81bbc 100644 --- a/hossted/utils.go +++ b/hossted/utils.go @@ -385,13 +385,19 @@ func PrettyPrint(i interface{}) string { func stopTraefik(appDir string) error { fmt.Println("Stopping traefik...") - command := []string{"sudo docker compose down"} - err, _, stderr := Shell(appDir, command) + // Construct the docker compose down command + cmd := exec.Command("sudo", "docker", "compose", "down") + cmd.Dir = appDir // Set the working directory for the command + + // Run the command and capture stdout and stderr + output, err := cmd.CombinedOutput() if err != nil { - return err + return fmt.Errorf("error stopping traefik: %v\nOutput: %s", err, string(output)) } - fmt.Println(trimOutput(stderr)) - fmt.Println("traefik stopeed") + + // Print the trimmed output for debugging + fmt.Println(string(output)) + fmt.Println("Traefik stopped") return nil } From fdd287cd322c80bfb2ba72edc7c8b6948beacfd1 Mon Sep 17 00:00:00 2001 From: AdheipSingh Date: Wed, 15 Jan 2025 19:10:04 +0530 Subject: [PATCH 3/6] update utils --- hossted/utils.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hossted/utils.go b/hossted/utils.go index 8c81bbc..97761b7 100644 --- a/hossted/utils.go +++ b/hossted/utils.go @@ -588,7 +588,7 @@ func sendActivityLog(env, uuid, fullCommand, options, typeActivity string) (acti user, err := user.Current() if err != nil { - log.Fatalf(err.Error()) + log.Fatalf("%s", err.Error()) } userName := user.Username @@ -618,10 +618,10 @@ func sendActivityLog(env, uuid, fullCommand, options, typeActivity string) (acti err = json.Unmarshal([]byte(resp), &response) if err != nil { - return response, fmt.Errorf("Failed to parse JSON. %w", err) + return response, fmt.Errorf("failed to parse JSON. %w", err) } - //fmt.Printf("%v \n", response.Message) + fmt.Printf("calling to activity log api %s\n", response.Message) return response, nil } From 73b27b304aced158d60b2705f36a35e04690042a Mon Sep 17 00:00:00 2001 From: AdheipSingh Date: Mon, 20 Jan 2025 08:03:33 +0530 Subject: [PATCH 4/6] update set domain command --- hossted/request.go | 1 + hossted/setDomain.go | 77 ++++++++++++++++++++++++----------------- hossted/structMethod.go | 2 +- hossted/utils.go | 4 +-- 4 files changed, 49 insertions(+), 35 deletions(-) diff --git a/hossted/request.go b/hossted/request.go index 1d34a4e..f946234 100644 --- a/hossted/request.go +++ b/hossted/request.go @@ -63,5 +63,6 @@ func (h *HosstedRequest) SendRequest() (string, error) { return "", fmt.Errorf("HTTP Status is not 200. %s", string(body)) } + fmt.Println(string(body)) return string(body), nil } diff --git a/hossted/setDomain.go b/hossted/setDomain.go index e0572ef..0691b82 100644 --- a/hossted/setDomain.go +++ b/hossted/setDomain.go @@ -9,7 +9,6 @@ import ( "os/exec" "path/filepath" "regexp" - "strings" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" @@ -82,6 +81,12 @@ func SetDomain(env, app, domain string) error { fmt.Println("Hossted Platform Domain set successfully") } else { + + err = CheckHosstedAuthFiles() + if err != nil { + fmt.Println("Please run hossted activate -t compose, to activate the vm") + os.Exit(1) + } if !HasContainerRunning() { fmt.Println("The application still in configuration") os.Exit(0) @@ -94,23 +99,18 @@ func SetDomain(env, app, domain string) error { return fmt.Errorf("\n\n%w", err) } - err = AddDomainToMotd(domain) + err = ChangeMOTD(domain) if err != nil { return err } check := verifyInputFormat(domain, "domain") if !check { - return fmt.Errorf("Invalid domain input. Expecting domain name (e.g. example.com).\nInput - %s\n", domain) + return fmt.Errorf("invalid domain input. Expecting domain name (e.g. example.com). input - %s", domain) } - // Get .env file and appDir - appConfig, err := config.GetAppConfig(app) - if err != nil { - return err - } - appDir := appConfig.AppPath - envPath, err := getAppFilePath(appConfig.AppPath, ".env") + appDir := "/opt/" + app + envPath, err := getAppFilePath(appDir, ".env") if err != nil { return err } @@ -154,40 +154,55 @@ func SetDomain(env, app, domain string) error { return nil } -// ChangeMOTD changes the content of the MOTD file, to match the set domain changes -// TODO: print status -// TODO: Allow domain to be something other than .com by changing the regex patten func ChangeMOTD(domain string) error { - filepath := "/etc/motd" + + // Read the file b, err := readProtected(filepath) if err != nil { - return fmt.Errorf("Can't read the /etc/motd file. Please check - %s and contact administrator.\n%w\n", filepath, err) + return fmt.Errorf("unable to read the /etc/motd file. Please check %s and contact administrator: %w", filepath, err) } content := string(b) - // Currently only .com is supported. Looking for line like - // Your ^[[01;32mgitbucket^[[0m is available under ^[[01;34m http://3.215.23.221.c.hossted.com ^[[0m - re, err := regexp.Compile(`(.*available under\s*.*https?:\/\/)(.*\.com)(.*)`) - if err != nil { - return err + // Match and update any URL that starts with https:// followed by a domain + re := regexp.MustCompile(`https://[\w\.\-]+\.\w+`) + updatedContent := re.ReplaceAllString(content, fmt.Sprintf("https://%s", domain)) + + if updatedContent == content { + return errors.New("no matching pattern found in /etc/motd. Please ensure the content is formatted correctly") } - matches := re.FindAllStringSubmatch(content, -1) - if len(matches) > 0 { - if len(matches[0]) == 4 { - new := matches[0][1] + domain + matches[0][3] - content = strings.Replace(content, matches[0][0], new, 1) // Replace the containing new with new string - } - } else { - return errors.New("No matching pattern in /etc/motd. Please check.\n") + // Write the updated content back to the file + err = writeProtected(filepath, []byte(updatedContent)) + if err != nil { + return fmt.Errorf("failed to write to the /etc/motd file: %w", err) } - // Write back to file - err = writeProtected(filepath, []byte(content)) + return nil +} + +// CheckHosstedAuthFiles checks if the files ~/.hossted/auth.json and ~/.hossted/authresp.json exist. +func CheckHosstedAuthFiles() error { + // Get the home directory + homeDir, err := os.UserHomeDir() if err != nil { - return err + return fmt.Errorf("failed to get home directory: %w", err) + } + + // Define the file paths + authFilePath := filepath.Join(homeDir, ".hossted", "auth.json") + authRespFilePath := filepath.Join(homeDir, ".hossted", "authresp.json") + + // Check if auth.json exists + if _, err := os.Stat(authFilePath); os.IsNotExist(err) { + return fmt.Errorf("file %s does not exist", authFilePath) + } + + // Check if authresp.json exists + if _, err := os.Stat(authRespFilePath); os.IsNotExist(err) { + return fmt.Errorf("file %s does not exist", authRespFilePath) } + // Both files exist return nil } diff --git a/hossted/structMethod.go b/hossted/structMethod.go index 884d373..ba433fe 100644 --- a/hossted/structMethod.go +++ b/hossted/structMethod.go @@ -18,7 +18,7 @@ func (c *Config) GetAppConfig(in string) (ConfigApplication, error) { } // Check if any matched if ca.AppName == "" { - return ca, fmt.Errorf("No Config found for app - %s", in) + return ca, fmt.Errorf("no config found for app - %s", in) } return ca, nil } diff --git a/hossted/utils.go b/hossted/utils.go index 97761b7..d2cf604 100644 --- a/hossted/utils.go +++ b/hossted/utils.go @@ -371,7 +371,7 @@ func writeProtected(path string, b []byte) error { func getAppFilePath(base, relative string) (string, error) { path := filepath.Join(base, relative) if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) { - return "", fmt.Errorf("File not exists. Please check. %w", err) + return "", fmt.Errorf("file not exists. please check. %w", err) } return path, nil } @@ -612,7 +612,6 @@ func sendActivityLog(env, uuid, fullCommand, options, typeActivity string) (acti resp, err := req.SendRequest() if err != nil { - fmt.Println("err", err) return response, err } @@ -621,7 +620,6 @@ func sendActivityLog(env, uuid, fullCommand, options, typeActivity string) (acti return response, fmt.Errorf("failed to parse JSON. %w", err) } - fmt.Printf("calling to activity log api %s\n", response.Message) return response, nil } From ddc888aa3ca1aeef6164186716ed64a4f2d256b7 Mon Sep 17 00:00:00 2001 From: AdheipSingh Date: Tue, 21 Jan 2025 15:24:54 +0530 Subject: [PATCH 5/6] update set domain --- hossted/service/common/common.go | 8 +- hossted/service/compose/reconcile_compose.go | 32 ++++---- hossted/setDomain.go | 86 ++++++++++++++++++++ 3 files changed, 106 insertions(+), 20 deletions(-) diff --git a/hossted/service/common/common.go b/hossted/service/common/common.go index 06da590..f812be0 100644 --- a/hossted/service/common/common.go +++ b/hossted/service/common/common.go @@ -61,10 +61,6 @@ func HttpRequest(method, url, token string, body []byte) error { Message interface{} `json:"message"` } - if resp.StatusCode != 200 { - return fmt.Errorf("rrror sending event, errcode: %d", resp.StatusCode) - } - respBody, err := io.ReadAll(resp.Body) if err != nil { return err @@ -76,6 +72,10 @@ func HttpRequest(method, url, token string, body []byte) error { return err } + if resp.StatusCode != 200 { + return fmt.Errorf("error sending event, errcode: %d, msg: %s", resp.StatusCode, apiResponse.Message) + } + if !apiResponse.Success { return fmt.Errorf("api response indicates failure: %v", apiResponse) } diff --git a/hossted/service/compose/reconcile_compose.go b/hossted/service/compose/reconcile_compose.go index 6da7c10..850c9a2 100644 --- a/hossted/service/compose/reconcile_compose.go +++ b/hossted/service/compose/reconcile_compose.go @@ -178,10 +178,10 @@ func writeComposeRequest2File( return isComposeStateChange, nil } -type optionsState struct { - Monitoring bool `json:"monitoring"` - Logging bool `json:"logging"` - CVEScan bool `json:"cve_scan"` +type OptionsState struct { + Monitoring bool `json:"monitoring,omitempty"` + Logging bool `json:"logging,omitempty"` + CVEScan bool `json:"cve_scan,omitempty"` } type URLInfo struct { @@ -194,7 +194,7 @@ type AccessInfo struct { URLs []URLInfo `json:"urls"` } -type request struct { +type Request struct { UUID string `json:"uuid"` OsUUID string `json:"osuuid"` OrgID string `json:"org_id"` @@ -203,7 +203,7 @@ type request struct { Product string `json:"product,omitempty"` CPUNum string `json:"cpunum,omitempty"` Memory string `json:"memory,omitempty"` - OptionsState optionsState `json:"options_state"` + OptionsState OptionsState `json:"options_state,omitempty"` ComposeFile string `json:"compose_file,omitempty"` AccessInfo AccessInfo `json:"access_info,omitempty"` } @@ -238,7 +238,7 @@ func sendComposeInfo(appFilePath string, osInfo OsInfo) error { return err } - accessInfo := getAccessInfo("/opt/" + projectName + "/.env") + accessInfo := GetAccessInfo("/opt/" + projectName + "/.env") var data map[string]AppRequest if err = json.Unmarshal(composeInfo, &data); err != nil { @@ -276,7 +276,7 @@ func sendComposeInfo(appFilePath string, osInfo OsInfo) error { // registerApplications registers all applications with the specified API URL. func registerApplications(data map[string]AppRequest, osInfo OsInfo, accessInfo AccessInfo, cpu, mem, orgID, token, composeUrl string) error { for appName, compose := range data { - newReq := request{ + newReq := Request{ UUID: compose.AppAPIInfo.AppUUID, OsUUID: compose.AppAPIInfo.OsUUID, Email: compose.AppAPIInfo.EmailID, @@ -286,7 +286,7 @@ func registerApplications(data map[string]AppRequest, osInfo OsInfo, accessInfo Product: appName, CPUNum: cpu, Memory: mem, - OptionsState: optionsState{ + OptionsState: OptionsState{ Monitoring: true, Logging: true, CVEScan: true, @@ -294,7 +294,7 @@ func registerApplications(data map[string]AppRequest, osInfo OsInfo, accessInfo ComposeFile: compose.AppInfo.ComposeFile, } - if err := sendRequest("POST", composeUrl, token, newReq); err != nil { + if err := SendRequest("POST", composeUrl, token, newReq); err != nil { return err } fmt.Printf("Successfully registered app [%s] with appID [%s]\n", appName, compose.AppAPIInfo.AppUUID) @@ -325,7 +325,7 @@ func registerDockerInstances(data map[string]AppRequest, osInfo OsInfo, token, c CreatedAt: ci.CreatedAt, } - if err := sendRequest("POST", containersUrl, token, newDI); err != nil { + if err := SendRequest("POST", containersUrl, token, newDI); err != nil { return err } @@ -345,7 +345,7 @@ func submitPatchRequest(osInfo OsInfo, compose map[string]AppRequest, accessInfo applicationName = appName } - newReq := request{ + newReq := Request{ UUID: osInfo.AppUUID, OsUUID: osInfo.OsUUID, AccessInfo: accessInfo, @@ -354,7 +354,7 @@ func submitPatchRequest(osInfo OsInfo, compose map[string]AppRequest, accessInfo Product: applicationName, CPUNum: cpu, Memory: mem, - OptionsState: optionsState{ + OptionsState: OptionsState{ Monitoring: true, Logging: true, CVEScan: false, @@ -362,11 +362,11 @@ func submitPatchRequest(osInfo OsInfo, compose map[string]AppRequest, accessInfo ComposeFile: composeFile, } - return sendRequest(http.MethodPatch, composeUrl, osInfo.Token, newReq) + return SendRequest(http.MethodPatch, composeUrl, osInfo.Token, newReq) } // sendRequest handles HTTP requests for a given method, URL, token, and request body. -func sendRequest(method, url, token string, reqBody interface{}) error { +func SendRequest(method, url, token string, reqBody interface{}) error { body, err := json.Marshal(reqBody) if err != nil { return fmt.Errorf("failed to marshal JSON: %v", err) @@ -705,7 +705,7 @@ func runMonitoringCompose(monitoringEnable, osUUID, appUUID string) error { return nil } -func getAccessInfo(filepath string) *AccessInfo { +func GetAccessInfo(filepath string) *AccessInfo { file, err := os.Open(filepath) if err != nil { return &AccessInfo{} diff --git a/hossted/setDomain.go b/hossted/setDomain.go index 0691b82..f718557 100644 --- a/hossted/setDomain.go +++ b/hossted/setDomain.go @@ -5,11 +5,14 @@ import ( "errors" "fmt" "log" + "net/http" "os" "os/exec" "path/filepath" "regexp" + "strings" + "github.com/hossted/cli/hossted/service/compose" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" @@ -149,11 +152,50 @@ func SetDomain(env, app, domain string) error { typeActivity := "set_domain" sendActivityLog(env, uuid, fullCommand, options, typeActivity) + + osInfo, err := compose.GetClusterInfo() + if err != nil { + return fmt.Errorf("error getting cluster info %s", err) + } + + projectName, err := getProjectName() + if err != nil { + return fmt.Errorf("error getting project name %s", err) + } + + accessInfo := compose.GetAccessInfo("/opt/" + projectName + "/.env") + + err = submitPatchRequest(osInfo, *accessInfo) + if err != nil { + return fmt.Errorf("error submitting patch request %v", err) + } + return nil } return nil } +// submitPatchRequest sends a PATCH request with VM info for marketplace setups. +func submitPatchRequest(osInfo compose.OsInfo, accessInfo compose.AccessInfo) error { + composeUrl := osInfo.HosstedApiUrl + "/compose/hosts/" + osInfo.OsUUID + + type req struct { + UUID string `json:"uuid"` // Application UUID + OsUUID string `json:"osuuid"` // Operating System UUID + AccessInfo compose.AccessInfo `json:"access_info"` // Access information for the VM + Type string `json:"type"` // Type of the request, e.g., "vm" + } + + newReq := req{ + UUID: osInfo.AppUUID, + OsUUID: osInfo.OsUUID, + AccessInfo: accessInfo, + Type: "vm", + } + + return compose.SendRequest(http.MethodPatch, composeUrl, osInfo.Token, newReq) +} + func ChangeMOTD(domain string) error { filepath := "/etc/motd" @@ -206,3 +248,47 @@ func CheckHosstedAuthFiles() error { // Both files exist return nil } + +func getSoftwarePath() (string, error) { + path := "/opt/hossted/run/software.txt" + if _, err := os.Stat(path); os.IsNotExist(err) { + return "", nil + } else { + return path, nil + } + +} + +func getProjectName() (string, error) { + path, err := getSoftwarePath() + if err != nil { + fmt.Println("Error getting software path", err) + } + + // its a market place VM, access info object will exist + if path == "/opt/hossted/run/software.txt" { + // read the file in this path + // file will have this convention - Linnovate-AWS-keycloak + // capture the last word ie keycloak in this case. + // and use this last work ie instead of osInfo.ProjectName + data, err := os.ReadFile(path) + if err != nil { + fmt.Println("Error reading file:", err) + return "", err + } + + // The file will have the convention Linnovate-AWS-keycloak + // Capture the last word (i.e., keycloak in this case) + softwareName := strings.TrimSpace(string(data)) + words := strings.Split(softwareName, "-") + if len(words) > 0 { + projectName := words[len(words)-1] + // Use this last word (i.e., keycloak) instead of osInfo.ProjectName + return projectName, nil + } + } else if path == "" { + fmt.Println("Contact Hossted support to add Access Info object") + return "", nil + } + return "", nil +} From c9f49101dfabcf32a0421a7e1b7133b917966e4b Mon Sep 17 00:00:00 2001 From: AdheipSingh Date: Tue, 21 Jan 2025 15:30:53 +0530 Subject: [PATCH 6/6] update request --- hossted/request.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hossted/request.go b/hossted/request.go index f946234..7f9c88c 100644 --- a/hossted/request.go +++ b/hossted/request.go @@ -3,7 +3,7 @@ package hossted import ( "crypto/tls" "fmt" - "io/ioutil" + "io" "net/http" "net/url" ) @@ -54,7 +54,7 @@ func (h *HosstedRequest) SendRequest() (string, error) { } defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { return "", err } @@ -63,6 +63,5 @@ func (h *HosstedRequest) SendRequest() (string, error) { return "", fmt.Errorf("HTTP Status is not 200. %s", string(body)) } - fmt.Println(string(body)) return string(body), nil }