2016-01-05 00:32:53 +01:00
package main
import (
2016-05-17 22:17:17 +02:00
"bufio"
2016-04-18 02:58:29 +02:00
"encoding/json"
2016-01-05 00:32:53 +01:00
"fmt"
2016-04-18 02:58:29 +02:00
"io/ioutil"
2017-02-23 00:21:49 +01:00
"net/http"
2016-04-18 02:58:29 +02:00
"os"
2016-04-24 20:11:43 +02:00
"path"
2016-04-18 02:58:29 +02:00
"strings"
2016-05-21 00:07:27 +02:00
"time"
2016-04-18 02:58:29 +02:00
2016-05-24 11:55:48 +02:00
"github.com/ansible-semaphore/semaphore/api"
"github.com/ansible-semaphore/semaphore/api/sockets"
"github.com/ansible-semaphore/semaphore/api/tasks"
2017-02-23 06:12:16 +01:00
"github.com/ansible-semaphore/semaphore/db"
2016-03-16 22:49:43 +01:00
"github.com/ansible-semaphore/semaphore/util"
2017-02-23 00:21:49 +01:00
"github.com/gorilla/handlers"
2016-04-30 09:52:33 +02:00
"golang.org/x/crypto/bcrypt"
2016-01-05 00:32:53 +01:00
)
func main ( ) {
2018-03-05 18:06:24 +01:00
util . ConfigInit ( )
2016-04-18 02:58:29 +02:00
if util . InteractiveSetup {
os . Exit ( doSetup ( ) )
}
2016-04-26 20:18:28 +02:00
if util . Upgrade {
2016-05-24 11:55:48 +02:00
if err := util . DoUpgrade ( util . Version ) ; err != nil {
2016-04-26 20:18:28 +02:00
panic ( err )
}
os . Exit ( 0 )
}
2016-01-05 00:32:53 +01:00
fmt . Printf ( "Semaphore %v\n" , util . Version )
fmt . Printf ( "Port %v\n" , util . Config . Port )
2016-04-18 02:58:29 +02:00
fmt . Printf ( "MySQL %v@%v %v\n" , util . Config . MySQL . Username , util . Config . MySQL . Hostname , util . Config . MySQL . DbName )
2016-04-07 14:49:34 +02:00
fmt . Printf ( "Tmp Path (projects home) %v\n" , util . Config . TmpPath )
2016-01-05 00:32:53 +01:00
2017-02-23 06:12:16 +01:00
if err := db . Connect ( ) ; err != nil {
2017-06-02 13:57:23 +02:00
fmt . Println ( "\n Have you run semaphore -setup?" )
2016-04-18 02:58:29 +02:00
panic ( err )
}
2017-02-23 06:12:16 +01:00
db . SetupDBLink ( )
defer db . Mysql . Db . Close ( )
2016-01-05 00:32:53 +01:00
2017-05-20 15:21:13 +02:00
if err := db . MigrateAll ( ) ; err != nil {
panic ( err )
}
// legacy
2016-01-05 00:32:53 +01:00
if util . Migration {
2017-05-20 15:21:13 +02:00
fmt . Println ( "\n DB migrations run on startup automatically" )
2016-01-05 00:32:53 +01:00
return
}
2016-04-02 14:40:07 +02:00
go sockets . StartWS ( )
2016-05-21 00:07:27 +02:00
go checkUpdates ( )
2016-04-04 15:44:34 +02:00
go tasks . StartRunner ( )
2016-01-05 00:32:53 +01:00
2017-02-23 00:21:49 +01:00
var router http . Handler = api . Route ( )
router = handlers . ProxyHeaders ( router )
http . Handle ( "/" , router )
http . ListenAndServe ( util . Config . Port , nil )
2016-01-05 00:32:53 +01:00
}
2016-04-18 02:58:29 +02:00
func doSetup ( ) int {
fmt . Print ( `
2016-04-30 09:52:33 +02:00
Hello ! You will now be guided through a setup to :
2016-04-18 02:58:29 +02:00
2016-04-30 09:52:33 +02:00
1. Set up configuration for a MySQL / MariaDB database
2016-04-30 14:28:47 +02:00
2. Set up a path for your playbooks ( auto - created )
3. Run database Migrations
2017-05-28 15:11:41 +02:00
4. Set up initial semaphore user & password
2016-04-18 02:58:29 +02:00
` )
var b [ ] byte
2016-04-30 14:28:47 +02:00
setup := util . NewConfig ( )
2016-05-23 21:29:38 +02:00
for {
2016-04-30 14:28:47 +02:00
setup . Scan ( )
2016-05-17 22:17:17 +02:00
setup . GenerateCookieSecrets ( )
2016-04-30 14:28:47 +02:00
2016-04-18 02:58:29 +02:00
var err error
2016-04-30 09:52:33 +02:00
b , err = json . MarshalIndent ( & setup , " " , "\t" )
2016-04-18 02:58:29 +02:00
if err != nil {
panic ( err )
}
2016-04-30 09:52:33 +02:00
fmt . Printf ( "\n Generated configuration:\n %v\n\n" , string ( b ) )
fmt . Print ( " > Is this correct? (yes/no): " )
2016-04-18 02:58:29 +02:00
var answer string
fmt . Scanln ( & answer )
2016-04-30 09:52:33 +02:00
if answer == "yes" || answer == "y" {
break
2016-04-18 02:58:29 +02:00
}
2016-04-30 09:52:33 +02:00
fmt . Println ( )
2016-04-30 14:28:47 +02:00
setup = util . NewConfig ( )
2016-04-18 02:58:29 +02:00
}
2018-03-15 00:13:45 +01:00
confDir , err := os . Getwd ( )
if err != nil {
confDir = "/etc/semaphore"
}
fmt . Print ( " > Config output directory (default " + confDir + "): " )
2016-04-24 20:11:43 +02:00
2018-03-15 00:13:45 +01:00
var answer string
fmt . Scanln ( & answer )
if len ( answer ) > 0 {
confDir = answer
}
fmt . Printf ( " Running: mkdir -p %v..\n" , confDir )
os . MkdirAll ( confDir , 0755 )
configPath := path . Join ( confDir , "/config.json" )
2016-04-24 20:11:43 +02:00
if err := ioutil . WriteFile ( configPath , b , 0644 ) ; err != nil {
2016-04-18 02:58:29 +02:00
panic ( err )
}
2018-03-15 00:13:45 +01:00
fmt . Printf ( " Configuration written to %v..\n" , configPath )
2016-04-18 02:58:29 +02:00
2017-02-23 06:12:16 +01:00
fmt . Println ( " Pinging db.." )
2016-04-18 02:58:29 +02:00
util . Config = setup
2017-02-23 06:12:16 +01:00
if err := db . Connect ( ) ; err != nil {
2016-04-30 09:52:33 +02:00
fmt . Printf ( "\n Cannot connect to database!\n %v\n" , err . Error ( ) )
os . Exit ( 1 )
2016-04-18 02:58:29 +02:00
}
2016-04-30 09:52:33 +02:00
fmt . Println ( "\n Running DB Migrations.." )
2017-02-23 06:12:16 +01:00
if err := db . MigrateAll ( ) ; err != nil {
2016-04-30 09:52:33 +02:00
fmt . Printf ( "\n Database migrations failed!\n %v\n" , err . Error ( ) )
os . Exit ( 1 )
2016-04-18 02:58:29 +02:00
}
2016-05-17 22:17:17 +02:00
stdin := bufio . NewReader ( os . Stdin )
2016-04-18 02:58:29 +02:00
2017-02-23 06:12:16 +01:00
var user db . User
2016-05-23 21:29:38 +02:00
user . Username = readNewline ( "\n\n > Username: " , stdin )
2016-04-18 02:58:29 +02:00
user . Username = strings . ToLower ( user . Username )
2016-05-23 21:29:38 +02:00
user . Email = readNewline ( " > Email: " , stdin )
2016-04-18 02:58:29 +02:00
user . Email = strings . ToLower ( user . Email )
2017-02-23 06:12:16 +01:00
var existingUser db . User
db . Mysql . SelectOne ( & existingUser , "select * from user where email=? or username=?" , user . Email , user . Username )
2016-05-23 21:29:38 +02:00
if existingUser . ID > 0 {
// user already exists
fmt . Printf ( "\n Welcome back, %v! (a user with this username/email is already set up..)\n\n" , existingUser . Name )
} else {
user . Name = readNewline ( " > Your name: " , stdin )
user . Password = readNewline ( " > Password: " , stdin )
pwdHash , _ := bcrypt . GenerateFromPassword ( [ ] byte ( user . Password ) , 11 )
2017-07-26 08:37:16 +02:00
if _ , err := db . Mysql . Exec ( "insert into user set name=?, username=?, email=?, password=?, admin=1, created=UTC_TIMESTAMP()" , user . Name , user . Username , user . Email , pwdHash ) ; err != nil {
2016-05-23 21:29:38 +02:00
fmt . Printf ( " Inserting user failed. If you already have a user, you can disregard this error.\n %v\n" , err . Error ( ) )
os . Exit ( 1 )
}
fmt . Printf ( "\n You are all setup %v!\n" , user . Name )
2016-04-18 02:58:29 +02:00
}
2016-04-30 09:52:33 +02:00
fmt . Printf ( " Re-launch this program pointing to the configuration file\n\n./semaphore -config %v\n\n" , configPath )
fmt . Printf ( " To run as daemon:\n\nnohup ./semaphore -config %v &\n\n" , configPath )
2016-05-17 22:17:17 +02:00
fmt . Printf ( " You can login with %v or %v.\n" , user . Email , user . Username )
2016-04-18 02:58:29 +02:00
return 0
}
2016-05-17 22:17:17 +02:00
func readNewline ( pre string , stdin * bufio . Reader ) string {
fmt . Print ( pre )
str , _ := stdin . ReadString ( '\n' )
2016-12-21 19:35:31 +01:00
str = strings . Replace ( strings . Replace ( str , "\n" , "" , - 1 ) , "\r" , "" , - 1 )
2016-05-17 22:17:17 +02:00
return str
}
2016-05-21 00:07:27 +02:00
func checkUpdates ( ) {
2016-05-24 11:55:48 +02:00
util . CheckUpdate ( util . Version )
2016-05-21 00:07:27 +02:00
t := time . NewTicker ( time . Hour * 24 )
for range t . C {
2016-05-24 11:55:48 +02:00
util . CheckUpdate ( util . Version )
2016-05-21 00:07:27 +02:00
}
}