@@ -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).\n Input - %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}
0 commit comments