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..." ;
2020-01-10 00:24:59 -05:00
detailsCell . appendChild ( jobType );
detailsCell . appendChild ( jobDetails );
detailsCell . appendChild ( br );
detailsCell . appendChild ( jobInfo );
row . appendChild ( detailsCell );
2020-01-22 23:03:30 -05:00
// Progress cell
var progressCell = document . createElement ( "td" );
if ( event . percent_complete && event . percent_complete != 100 )
progressCell . innerHTML = event . percent_complete + "%" ;
if ( event . time_remaining ) {
if ( progressCell . innerHTML . length )
progressCell . innerHTML += ", " ;
var times = event . time_remaining . split ( ":" );
var ms = 0 ;
ms += parseInt ( times [ 0 ]) * 3600000 ;
ms += parseInt ( times [ 1 ]) * 60000 ;
ms += parseInt ( times [ 2 ]) * 1000 ;
progressCell . innerHTML += timeString ( ms , false ) + " to go" ;
}
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 );
})();