2020-01-10 00:24:59 -05:00
/ *
* This file is part of Linode Manager Classic .
*
* Linode Manager Classic is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* Linode Manager Classic is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with Linode Manager Classic . If not , see < https : //www.gnu.org/licenses/>.
* /
import { settings , elements , apiDelete , apiGet , apiPost , eventTitles , parseParams , setupHeader , timeString , translateKernel } from "/global.js" ;
( function ( )
{
// Element names specific to this page
elements . backups = "backups" ;
elements . backupsEnabled = "backups-enabled" ;
elements . boot = "boot" ;
elements . configRadioName = "config-radio" ;
elements . configRemovePrefix = "config-remove-" ;
elements . configTable = "config-table" ;
elements . diskIcon = "disk-icon" ;
elements . diskIconImg = "/img/disk.gif" ;
elements . diskRemovePrefix = "disk-remove-" ;
elements . diskTable = "disk-table" ;
elements . diskUsage = "disk-usage" ;
elements . eventRowPrefix = "event-row-" ;
elements . eventTable = "event-table" ;
elements . extraEvent = "extra-event" ;
elements . info = "info" ;
elements . jobFailed = "job-failed" ;
elements . jobInfo = "job-info" ;
elements . jobNotice = "job-notice" ;
elements . jobProgress = "job-progress" ;
elements . jobProgressRow = "job-progress-row" ;
elements . jobRunning = "job-running" ;
elements . jobSuccess = "job-success" ;
elements . jobType = "job-type" ;
elements . lastBackup = "last-backup" ;
elements . lastBackupTime = "last-backup-time" ;
elements . linodeLabel = "linode-label" ;
elements . linodeTag = "linode-tag" ;
elements . linodeTagLink = "linode-tag-link" ;
elements . lmcRow = "lmc-tr3" ;
elements . loadingConfigs = "loading-configs" ;
elements . loadingDisks = "loading-disks" ;
elements . loadingJobs = "loading-jobs" ;
elements . loadingVolumes = "loading-volumes" ;
elements . moreJobs = "moar-jobs" ;
elements . netUsage = "net-usage" ;
elements . notification = "notification" ;
elements . notifications = "notifications" ;
elements . reboot = "reboot" ;
elements . serverStatus = "server-status" ;
elements . shutDown = "shut-down" ;
elements . spinnerImg = "/img/spinner-trans.gif" ;
elements . storageFree = "storage-free" ;
elements . storageTotal = "storage-total" ;
elements . storageUsed = "storage-used" ;
elements . transferMonthly = "transfer-monthly" ;
elements . transferOverage = "transfer-overage" ;
elements . transferUsed = "transfer-used" ;
2020-01-22 21:01:47 -05:00
elements . upgrade = "upgrade" ;
2020-01-10 00:24:59 -05:00
elements . volumeTable = "volume-table" ;
// Data recieved from API calls
var data = { } ;
data . params = { } ;
data . configs = [ ] ;
data . disks = [ ] ;
data . events = [ ] ;
data . linode = { } ;
data . linodeTransfer = { } ;
data . notifications = [ ] ;
2020-01-22 21:01:47 -05:00
data . plan = { } ;
2020-01-10 00:24:59 -05:00
data . volumes = [ ] ;
// Static references to UI elements
var ui = { } ;
ui . backups = { } ;
ui . boot = { } ;
ui . configTable = { } ;
ui . diskTable = { } ;
ui . diskUsage = { } ;
ui . eventTable = { } ;
ui . jobProgress = { } ;
ui . jobProgressRow = { } ;
ui . lastBackup = { } ;
ui . lastBackupTime = { } ;
ui . linodeLabel = { } ;
ui . linodeTag = { } ;
ui . linodeTagLink = { } ;
ui . loadingConfigs = { } ;
ui . loadingDisks = { } ;
ui . loadingJobs = { } ;
ui . loadingVolumes = { } ;
ui . moreJobs = { } ;
ui . netUsage = { } ;
ui . notifications = { } ;
ui . reboot = { } ;
ui . serverStatus = { } ;
ui . shutDown = { } ;
ui . storageFree = { } ;
ui . storageTotal = { } ;
ui . storageUsed = { } ;
ui . transferMonthly = { } ;
ui . transferOverage = { } ;
ui . transferUsed = { } ;
2020-01-22 21:01:47 -05:00
ui . upgrade = { } ;
2020-01-10 00:24:59 -05:00
ui . volumeTable = { } ;
// Temporary state
var state = { } ;
state . diskRefresh = false ;
state . eventsComplete = 0 ;
state . linodeRefresh = false ;
state . showExtraEvents = false ;
// Button handler for boot button
var bootLinode = function ( event )
{
if ( ! confirm ( "Boot this Linode?" ) )
return ;
var config = getSelectedConfig ( ) ;
var request = { } ;
if ( config )
request . config _id = config ;
// Reload the page on successful API return
var callback = function ( )
{
location . reload ( ) ;
} ;
apiPost ( "/linode/instances/" + data . params . lid + "/boot" , request , callback ) ;
} ;
// Convert a byte count into a "friendly" byte string (KB, MB, GB, etc)
var byteString = function ( count )
{
var prefix = "KMGTPEZY" ;
var unit = "" ;
for ( var i = 0 ; i < prefix . length ; i ++ ) {
if ( count >= 1024 ) {
count /= 1024 ;
unit = prefix . charAt ( i ) ;
} else {
break ;
}
}
return count . toFixed ( 2 ) + " " + unit + "B" ;
} ;
// Generate a config profile table row
var createConfigRow = function ( config )
{
var row = document . createElement ( "tr" ) ;
row . className = elements . lmcRow ;
// Radio button selector
var radioCell = document . createElement ( "td" ) ;
var radioInput = document . createElement ( "input" ) ;
radioInput . name = elements . configRadioName ;
radioInput . className = elements . configRadioName ;
radioInput . id = elements . configRadioName + "-" + config . id ;
radioInput . type = "radio" ;
radioCell . appendChild ( radioInput ) ;
row . appendChild ( radioCell ) ;
// Config profile name and kernel
var nameCell = document . createElement ( "td" ) ;
var nameLink = document . createElement ( "a" ) ;
nameLink . href = "/linodes/config?cid=" + config . id + "&lid=" + data . params . lid ;
if ( config . label . length > 41 )
nameLink . innerHTML = config . label . substring ( 0 , 41 ) + "..." ;
else
nameLink . innerHTML = config . label ;
nameCell . appendChild ( nameLink ) ;
var prefix = document . createElement ( "span" ) ;
prefix . className = elements . info ;
prefix . innerHTML = " (" ;
nameCell . appendChild ( prefix ) ;
var kernel = document . createElement ( "span" ) ;
kernel . className = elements . info ;
translateKernel ( config . kernel , kernel ) ;
nameCell . appendChild ( kernel ) ;
var suffix = document . createElement ( "span" ) ;
suffix . className = elements . info ;
suffix . innerHTML = ")" ;
nameCell . appendChild ( suffix ) ;
row . appendChild ( nameCell ) ;
// Option links
var options = document . createElement ( "td" ) ;
var editLink = document . createElement ( "a" ) ;
editLink . href = "/linodes/config?cid=" + config . id + "&lid=" + data . params . lid ;
editLink . innerHTML = "Edit" ;
var separator = document . createElement ( "span" ) ;
separator . innerHTML = " | " ;
var removeLink = document . createElement ( "a" ) ;
removeLink . href = "#" ;
removeLink . id = elements . configRemovePrefix + config . id ;
removeLink . innerHTML = "Remove" ;
removeLink . addEventListener ( "click" , deleteConfig ) ;
options . appendChild ( editLink ) ;
options . appendChild ( separator ) ;
options . appendChild ( removeLink ) ;
row . appendChild ( options ) ;
return row ;
} ;
// Generate a disk table row
var createDiskRow = function ( disk )
{
var row = document . createElement ( "tr" ) ;
row . className = elements . lmcRow ;
// Disk icon
var iconCell = document . createElement ( "td" ) ;
var diskIcon = document . createElement ( "img" ) ;
diskIcon . className = elements . diskIcon ;
diskIcon . src = elements . diskIconImg ;
iconCell . appendChild ( diskIcon ) ;
row . appendChild ( iconCell ) ;
// Disk name and size
var nameCell = document . createElement ( "td" ) ;
var nameLink = document . createElement ( "a" ) ;
nameLink . href = "/linodes/disk?did=" + disk . id + "&lid=" + data . params . lid ;
nameLink . innerHTML = disk . label ;
var size = document . createElement ( "span" ) ;
size . className = elements . info ;
size . innerHTML = " (" + disk . size + " MB, " + disk . filesystem + ")" ;
nameCell . appendChild ( nameLink ) ;
nameCell . appendChild ( size ) ;
row . appendChild ( nameCell ) ;
// Options links
var options = document . createElement ( "td" ) ;
var editLink = document . createElement ( "a" ) ;
editLink . href = "/linodes/disk?did=" + disk . id + "&lid=" + data . params . lid ;
editLink . innerHTML = "Edit" ;
var separator = document . createElement ( "span" ) ;
separator . innerHTML = " | " ;
var removeLink = document . createElement ( "a" ) ;
removeLink . href = "#" ;
removeLink . id = elements . diskRemovePrefix + disk . id ;
removeLink . innerHTML = "Remove" ;
removeLink . addEventListener ( "click" , deleteDisk ) ;
options . appendChild ( editLink ) ;
options . appendChild ( separator ) ;
options . appendChild ( removeLink ) ;
row . appendChild ( options ) ;
return row ;
} ;
// Generate an event table row
var createEventRow = function ( event , extra )
{
var row = document . createElement ( "tr" ) ;
row . id = elements . eventRowPrefix + event . id ;
row . className = elements . lmcRow ;
if ( extra )
row . className += " " + elements . extraEvent ;
// Status cell
var statusCell = document . createElement ( "td" ) ;
if ( event . status . match ( /scheduled|started/ ) ) {
statusCell . className = elements . jobRunning ;
var spinner = document . createElement ( "img" ) ;
spinner . src = elements . spinnerImg ;
statusCell . appendChild ( spinner ) ;
} else if ( event . status == "failed" ) {
var failed = document . createElement ( "span" ) ;
failed . className = elements . jobFailed ;
failed . innerHTML = "Failed" ;
statusCell . appendChild ( failed ) ;
} else if ( event . status == "notification" ) {
var notice = document . createElement ( "span" ) ;
notice . className = elements . jobNotice ;
notice . innerHTML = "Notice" ;
statusCell . appendChild ( notice ) ;
} else if ( event . status == "finished" ) {
var success = document . createElement ( "span" ) ;
success . className = elements . jobSuccess ;
success . innerHTML = "Success" ;
statusCell . appendChild ( success ) ;
}
row . appendChild ( statusCell ) ;
// Details cell
var detailsCell = document . createElement ( "td" ) ;
var jobType = document . createElement ( "span" ) ;
jobType . className = elements . jobType ;
if ( eventTitles [ event . action ] )
jobType . innerHTML = eventTitles [ event . action ] ;
else
jobType . innerHTML = event . action ;
var jobDetails = document . createElement ( "span" ) ;
if ( event . secondary _entity )
jobDetails . innerHTML = " - " + event . secondary _entity . label ;
var br = document . createElement ( "br" ) ;
var jobInfo = document . createElement ( "span" ) ;
jobInfo . className = elements . jobInfo ;
var eventDate = new Date ( event . created + "Z" ) ;
var curDate = new Date ( ) ;
jobInfo . innerHTML = "Entered: " + timeString ( curDate - eventDate , true ) ;
2020-01-22 23:03:30 -05:00
if ( event . duration )
jobInfo . innerHTML += " - Took: " + timeString ( event . duration * 1000 , false ) ;
else if ( event . status != "notification" )
jobInfo . innerHTML += " - Waiting..." ;
detailsCell . appendChild ( jobType ) ;
detailsCell . appendChild ( jobDetails ) ;
detailsCell . appendChild ( br ) ;
detailsCell . appendChild ( jobInfo ) ;
row . appendChild ( detailsCell ) ;
// Progress cell
var progressCell = document . createElement ( "td" ) ;
2020-01-10 00:24:59 -05:00
if ( event . percent _complete && event . percent _complete != 100 )
2020-01-22 23:03:30 -05:00
progressCell . innerHTML = event . percent _complete + "%" ;
2020-01-10 00:24:59 -05:00
if ( event . time _remaining ) {
2020-01-22 23:03:30 -05:00
if ( progressCell . innerHTML . length )
progressCell . innerHTML += ", " ;
2020-01-10 00:24:59 -05:00
var times = event . time _remaining . split ( ":" ) ;
var ms = 0 ;
ms += parseInt ( times [ 0 ] ) * 3600000 ;
ms += parseInt ( times [ 1 ] ) * 60000 ;
ms += parseInt ( times [ 2 ] ) * 1000 ;
2020-01-22 23:03:30 -05:00
progressCell . innerHTML += timeString ( ms , false ) + " to go" ;
2020-01-10 00:24:59 -05:00
}
2020-01-22 23:03:30 -05:00
if ( event . rate ) {
if ( progressCell . innerHTML . length )
progressCell . innerHTML += ", " ;
progressCell . innerHTML += event . rate ;
}
row . appendChild ( progressCell ) ;
2020-01-10 00:24:59 -05:00
return row ;
} ;
// Generate a volume table row
var createVolumeRow = function ( volume )
{
var row = document . createElement ( "tr" ) ;
row . className = elements . lmcRow ;
// Disk icon
var iconCell = document . createElement ( "td" ) ;
var diskIcon = document . createElement ( "img" ) ;
diskIcon . className = elements . diskIcon ;
diskIcon . src = elements . diskIconImg ;
iconCell . appendChild ( diskIcon ) ;
row . appendChild ( iconCell ) ;
// Volume name and size
var nameCell = document . createElement ( "td" ) ;
var nameLink = document . createElement ( "a" ) ;
nameLink . href = "/volumes/settings?vid=" + volume . id ;
nameLink . innerHTML = volume . label ;
var size = document . createElement ( "span" ) ;
size . className = elements . info ;
size . innerHTML = " (" + volume . size + " GiB)" ;
nameCell . appendChild ( nameLink ) ;
nameCell . appendChild ( size ) ;
row . appendChild ( nameCell ) ;
// Options links
var options = document . createElement ( "td" ) ;
var editLink = document . createElement ( "a" ) ;
editLink . href = "/volumes/settings?vid=" + volume . id ;
editLink . innerHTML = "Edit" ;
var separator = document . createElement ( "span" ) ;
separator . innerHTML = " | " ;
var cloneLink = document . createElement ( "a" ) ;
cloneLink . href = "/volumes/clone?vid=" + volume . id ;
cloneLink . innerHTML = "Clone" ;
var detachLink = document . createElement ( "a" ) ;
detachLink . href = "/volumes/detach?vid=" + volume . id ;
detachLink . innerHTML = "Detach" ;
var removeLink = document . createElement ( "a" ) ;
removeLink . href = "/volumes/remove?vid=" + volume . id ;
removeLink . innerHTML = "Remove" ;
options . appendChild ( editLink ) ;
options . appendChild ( separator ) ;
options . appendChild ( cloneLink ) ;
options . appendChild ( separator . cloneNode ( true ) ) ;
options . appendChild ( detachLink ) ;
options . appendChild ( separator . cloneNode ( true ) ) ;
options . appendChild ( removeLink ) ;
row . appendChild ( options ) ;
return row ;
} ;
// Handler for config delete
var deleteConfig = function ( event )
{
if ( ! confirm ( "Delete this Configuration Profile?" ) )
return ;
var cid = event . currentTarget . id . substring ( elements . configRemovePrefix . length ) ;
apiDelete ( "/linode/instances/" + data . params . lid + "/configs/" + cid , function ( )
{
location . reload ( ) ;
} ) ;
} ;
// Handler for disk delete
var deleteDisk = function ( event )
{
var did = parseInt ( event . currentTarget . id . substring ( elements . diskRemovePrefix . length ) ) ;
var disk = null ;
for ( var i = 0 ; i < data . disks . length ; i ++ ) {
if ( data . disks [ i ] . id == did ) {
disk = data . disks [ i ] ;
break ;
}
}
if ( ! disk )
return ;
if ( ! confirm ( "Delete " + disk . label + "?" ) )
return ;
apiDelete ( "/linode/instances/" + data . params . lid + "/disks/" + did , function ( )
{
location . reload ( ) ;
} ) ;
} ;
// Callback for config profile API call
var displayConfigs = function ( response )
{
// Add configs to array
data . configs = data . configs . concat ( response . data ) ;
// Request the next page if there are more
if ( response . page != response . pages ) {
apiGet ( "/linode/instances/" + data . params . lid + "/configs?page=" + ( response . page + 1 ) , displayConfigs , null ) ;
return ;
}
// Remove loading row
ui . loadingConfigs . remove ( ) ;
// Insert config profile rows into table
for ( var i = 0 ; i < data . configs . length ; i ++ )
ui . configTable . appendChild ( createConfigRow ( data . configs [ i ] ) ) ;
} ;
// Callback for linode details API call
var displayDetails = function ( response )
{
data . linode = response ;
// Set page title and header stuff
if ( document . title . indexOf ( "//" ) == - 1 )
document . title += " // " + data . linode . label ;
ui . linodeLabel . innerHTML = data . linode . label ;
if ( data . linode . tags . length == 1 ) {
ui . linodeTagLink . href = "/linodes?tag=" + data . linode . tags [ 0 ] ;
ui . linodeTagLink . innerHTML = "(" + data . linode . tags [ 0 ] + ")" ;
ui . linodeTag . style . display = "inline" ;
} else {
ui . linodeTag . style . display = "none" ;
}
// Set running status
ui . serverStatus . innerHTML = data . linode . status . charAt ( 0 ) . toUpperCase ( ) + data . linode . status . slice ( 1 ) . replace ( /_/g , " " ) ;
if ( data . linode . status == "running" ) {
ui . shutDown . disabled = false ;
ui . shutDown . style . display = "block" ;
} else {
ui . shutDown . style . display = "none" ;
}
if ( data . linode . status . match ( /offline|provisioning|migrating|rebuilding|restoring|shutting_down|resizing/ ) ) {
ui . reboot . style . display = "none" ;
ui . boot . disabled = false ;
ui . boot . style . display = "inline" ;
} else if ( data . linode . status != "cloning" ) {
ui . boot . style . display = "none" ;
ui . reboot . disabled = false ;
ui . reboot . style . display = "inline" ;
}
// Update storage info
displayStorage ( ) ;
// Set backup status
if ( data . linode . backups . enabled ) {
ui . backups . innerHTML = "Enabled!" ;
ui . backups . className += " " + elements . backupsEnabled ;
2020-01-22 23:03:30 -05:00
if ( data . linode . backups . last _successful ) {
var backupDate = new Date ( data . linode . backups . last _successful + "Z" ) ;
var now = new Date ( ) ;
ui . lastBackupTime . innerHTML = timeString ( now - backupDate , true ) ;
ui . lastBackup . style . display = "block" ;
}
2020-01-10 00:24:59 -05:00
} else {
ui . backups . innerHTML = "" ;
var text = document . createElement ( "span" ) ;
text . innerHTML = "No - " ;
var backupLink = document . createElement ( "a" ) ;
backupLink . href = "/linodes/backups_enable?lid=" + data . params . lid ;
backupLink . innerHTML = "Enable" ;
backups . appendChild ( text ) ;
backups . appendChild ( backupLink ) ;
}
2020-01-22 21:01:47 -05:00
// Get plan info
2020-01-22 21:04:24 -05:00
if ( data . linode . type && ! data . plan . id )
2020-01-22 21:01:47 -05:00
apiGet ( "/linode/types/" + data . linode . type , displayPlan , null ) ;
2020-01-10 00:24:59 -05:00
state . linodeRefresh = false ;
} ;
// Callback for disks API call
var displayDisks = function ( response )
{
// Add disks to array
data . disks = data . disks . concat ( response . data ) ;
// Request the next page if there are more
if ( response . page != response . pages ) {
apiGet ( "/linode/instances/" + data . params . lid + "/disks?page=" + ( response . page + 1 ) , displayDisks , null ) ;
return ;
}
// Remove loading row
ui . loadingDisks . remove ( ) ;
// Update storage info
displayStorage ( ) ;
// Insert disk rows into table
ui . diskTable . innerHTML = "" ;
for ( var i = 0 ; i < data . disks . length ; i ++ )
ui . diskTable . appendChild ( createDiskRow ( data . disks [ i ] ) ) ;
state . diskRefresh = false ;
} ;
// Callback for events API call
var displayEvents = function ( response )
{
// Only collect a max of 8 finished jobs
for ( var i = 0 ; i < response . data . length && state . eventsComplete < 8 ; i ++ ) {
if ( response . data [ i ] . status . match ( /failed|finished|notification/ ) )
state . eventsComplete ++ ;
data . events . push ( response . data [ i ] ) ;
}
// Request the next page if there are more
if ( state . eventsComplete < 8 && response . page != response . pages ) {
var filter = {
"entity.type" : "linode" ,
"entity.id" : parseInt ( data . params . lid )
} ;
apiGet ( "/account/events?page=" + ( response . page + 1 ) , displayEvents , filter ) ;
return ;
}
// Remove loading row
ui . loadingJobs . remove ( ) ;
// Insert events into table and compute total progress
var progress = 0 ;
var totalProgress = 0 ;
for ( var i = 0 ; i < data . events . length ; i ++ ) {
var extra = ( data . events [ i ] . status . match ( /failed|finished|notification/ ) && i >= 4 ) ;
ui . eventTable . appendChild ( createEventRow ( data . events [ i ] , extra ) ) ;
if ( ! data . events [ i ] . status . match ( /failed|finished|notification/ ) ) {
totalProgress += 100 ;
progress += data . events [ i ] . percent _complete ;
// Set refresh timer for event
window . setTimeout ( getEvent , settings . refreshRate , data . events [ i ] . id ) ;
}
}
// If there are ongoing events, show the progress bar
if ( totalProgress ) {
ui . jobProgress . max = totalProgress ;
ui . jobProgress . value = progress ;
ui . jobProgress . innerHTML = ( progress / totalProgress * 100 ) . toFixed ( 0 ) + "%" ;
ui . jobProgress . title = ui . jobProgress . innerHTML ;
ui . jobProgressRow . style . display = "table-row" ;
}
} ;
// Callback for notifications API call
var displayNotifications = function ( response )
{
// Add notifications to array
data . notifications = data . notifications . concat ( response . data ) ;
// Request the next page if there are more pages
if ( response . page != response . pages ) {
apiGet ( "/account/notifications?page=" + ( response . page + 1 ) , displayNotifications , null ) ;
return ;
}
// Display notifications
for ( var i = 0 ; i < data . notifications . length ; i ++ ) {
if ( ! data . notifications [ i ] . entity || data . notifications [ i ] . entity . type != "linode" || data . notifications [ i ] . entity . id != data . params . lid )
continue ;
2021-03-11 10:37:07 -05:00
if ( data . notifications [ i ] . type == "maintenance" ) {
var now = new Date ( ) ;
var maintStart = new Date ( data . notifications [ i ] . when + "Z" ) ;
data . notifications [ i ] . label = "Maintenance Scheduled" ;
data . notifications [ i ] . message = "This Linode's physical host will be undergoing maintenance on " + maintStart . toLocaleString ( ) + " (in " + timeString ( maintStart - now , false ) + ")." ;
data . notifications [ i ] . message += " During this time, your Linode will be shut down and remain offline, then returned to its last state (running or powered off)." ;
data . notifications [ i ] . message += " For more information, please see your open support tickets." ;
}
2022-09-14 22:33:35 -04:00
if ( data . notifications [ i ] . type == "migration_scheduled" ) {
var now = new Date ( ) ;
var migrateStart = new Date ( data . notifications [ i ] . when + "Z" ) ;
data . notifications [ i ] . message += " If no action is taken, the migration will start automatically on " + migrateStart . toLocaleString ( ) + " (in " + timeString ( migrateStart - now , false ) + ")." ;
}
2020-01-10 00:24:59 -05:00
var notification = document . createElement ( "div" ) ;
notification . className = elements . notification ;
var header = document . createElement ( "h1" ) ;
header . innerHTML = data . notifications [ i ] . label ;
notification . appendChild ( header ) ;
2021-03-15 14:40:29 -04:00
if ( data . notifications [ i ] . type == "migration_pending" || data . notifications [ i ] . type == "migration_scheduled" ) {
2020-01-10 00:24:59 -05:00
var migrateButton = document . createElement ( "button" ) ;
migrateButton . type = "button" ;
migrateButton . innerHTML = "Migrate " + data . notifications [ i ] . entity . label + " NOW" ;
migrateButton . addEventListener ( "click" , initiateMigration ) ;
notification . appendChild ( migrateButton ) ;
}
var body = document . createElement ( "p" ) ;
body . innerHTML = data . notifications [ i ] . message ;
notification . appendChild ( body ) ;
ui . notifications . appendChild ( notification ) ;
}
} ;
2020-01-22 21:01:47 -05:00
// Callback for linode plan API call
var displayPlan = function ( response )
{
data . plan = response ;
// Display the upgrade banner if one is available
if ( data . plan . successor )
ui . upgrade . style . display = "block" ;
} ;
2020-01-10 00:24:59 -05:00
// Show storage totals
var displayStorage = function ( )
{
if ( ! data . linode . specs )
return ;
ui . storageTotal . innerHTML = data . linode . specs . disk + " MB" ;
var storageUsed = 0 ;
for ( var i = 0 ; i < data . disks . length ; i ++ )
storageUsed += data . disks [ i ] . size ;
ui . storageUsed . innerHTML = storageUsed + " MB" ;
ui . storageFree . innerHTML = ( data . linode . specs . disk - storageUsed ) + " MB" ;
ui . diskUsage . value = ( storageUsed / data . linode . specs . disk * 100 ) . toFixed ( 0 ) ;
ui . diskUsage . innerHTML = ui . diskUsage . value + "%" ;
ui . diskUsage . title = ui . diskUsage . innerHTML ;
} ;
// Callback for network transfer API call
var displayTransfer = function ( response )
{
data . linodeTransfer = response ;
// Display network transfer info
ui . transferMonthly . innerHTML = data . linodeTransfer . quota + " GB" ;
ui . transferUsed . innerHTML = byteString ( data . linodeTransfer . used ) ;
ui . transferOverage . innerHTML = data . linodeTransfer . billable + " GB" ;
ui . netUsage . value = ( ( data . linodeTransfer . used / 1024 / 1024 / 1024 ) / data . linodeTransfer . quota * 100 ) . toFixed ( 0 ) ;
ui . netUsage . innerHTML = ui . netUsage . value + "%" ;
ui . netUsage . title = ui . netUsage . innerHTML ;
} ;
// Callback for volumes API call
var displayVolumes = function ( response )
{
// Add volumes to array
data . volumes = data . volumes . concat ( response . data ) ;
// Request the next page if there are more
if ( response . page != response . pages ) {
apiGet ( "/linode/instances/" + data . params . lid + "/volumes?page=" + ( response . page + 1 ) , displayVolumes , null ) ;
return ;
}
// Remove loading row
ui . loadingVolumes . remove ( ) ;
// Insert volume rows into table
for ( var i = 0 ; i < data . volumes . length ; i ++ )
ui . volumeTable . appendChild ( createVolumeRow ( data . volumes [ i ] ) ) ;
} ;
// Retrieve the given event from the API
var getEvent = function ( eventID )
{
apiGet ( "/account/events/" + eventID , updateEvent , null ) ;
} ;
// Get selected config profile
var getSelectedConfig = function ( )
{
var configs = document . getElementsByClassName ( elements . configRadioName ) ;
for ( var i = 0 ; i < configs . length ; i ++ ) {
if ( configs [ i ] . checked )
return parseInt ( configs [ i ] . id . replace ( elements . configRadioName + "-" , "" ) ) ;
}
return 0 ;
} ;
// Button handler to initiate migration
var initiateMigration = function ( event )
{
if ( event . currentTarget . disabled )
return ;
var req = {
"upgrade" : false
} ;
apiPost ( "/linode/instances/" + data . params . lid + "/migrate" , req , function ( response )
{
location . reload ( ) ;
} ) ;
} ;
// Button handler for reboot button
var rebootLinode = function ( event )
{
if ( ! confirm ( "Are you sure you want to issue a Reboot?" ) )
return ;
var config = getSelectedConfig ( ) ;
var request = { } ;
if ( config )
request . config _id = config ;
// Reload the page on successful API return
var callback = function ( )
{
location . reload ( ) ;
} ;
apiPost ( "/linode/instances/" + data . params . lid + "/reboot" , request , callback ) ;
} ;
// Initial setup
var setup = function ( )
{
// Parse URL parameters
data . params = parseParams ( ) ;
// We need a Linode ID, so die if we don't have it
if ( ! data . params . lid ) {
alert ( "No Linode ID supplied!" ) ;
return ;
}
setupHeader ( ) ;
// Update links on page to include proper Linode ID
var anchors = document . getElementsByTagName ( "a" ) ;
for ( var i = 0 ; i < anchors . length ; i ++ )
anchors [ i ] . href = anchors [ i ] . href . replace ( "lid=0" , "lid=" + data . params . lid ) ;
// Get element references
ui . backups = document . getElementById ( elements . backups ) ;
ui . boot = document . getElementById ( elements . boot ) ;
ui . configTable = document . getElementById ( elements . configTable ) ;
ui . diskTable = document . getElementById ( elements . diskTable ) ;
ui . diskUsage = document . getElementById ( elements . diskUsage ) ;
ui . eventTable = document . getElementById ( elements . eventTable ) ;
ui . jobProgress = document . getElementById ( elements . jobProgress ) ;
ui . jobProgressRow = document . getElementById ( elements . jobProgressRow ) ;
ui . lastBackup = document . getElementById ( elements . lastBackup ) ;
ui . lastBackupTime = document . getElementById ( elements . lastBackupTime ) ;
ui . linodeLabel = document . getElementById ( elements . linodeLabel ) ;
ui . linodeTag = document . getElementById ( elements . linodeTag ) ;
ui . linodeTagLink = document . getElementById ( elements . linodeTagLink ) ;
ui . loadingConfigs = document . getElementById ( elements . loadingConfigs ) ;
ui . loadingDisks = document . getElementById ( elements . loadingDisks ) ;
ui . loadingJobs = document . getElementById ( elements . loadingJobs ) ;
ui . loadingVolumes = document . getElementById ( elements . loadingVolumes ) ;
ui . moreJobs = document . getElementById ( elements . moreJobs ) ;
ui . netUsage = document . getElementById ( elements . netUsage ) ;
ui . notifications = document . getElementById ( elements . notifications ) ;
ui . reboot = document . getElementById ( elements . reboot ) ;
ui . serverStatus = document . getElementById ( elements . serverStatus ) ;
ui . shutDown = document . getElementById ( elements . shutDown ) ;
ui . storageFree = document . getElementById ( elements . storageFree ) ;
ui . storageTotal = document . getElementById ( elements . storageTotal ) ;
ui . storageUsed = document . getElementById ( elements . storageUsed ) ;
ui . transferMonthly = document . getElementById ( elements . transferMonthly ) ;
ui . transferOverage = document . getElementById ( elements . transferOverage ) ;
ui . transferUsed = document . getElementById ( elements . transferUsed ) ;
2020-01-22 21:01:47 -05:00
ui . upgrade = document . getElementById ( elements . upgrade ) ;
2020-01-10 00:24:59 -05:00
ui . volumeTable = document . getElementById ( elements . volumeTable ) ;
// Attach button handlers
ui . boot . addEventListener ( "click" , bootLinode ) ;
ui . moreJobs . addEventListener ( "click" , toggleEvents ) ;
ui . reboot . addEventListener ( "click" , rebootLinode ) ;
ui . shutDown . addEventListener ( "click" , shutDownLinode ) ;
// Get data from the API
apiGet ( "/linode/instances/" + data . params . lid , displayDetails , null ) ;
apiGet ( "/linode/instances/" + data . params . lid + "/configs" , displayConfigs , null ) ;
apiGet ( "/linode/instances/" + data . params . lid + "/disks" , displayDisks , null ) ;
apiGet ( "/linode/instances/" + data . params . lid + "/volumes" , displayVolumes , null ) ;
apiGet ( "/linode/instances/" + data . params . lid + "/transfer" , displayTransfer , null ) ;
var filter = {
"entity.type" : "linode" ,
"entity.id" : parseInt ( data . params . lid )
} ;
apiGet ( "/account/events" , displayEvents , filter ) ;
apiGet ( "/account/notifications" , displayNotifications , null ) ;
} ;
// Button handler for shutdown button
var shutDownLinode = function ( event )
{
if ( ! confirm ( "Are you sure you want to issue a Shutdown?" ) )
return ;
// Reload the page on successful API return
var callback = function ( )
{
location . reload ( ) ;
} ;
apiPost ( "/linode/instances/" + data . params . lid + "/shutdown" , { } , callback ) ;
} ;
// Toggle visibility of "extra" events
var toggleEvents = function ( event )
{
// Flip
state . showExtraEvents = ! state . showExtraEvents ;
var display = "none" ;
if ( state . showExtraEvents )
display = "table-row" ;
// Get extra events and show/hide them
var extras = document . getElementsByClassName ( elements . extraEvent ) ;
for ( var i = 0 ; i < extras . length ; i ++ )
extras [ i ] . style . display = display ;
} ;
// Update an existing event
var updateEvent = function ( event )
{
// Update the local copy of the event
var progress = 0 ;
for ( var i = 0 ; i < data . events . length ; i ++ ) {
if ( data . events [ i ] . id == event . id ) {
progress = event . percent _complete - data . events [ i ] . percent _complete ;
// Refresh details if event status changed
if ( event . status != data . events [ i ] . status && ! state . linodeRefresh && ! state . diskRefresh ) {
state . linodeRefresh = true ;
state . diskRefresh = true ;
data . linode = { } ;
data . disks = [ ] ;
apiGet ( "/linode/instances/" + data . params . lid , displayDetails , null ) ;
apiGet ( "/linode/instances/" + data . params . lid + "/disks" , displayDisks , null ) ;
}
data . events [ i ] = event ;
continue ;
}
}
// Generate a new event row and replace the existing one
var eventRow = document . getElementById ( elements . eventRowPrefix + event . id ) ;
var extra = ( eventRow . className . indexOf ( elements . extraEvent ) != - 1 ) ;
eventRow . replaceWith ( createEventRow ( event , extra ) ) ;
// Update progress bar
ui . jobProgress . value += progress ;
ui . jobProgress . innerHTML = ( ui . jobProgress . value / ui . jobProgress . max * 100 ) . toFixed ( 0 ) + "%" ;
ui . jobProgress . title = ui . jobProgress . innerHTML ;
if ( ui . jobProgress . value == ui . jobProgress . max )
ui . jobProgressRow . style . display = "none" ;
// Refresh again if not complete
if ( ! event . status . match ( /failed|finished|notification/ ) )
window . setTimeout ( getEvent , settings . refreshRate , event . id ) ;
} ;
// Attach onload handler
window . addEventListener ( "load" , setup ) ;
} ) ( ) ;