diff --git a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt index e6e096ab122..8944c37584e 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt +++ b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt @@ -261,6 +261,9 @@ Release 2.3.0 - UNRELEASED HDFS-5379. Update links to datanode information in dfshealth.html. (Haohui Mai via jing9) + HDFS-5382. Implement the UI of browsing filesystems in HTML 5 page. (Haohui + Mai via jing9) + IMPROVEMENTS HDFS-5267. Remove volatile from LightWeightHashSet. (Junping Du via llu) diff --git a/hadoop-hdfs-project/hadoop-hdfs/pom.xml b/hadoop-hdfs-project/hadoop-hdfs/pom.xml index 86a3c5ae6a9..4fa7213746b 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/pom.xml +++ b/hadoop-hdfs-project/hadoop-hdfs/pom.xml @@ -550,6 +550,8 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> src/main/webapps/static/dust-full-2.0.0.min.js src/main/webapps/static/dust-helpers-1.1.1.min.js src/main/webapps/hdfs/dfshealth.dust.html + src/main/webapps/hdfs/explorer-block-info.dust.html + src/main/webapps/hdfs/explorer.dust.html diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/web/resources/DatanodeWebHdfsMethods.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/web/resources/DatanodeWebHdfsMethods.java index 973d0916b90..6e8d605d767 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/web/resources/DatanodeWebHdfsMethods.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/web/resources/DatanodeWebHdfsMethods.java @@ -413,8 +413,15 @@ public class DatanodeWebHdfsMethods { final long n = length.getValue() != null ? Math.min(length.getValue(), in.getVisibleLength() - offset.getValue()) : in.getVisibleLength() - offset.getValue(); - return Response.ok(new OpenEntity(in, n, dfsclient)).type( - MediaType.APPLICATION_OCTET_STREAM).build(); + + /** + * Allow the Web UI to perform an AJAX request to get the data. + */ + return Response.ok(new OpenEntity(in, n, dfsclient)) + .type(MediaType.APPLICATION_OCTET_STREAM) + .header("Access-Control-Allow-Methods", "GET") + .header("Access-Control-Allow-Origin", "*") + .build(); } case GETFILECHECKSUM: { diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/dfshealth.dust.html b/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/dfshealth.dust.html index 9924825ea55..e7bb5a2b123 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/dfshealth.dust.html +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/dfshealth.dust.html @@ -47,7 +47,7 @@ -Browse the filesystem NameNode Logs +Browse the filesystem NameNode Logs
@@ -56,7 +56,7 @@

- Security is {#nnstat}{#SecurityModeEnabled}on{:else}off{/SecurityModeEnabled}{/nnstat}.

+ Security is {#nnstat}{#SecurityEnabled}on{:else}off{/SecurityEnabled}{/nnstat}.

{#nn}{#Safemode}{.}{:else}Safemode is off.{/Safemode}{/nn}

@@ -207,7 +207,7 @@ {#nn.LiveNodes} - {name} ({xferaddr}) + {name} ({xferaddr}) {lastContact} {adminState} {capacity|fmt_bytes} diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/dfshealth.js b/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/dfshealth.js index 852b8618449..a1fea90e3ea 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/dfshealth.js +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/dfshealth.js @@ -19,19 +19,6 @@ "use strict"; var data = {}; - function generate_browse_dn_link(info_http_addr, info_https_addr) { - var is_https = window.location.protocol === 'https:'; - var authority = is_https ? info_https_addr : info_http_addr; - - var nn_info_port = window.location.port; - if (nn_info_port === "") { - nn_info_port = is_https ? 443 : 80; - } - - var l = '//' + authority + '/browseDirectory.jsp?dir=%2F&namenodeInfoPort=' + - nn_info_port + '&nnaddr=' + data.nnstat.HostAndPort; - return l; - } function render() { var helpers = { @@ -56,24 +43,7 @@ load_templates(dust, TEMPLATES, function() { dust.render('dfshealth', base.push(data), function(err, out) { - - $('#panel').append(out); - - $('#browse-dir-first').click(function () { - var len = data.nn.LiveNodes.length; - if (len < 1) { - show_err_msg('Cannot browse the DFS since there are no live nodes available.'); - return false; - } - - var dn = data.nn.LiveNodes[Math.floor(Math.random() * len)]; - window.location.href = generate_browse_dn_link(dn.infoAddr, dn.infoSecureAddr); - }); - - $('.browse-dir-links').click(function () { - var http_addr = $(this).attr('info-http-addr'), https_addr = $(this).attr('info-https-addr'); - window.location.href = generate_browse_dn_link(http_addr, https_addr); - }); + $('#panel').html(out); }); }, function () { show_err_msg('Failed to load the page.'); diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/explorer-block-info.dust.html b/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/explorer-block-info.dust.html new file mode 100644 index 00000000000..5e42b6881d9 --- /dev/null +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/explorer-block-info.dust.html @@ -0,0 +1,13 @@ +{#block} +

Block ID: {blockId}

+

Block Pool ID: {blockPoolId}

+

Generation Stamp: {generationStamp}

+

Size: {numBytes}

+{/block} +

Availability: +

+

diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/explorer.dust.html b/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/explorer.dust.html new file mode 100644 index 00000000000..7e45860a403 --- /dev/null +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/explorer.dust.html @@ -0,0 +1,26 @@ + + + + + + + + + + + + + +{#FileStatus} + + + + + + + + + +{/FileStatus} + +
PermissionOwnerGroupSizeReplicationBlock SizeName
{#helper_to_permission/}{owner}{group}{length|fmt_bytes}{replication}{blockSize|fmt_bytes}{pathSuffix}
diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/explorer.html b/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/explorer.html new file mode 100644 index 00000000000..ffa0935a777 --- /dev/null +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/explorer.html @@ -0,0 +1,86 @@ + + + + + + + Browsing HDFS + + + +
+ + +
+
+
+
+
+
+
+
+ +
+

Hadoop, 2013.

+ + diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/explorer.js b/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/explorer.js new file mode 100644 index 00000000000..72d3c8d0495 --- /dev/null +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/webapps/hdfs/explorer.js @@ -0,0 +1,182 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +(function() { + "use strict"; + + // The chunk size of tailing the files, i.e., how many bytes will be shown + // in the preview. + var TAIL_CHUNK_SIZE = 32768; + var helpers = { + 'helper_to_permission': function(chunk, ctx, bodies, params) { + var p = ctx.current().permission; + var dir = ctx.current().type == 'DIRECTORY' ? 'd' : '-'; + var symbols = [ '---', '--x', '-w-', '-wx', 'r--', 'r-x', 'rw-', 'rwx' ]; + var sticky = p > 1000; + + var res = ""; + for (var i = 0; i < 3; ++i) { + res = symbols[(p % 10)] + res; + p = Math.floor(p / 10); + } + + if (sticky) { + var exec = ((parms.perm % 10) & 1) == 1; + res[res.length - 1] = exec ? 't' : 'T'; + } + + chunk.write(dir + res); + return chunk; + } + }; + + var base = dust.makeBase(helpers); + var current_directory = ""; + + function show_err_msg(msg) { + $('#alert-panel-body').html(msg); + $('#alert-panel').show(); + } + + function network_error_handler(url) { + return function (jqxhr, text, err) { + var msg = '

Failed to retreive data from ' + url + ', cause: ' + err + '

'; + if (url.indexOf('/webhdfs/v1') === 0) { + msg += '

WebHDFS might be disabled. WebHDFS is required to browse the filesystem.

'; + } + show_err_msg(msg); + }; + } + + function append_path(prefix, s) { + var l = prefix.length; + var p = l > 0 && prefix[l - 1] == '/' ? prefix.substring(0, l - 1) : prefix; + return p + '/' + s; + } + + function get_response(data, type) { + return data[type] !== undefined ? data[type] : null; + } + + function get_response_err_msg(data) { + var msg = data.RemoteException !== undefined ? data.RemoteException.message : ""; + return msg; + } + + function view_file_details(path, abs_path) { + function show_block_info(blocks) { + var menus = $('#file-info-blockinfo-list'); + menus.empty(); + + menus.data("blocks", blocks); + menus.change(function() { + var d = $(this).data('blocks')[$(this).val()]; + if (d === undefined) { + return; + } + + dust.render('block-info', d, function(err, out) { + $('#file-info-blockinfo-body').html(out); + }); + + }); + for (var i = 0; i < blocks.length; ++i) { + var item = $(''); + menus.append(item); + } + menus.change(); + } + + var url = '/webhdfs/v1' + abs_path + '?op=GET_BLOCK_LOCATIONS'; + $.ajax({"url": url, "crossDomain": true}).done(function(data) { + var d = get_response(data, "LocatedBlocks"); + if (d === null) { + show_err_msg(get_response_err_msg(data)); + return; + } + + $('#file-info-tail').hide(); + $('#file-info-title').text("File information - " + path); + + var download_url = '/webhdfs/v1' + abs_path + '/?op=OPEN'; + + $('#file-info-download').attr('href', download_url); + $('#file-info-preview').click(function() { + var offset = d.fileLength - TAIL_CHUNK_SIZE; + var url = offset > 0 ? download_url + '&offset=' + offset : download_url; + $.get(url, function(t) { + $('#file-info-preview-body').val(t); + $('#file-info-tail').show(); + }, "text").error(network_error_handler(url)); + }); + + if (d.fileLength > 0) { + show_block_info(d.locatedBlocks); + $('#file-info-blockinfo-panel').show(); + } else { + $('#file-info-blockinfo-panel').hide(); + } + $('#file-info').modal(); + }).error(network_error_handler(url)); + } + + function browse_directory(dir) { + var url = '/webhdfs/v1' + dir + '?op=LISTSTATUS'; + $.get(url, function(data) { + var d = get_response(data, "FileStatuses"); + if (d === null) { + show_err_msg(get_response_err_msg(data)); + return; + } + + current_directory = dir; + $('#directory').val(dir); + dust.render('explorer', base.push(d), function(err, out) { + $('#panel').html(out); + + $('.explorer-browse-links').click(function() { + var type = $(this).attr('inode-type'); + var path = $(this).attr('inode-path'); + var abs_path = append_path(current_directory, path); + if (type == 'DIRECTORY') { + browse_directory(abs_path); + } else { + view_file_details(path, abs_path); + } + }); + }); + }).error(network_error_handler(url)); + } + + + function init() { + var templates = [ + { 'name': 'explorer', 'url': 'explorer.dust.html'}, + { 'name': 'block-info', 'url': 'explorer-block-info.dust.html'} + ]; + + load_templates(dust, templates, function () { + var b = function() { browse_directory($('#directory').val()); }; + $('#btn-nav-directory').click(b); + browse_directory('/'); + }, function (url, jqxhr, text, err) { + network_error_handler(url)(jqxhr, text, err); + }); + } + + init(); +})();