Skip to content

Commit 681e227

Browse files
authored
Merge pull request #192 from hossted/sdomain
set domain cmd updates
2 parents 4529393 + c9f4910 commit 681e227

6 files changed

Lines changed: 154 additions & 55 deletions

File tree

hossted/request.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package hossted
33
import (
44
"crypto/tls"
55
"fmt"
6-
"io/ioutil"
6+
"io"
77
"net/http"
88
"net/url"
99
)
@@ -54,7 +54,7 @@ func (h *HosstedRequest) SendRequest() (string, error) {
5454
}
5555
defer resp.Body.Close()
5656

57-
body, err := ioutil.ReadAll(resp.Body)
57+
body, err := io.ReadAll(resp.Body)
5858
if err != nil {
5959
return "", err
6060
}

hossted/service/common/common.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,6 @@ func HttpRequest(method, url, token string, body []byte) error {
6161
Message interface{} `json:"message"`
6262
}
6363

64-
if resp.StatusCode != 200 {
65-
return fmt.Errorf("rrror sending event, errcode: %d", resp.StatusCode)
66-
}
67-
6864
respBody, err := io.ReadAll(resp.Body)
6965
if err != nil {
7066
return err
@@ -76,6 +72,10 @@ func HttpRequest(method, url, token string, body []byte) error {
7672
return err
7773
}
7874

75+
if resp.StatusCode != 200 {
76+
return fmt.Errorf("error sending event, errcode: %d, msg: %s", resp.StatusCode, apiResponse.Message)
77+
}
78+
7979
if !apiResponse.Success {
8080
return fmt.Errorf("api response indicates failure: %v", apiResponse)
8181
}

hossted/service/compose/reconcile_compose.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,10 @@ func writeComposeRequest2File(
178178
return isComposeStateChange, nil
179179
}
180180

181-
type optionsState struct {
182-
Monitoring bool `json:"monitoring"`
183-
Logging bool `json:"logging"`
184-
CVEScan bool `json:"cve_scan"`
181+
type OptionsState struct {
182+
Monitoring bool `json:"monitoring,omitempty"`
183+
Logging bool `json:"logging,omitempty"`
184+
CVEScan bool `json:"cve_scan,omitempty"`
185185
}
186186

187187
type URLInfo struct {
@@ -194,7 +194,7 @@ type AccessInfo struct {
194194
URLs []URLInfo `json:"urls"`
195195
}
196196

197-
type request struct {
197+
type Request struct {
198198
UUID string `json:"uuid"`
199199
OsUUID string `json:"osuuid"`
200200
OrgID string `json:"org_id"`
@@ -203,7 +203,7 @@ type request struct {
203203
Product string `json:"product,omitempty"`
204204
CPUNum string `json:"cpunum,omitempty"`
205205
Memory string `json:"memory,omitempty"`
206-
OptionsState optionsState `json:"options_state"`
206+
OptionsState OptionsState `json:"options_state,omitempty"`
207207
ComposeFile string `json:"compose_file,omitempty"`
208208
AccessInfo AccessInfo `json:"access_info,omitempty"`
209209
}
@@ -238,7 +238,7 @@ func sendComposeInfo(appFilePath string, osInfo OsInfo) error {
238238
return err
239239
}
240240

241-
accessInfo := getAccessInfo("/opt/" + projectName + "/.env")
241+
accessInfo := GetAccessInfo("/opt/" + projectName + "/.env")
242242

243243
var data map[string]AppRequest
244244
if err = json.Unmarshal(composeInfo, &data); err != nil {
@@ -276,7 +276,7 @@ func sendComposeInfo(appFilePath string, osInfo OsInfo) error {
276276
// registerApplications registers all applications with the specified API URL.
277277
func registerApplications(data map[string]AppRequest, osInfo OsInfo, accessInfo AccessInfo, cpu, mem, orgID, token, composeUrl string) error {
278278
for appName, compose := range data {
279-
newReq := request{
279+
newReq := Request{
280280
UUID: compose.AppAPIInfo.AppUUID,
281281
OsUUID: compose.AppAPIInfo.OsUUID,
282282
Email: compose.AppAPIInfo.EmailID,
@@ -286,15 +286,15 @@ func registerApplications(data map[string]AppRequest, osInfo OsInfo, accessInfo
286286
Product: appName,
287287
CPUNum: cpu,
288288
Memory: mem,
289-
OptionsState: optionsState{
289+
OptionsState: OptionsState{
290290
Monitoring: true,
291291
Logging: true,
292292
CVEScan: true,
293293
},
294294
ComposeFile: compose.AppInfo.ComposeFile,
295295
}
296296

297-
if err := sendRequest("POST", composeUrl, token, newReq); err != nil {
297+
if err := SendRequest("POST", composeUrl, token, newReq); err != nil {
298298
return err
299299
}
300300
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
325325
CreatedAt: ci.CreatedAt,
326326
}
327327

328-
if err := sendRequest("POST", containersUrl, token, newDI); err != nil {
328+
if err := SendRequest("POST", containersUrl, token, newDI); err != nil {
329329
return err
330330
}
331331

@@ -345,7 +345,7 @@ func submitPatchRequest(osInfo OsInfo, compose map[string]AppRequest, accessInfo
345345
applicationName = appName
346346
}
347347

348-
newReq := request{
348+
newReq := Request{
349349
UUID: osInfo.AppUUID,
350350
OsUUID: osInfo.OsUUID,
351351
AccessInfo: accessInfo,
@@ -354,19 +354,19 @@ func submitPatchRequest(osInfo OsInfo, compose map[string]AppRequest, accessInfo
354354
Product: applicationName,
355355
CPUNum: cpu,
356356
Memory: mem,
357-
OptionsState: optionsState{
357+
OptionsState: OptionsState{
358358
Monitoring: true,
359359
Logging: true,
360360
CVEScan: false,
361361
},
362362
ComposeFile: composeFile,
363363
}
364364

365-
return sendRequest(http.MethodPatch, composeUrl, osInfo.Token, newReq)
365+
return SendRequest(http.MethodPatch, composeUrl, osInfo.Token, newReq)
366366
}
367367

368368
// sendRequest handles HTTP requests for a given method, URL, token, and request body.
369-
func sendRequest(method, url, token string, reqBody interface{}) error {
369+
func SendRequest(method, url, token string, reqBody interface{}) error {
370370
body, err := json.Marshal(reqBody)
371371
if err != nil {
372372
return fmt.Errorf("failed to marshal JSON: %v", err)
@@ -705,7 +705,7 @@ func runMonitoringCompose(monitoringEnable, osUUID, appUUID string) error {
705705
return nil
706706
}
707707

708-
func getAccessInfo(filepath string) *AccessInfo {
708+
func GetAccessInfo(filepath string) *AccessInfo {
709709
file, err := os.Open(filepath)
710710
if err != nil {
711711
return &AccessInfo{}

hossted/setDomain.go

Lines changed: 130 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ import (
55
"errors"
66
"fmt"
77
"log"
8+
"net/http"
89
"os"
910
"os/exec"
1011
"path/filepath"
1112
"regexp"
1213
"strings"
1314

15+
"github.com/hossted/cli/hossted/service/compose"
1416
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1517
"k8s.io/client-go/kubernetes"
1618
"k8s.io/client-go/tools/clientcmd"
@@ -82,6 +84,12 @@ func SetDomain(env, app, domain string) error {
8284
fmt.Println("Hossted Platform Domain set successfully")
8385

8486
} else {
87+
88+
err = CheckHosstedAuthFiles()
89+
if err != nil {
90+
fmt.Println("Please run hossted activate -t compose, to activate the vm")
91+
os.Exit(1)
92+
}
8593
if !HasContainerRunning() {
8694
fmt.Println("The application still in configuration")
8795
os.Exit(0)
@@ -94,23 +102,18 @@ func SetDomain(env, app, domain string) error {
94102
return fmt.Errorf("\n\n%w", err)
95103
}
96104

97-
err = AddDomainToMotd(domain)
105+
err = ChangeMOTD(domain)
98106
if err != nil {
99107
return err
100108
}
101109

102110
check := verifyInputFormat(domain, "domain")
103111
if !check {
104-
return fmt.Errorf("Invalid domain input. Expecting domain name (e.g. example.com).\nInput - %s\n", domain)
112+
return fmt.Errorf("invalid domain input. Expecting domain name (e.g. example.com). input - %s", domain)
105113
}
106114

107-
// Get .env file and appDir
108-
appConfig, err := config.GetAppConfig(app)
109-
if err != nil {
110-
return err
111-
}
112-
appDir := appConfig.AppPath
113-
envPath, err := getAppFilePath(appConfig.AppPath, ".env")
115+
appDir := "/opt/" + app
116+
envPath, err := getAppFilePath(appDir, ".env")
114117
if err != nil {
115118
return err
116119
}
@@ -149,45 +152,143 @@ func SetDomain(env, app, domain string) error {
149152
typeActivity := "set_domain"
150153

151154
sendActivityLog(env, uuid, fullCommand, options, typeActivity)
155+
156+
osInfo, err := compose.GetClusterInfo()
157+
if err != nil {
158+
return fmt.Errorf("error getting cluster info %s", err)
159+
}
160+
161+
projectName, err := getProjectName()
162+
if err != nil {
163+
return fmt.Errorf("error getting project name %s", err)
164+
}
165+
166+
accessInfo := compose.GetAccessInfo("/opt/" + projectName + "/.env")
167+
168+
err = submitPatchRequest(osInfo, *accessInfo)
169+
if err != nil {
170+
return fmt.Errorf("error submitting patch request %v", err)
171+
}
172+
152173
return nil
153174
}
154175
return nil
155176
}
156177

157-
// ChangeMOTD changes the content of the MOTD file, to match the set domain changes
158-
// TODO: print status
159-
// TODO: Allow domain to be something other than .com by changing the regex patten
160-
func ChangeMOTD(domain string) error {
178+
// submitPatchRequest sends a PATCH request with VM info for marketplace setups.
179+
func submitPatchRequest(osInfo compose.OsInfo, accessInfo compose.AccessInfo) error {
180+
composeUrl := osInfo.HosstedApiUrl + "/compose/hosts/" + osInfo.OsUUID
181+
182+
type req struct {
183+
UUID string `json:"uuid"` // Application UUID
184+
OsUUID string `json:"osuuid"` // Operating System UUID
185+
AccessInfo compose.AccessInfo `json:"access_info"` // Access information for the VM
186+
Type string `json:"type"` // Type of the request, e.g., "vm"
187+
}
161188

189+
newReq := req{
190+
UUID: osInfo.AppUUID,
191+
OsUUID: osInfo.OsUUID,
192+
AccessInfo: accessInfo,
193+
Type: "vm",
194+
}
195+
196+
return compose.SendRequest(http.MethodPatch, composeUrl, osInfo.Token, newReq)
197+
}
198+
199+
func ChangeMOTD(domain string) error {
162200
filepath := "/etc/motd"
201+
202+
// Read the file
163203
b, err := readProtected(filepath)
164204
if err != nil {
165-
return fmt.Errorf("Can't read the /etc/motd file. Please check - %s and contact administrator.\n%w\n", filepath, err)
205+
return fmt.Errorf("unable to read the /etc/motd file. Please check %s and contact administrator: %w", filepath, err)
166206
}
167207
content := string(b)
168208

169-
// Currently only .com is supported. Looking for line like
170-
// Your ^[[01;32mgitbucket^[[0m is available under ^[[01;34m http://3.215.23.221.c.hossted.com ^[[0m
171-
re, err := regexp.Compile(`(.*available under\s*.*https?:\/\/)(.*\.com)(.*)`)
209+
// Match and update any URL that starts with https:// followed by a domain
210+
re := regexp.MustCompile(`https://[\w\.\-]+\.\w+`)
211+
updatedContent := re.ReplaceAllString(content, fmt.Sprintf("https://%s", domain))
212+
213+
if updatedContent == content {
214+
return errors.New("no matching pattern found in /etc/motd. Please ensure the content is formatted correctly")
215+
}
216+
217+
// Write the updated content back to the file
218+
err = writeProtected(filepath, []byte(updatedContent))
172219
if err != nil {
173-
return err
220+
return fmt.Errorf("failed to write to the /etc/motd file: %w", err)
174221
}
175222

176-
matches := re.FindAllStringSubmatch(content, -1)
177-
if len(matches) > 0 {
178-
if len(matches[0]) == 4 {
179-
new := matches[0][1] + domain + matches[0][3]
180-
content = strings.Replace(content, matches[0][0], new, 1) // Replace the containing new with new string
181-
}
223+
return nil
224+
}
225+
226+
// CheckHosstedAuthFiles checks if the files ~/.hossted/auth.json and ~/.hossted/authresp.json exist.
227+
func CheckHosstedAuthFiles() error {
228+
// Get the home directory
229+
homeDir, err := os.UserHomeDir()
230+
if err != nil {
231+
return fmt.Errorf("failed to get home directory: %w", err)
232+
}
233+
234+
// Define the file paths
235+
authFilePath := filepath.Join(homeDir, ".hossted", "auth.json")
236+
authRespFilePath := filepath.Join(homeDir, ".hossted", "authresp.json")
237+
238+
// Check if auth.json exists
239+
if _, err := os.Stat(authFilePath); os.IsNotExist(err) {
240+
return fmt.Errorf("file %s does not exist", authFilePath)
241+
}
242+
243+
// Check if authresp.json exists
244+
if _, err := os.Stat(authRespFilePath); os.IsNotExist(err) {
245+
return fmt.Errorf("file %s does not exist", authRespFilePath)
246+
}
247+
248+
// Both files exist
249+
return nil
250+
}
251+
252+
func getSoftwarePath() (string, error) {
253+
path := "/opt/hossted/run/software.txt"
254+
if _, err := os.Stat(path); os.IsNotExist(err) {
255+
return "", nil
182256
} else {
183-
return errors.New("No matching pattern in /etc/motd. Please check.\n")
257+
return path, nil
184258
}
185259

186-
// Write back to file
187-
err = writeProtected(filepath, []byte(content))
260+
}
261+
262+
func getProjectName() (string, error) {
263+
path, err := getSoftwarePath()
188264
if err != nil {
189-
return err
265+
fmt.Println("Error getting software path", err)
190266
}
191267

192-
return nil
268+
// its a market place VM, access info object will exist
269+
if path == "/opt/hossted/run/software.txt" {
270+
// read the file in this path
271+
// file will have this convention - Linnovate-AWS-keycloak
272+
// capture the last word ie keycloak in this case.
273+
// and use this last work ie instead of osInfo.ProjectName
274+
data, err := os.ReadFile(path)
275+
if err != nil {
276+
fmt.Println("Error reading file:", err)
277+
return "", err
278+
}
279+
280+
// The file will have the convention Linnovate-AWS-keycloak
281+
// Capture the last word (i.e., keycloak in this case)
282+
softwareName := strings.TrimSpace(string(data))
283+
words := strings.Split(softwareName, "-")
284+
if len(words) > 0 {
285+
projectName := words[len(words)-1]
286+
// Use this last word (i.e., keycloak) instead of osInfo.ProjectName
287+
return projectName, nil
288+
}
289+
} else if path == "" {
290+
fmt.Println("Contact Hossted support to add Access Info object")
291+
return "", nil
292+
}
293+
return "", nil
193294
}

hossted/structMethod.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func (c *Config) GetAppConfig(in string) (ConfigApplication, error) {
1818
}
1919
// Check if any matched
2020
if ca.AppName == "" {
21-
return ca, fmt.Errorf("No Config found for app - %s", in)
21+
return ca, fmt.Errorf("no config found for app - %s", in)
2222
}
2323
return ca, nil
2424
}

0 commit comments

Comments
 (0)