summaryrefslogblamecommitdiffstats
path: root/server/lib/shell.js
blob: 863e06bc313c94a660aa096f73e7047f73156336 (plain) (tree)
1
2
3
4
5
6
7
8
9
                     

                              
                                       
                                              
                                            

                                                        
 



                                                   
                  

                                          
 



                                                         



                                                                                                                                                                               








                                                                                                                  


                                                          
                                      
 


                                                              
                                      



                                                                       
 
                                            
                                        

                                                                         

                 
 
                                             
                                                   





                                                            
        
                                                   





                                                           

        
 
                                      
                                     
                                                                

                                                                                                              

                                               

    
                                             

                                          
                  

                                            
                                          













                                                                                                                             



                                                                        
                                        
                                                                               



                                  

   
 
                                        

                                             
                                                                                
   
 













                                                                                                    
                                    




                                                                                                                                                          

 





                                                      
                                                           

                                       
                                                 




                                            
 
                                                                 
 

                                                    
                                          

 
                                           



                                                                                                                                                                   
/* global __appdir */
var path = require('path')
var shell = require('shelljs')
// var child = require('child_process')
// var ipxeGIT = 'git://git.ipxe.org/ipxe.git'
var ipxeGIT = 'http://git.ipxe.org/ipxe.git'
var io = require(path.join(__appdir, 'lib', 'socketio'))
const fs = require('fs')

// Only one building process per version at a time.
var building = { efi: false, bios: false }
var make = {}

module.exports = {
  buildIpxe: async function (req, res) {
    const ipxeVersion = req.params.version

    // Different make commands for efi / bios are needed.
    var makeCmd = ''
    // Only one building process can be running.
    if (!building[ipxeVersion]) {
      makeCmd = 'make '
      if (ipxeVersion === 'efi') makeCmd += 'bin-x86_64-efi/snponly.efi '
      makeCmd += 'EMBED=' + path.join(__appdir, 'ipxe', 'embedded_' + ipxeVersion + '.ipxe') + ' TRUST=' + path.join(__appdir, 'bin', 'fullchain.pem')// + ' bin/undionly.kpxe'

      updateInProgress(ipxeVersion, true)
    } else {
      res.send({ status: 'ALREADY_BUILDING', error: 'Building ' + ipxeVersion + '-iPXE is already in progress.' })
      return
    }

    // Sending feedback, that the ipxe building progress started.
    res.status(200).send({ status: 'SUCCESS', msg: 'Starting iPXE building process' })

    // Cloning git.
    sendToLog(ipxeVersion, 'Cloning git ...\n', 'primary')
    await cloneIpxe(ipxeVersion)
    if (!building[ipxeVersion]) return

    // Copying configs.
    sendToLog(ipxeVersion, 'Copying configs ...\n', 'primary')
    copyConfigs(ipxeVersion)
    if (!building[ipxeVersion]) return

    // Make ipxe.
    sendToLog(ipxeVersion, 'Make iPXE ...\n', 'primary')
    shell.cd(path.join(__appdir, 'ipxe', 'ipxe_' + ipxeVersion, 'src'))

    await new Promise((resolve, reject) => {
      if (!building[ipxeVersion]) return
      make[ipxeVersion] = shell.exec(makeCmd, { async: true }, () => {
      // make[ipxeVersion] = child.exec(makeCmd, { async: true }, () => {
        resolve()
      })

      // Send the output to the frontend log.
      make[ipxeVersion].stdout.on('data', data => {
        const multiline = data.split('\n')
        if (multiline.length > 2) {
          multiline.forEach(line => {
            if (line) sendToLog(ipxeVersion, line, 'normal')
          })
        } else sendToLog(ipxeVersion, data, 'normal')
      })
      make[ipxeVersion].stderr.on('data', data => {
        const multiline = data.split('\n')
        if (multiline.length > 2) {
          multiline.forEach(line => {
            if (line) sendToLog(ipxeVersion, line, 'error')
          })
        } else sendToLog(ipxeVersion, data, 'error')
      })
    })

    if (!building[ipxeVersion]) return
    // Copy and rename the ipxe file.
    sendToLog(ipxeVersion, 'Copying ipxe file ...\n', 'primary')
    shell.cp('bin/undionly.kpxe', path.join(__appdir, 'ipxe'))
    shell.mv(path.join(__appdir, 'ipxe', 'undionly.kpxe'), path.join(__appdir, 'ipxe', 'ipxe.' + ipxeVersion))
    sendToLog(ipxeVersion, 'done\n', 'success')
    updateInProgress(ipxeVersion, false)
  },

  cancelBuilding: async function (req, res) {
    const ipxeVersion = req.params.version
    const process = make[ipxeVersion]
    if (process) {
      const kill = 'pkill -P ' + process.pid
      shell.exec(kill)
      updateInProgress(ipxeVersion, false)
    }
    res.send({ status: 'SUCCESS', data: process })
  },

  clean: async function (req, res) {
    const ipxeVersion = req.params.version
    if (building[ipxeVersion]) {
      res.send({ status: 'ALREADY_BUILDING', error: 'Can\'t clean, while building' + ipxeVersion + '-iPXE is in progress.' })
      return
    } else {
      updateInProgress(ipxeVersion, true)
      res.send({ status: 'SUCCESS', msg: 'Cleaning iPXE started' })
    }

    shell.cd(path.join(__appdir, 'ipxe'))
    shell.rm('-rf', 'ipxe_' + ipxeVersion)
    shell.rm(path.join(__appdir, 'ipxe', 'ipxe.' + ipxeVersion))
    shell.rm(path.join(__appdir, 'ipxe', 'log_' + ipxeVersion + '.txt'))
    updateInProgress(ipxeVersion, false)
    sendToLog(ipxeVersion, 'iPXE files successfully cleaned', 'success', false)
  },

  status: function (ipxeVersion) {
    return building[ipxeVersion]
  }
}

async function cloneIpxe (ipxeVersion) {
  // Check if git is installed on the server.
  if (!shell.which('git')) {
    return { status: 'GIT_MISSING', error: 'Please install git on the server.' }
  }

  shell.cd(path.join(__appdir, 'ipxe'))
  return new Promise((resolve, reject) => {
    var clone = shell.exec('git clone ' + ipxeGIT + ' ipxe_' + ipxeVersion, { async: true }, () => {
      resolve()
    })
    clone.stdout.on('data', data => {
      sendToLog(ipxeVersion, data, 'normal')
    })
    clone.stderr.on('data', data => {
      sendToLog(ipxeVersion, data, 'error')
    })
  })
}

function copyConfigs (ipxeVersion) {
  // Remove the default configs and paste in the customized ones.
  shell.rm(path.join(__appdir, 'ipxe', 'ipxe_' + ipxeVersion, 'src', 'config', 'general.h'))
  shell.rm(path.join(__appdir, 'ipxe', 'ipxe_' + ipxeVersion, 'src', 'config', 'console.h'))
  shell.cp(path.join(__appdir, 'ipxe', 'general_' + ipxeVersion + '.h'), path.join(__appdir, 'ipxe', 'ipxe_' + ipxeVersion, 'src', 'config', 'general.h'))
  shell.cp(path.join(__appdir, 'ipxe', 'console_' + ipxeVersion + '.h'), path.join(__appdir, 'ipxe', 'ipxe_' + ipxeVersion, 'src', 'config', 'console.h'))
}

function updateInProgress (ipxeVersion, inProgress) {
  building[ipxeVersion] = inProgress
  const event = ipxeVersion + ' inProgress'
  io.in('broadcast ipxeBuild').emit(event, inProgress)
}

function sendToLog (ipxeVersion, msg, status, log = true) {
  const date = new Date()
  const pad = x => x < 10 ? '0' + x : x
  var dateString = '[' + date.getFullYear() + '-'
  dateString += pad(date.getMonth()) + '-'
  dateString += pad(date.getDate()) + ' '
  dateString += pad(date.getHours()) + ':'
  dateString += pad(date.getMinutes()) + ':'
  dateString += pad(date.getSeconds()) + ']'

  const logEntry = { date: dateString, status: status, msg: msg }

  const event = ipxeVersion + ' log'
  io.in('broadcast ipxeBuild').emit(event, logEntry)
  if (log) writeLog(ipxeVersion, logEntry)
}

function writeLog (ipxeVersion, logEntry) {
  fs.writeFile(path.join(__appdir, 'ipxe', 'log_' + ipxeVersion + '.txt'), logEntry.date + '\t' + logEntry.status + '\t' + logEntry.msg, { flag: 'a+' }, (err) => {
    if (err) throw err
  })
}