Merge branch 'release/1.9.3'

pull/271/head 1.9.3
Anthony Lapenna 2016-10-09 10:50:46 +13:00
commit 09a5534499
20 changed files with 117 additions and 95 deletions

View File

@ -1,79 +1,47 @@
# Portainer
The easiest way to manage Docker.
<p align="center">
<img title="portainer" src='http://portainer.io/images/logo_alt.png' />
</p>
[![Microbadger version](https://images.microbadger.com/badges/version/portainer/portainer.svg)](https://microbadger.com/images/portainer/portainer "Latest version on Docker Hub")
[![Microbadger](https://images.microbadger.com/badges/image/portainer/portainer.svg)](http://microbadger.com/images/portainer/portainer "Image size")
[![Documentation Status](https://readthedocs.org/projects/portainer/badge/?version=stable)](http://portainer.readthedocs.io/en/stable/?badge=stable)
[![Documentation Status](https://readthedocs.org/projects/portainer/badge/?version=latest)](http://portainer.readthedocs.io/en/latest/?badge=latest)
[![Gitter](https://badges.gitter.im/portainer/Lobby.svg)](https://gitter.im/portainer/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
Portainer is a lightweight management UI which allows you to **easily** manage your Docker host or Swarm cluster.
**_Portainer_** is a lightweight management UI which allows you to **easily** manage your Docker host or Swarm cluster.
# Usage
**_Portainer_** is meant to be as **simple** to deploy as it is to use. It consists of a single container that can run on any Docker for Linux engine. A Docker for Windows version is on its way !
It's really simple to deploy it using Docker:
**_Portainer_** allows you to manage your Docker containers, images, volumes, networks and more ! It is compatible with the *standalone Docker* engine and with *Docker Swarm*.
```shell
$ docker run -d -p 9000:9000 portainer/portainer -H tcp://<DOCKER_HOST>:<DOCKER_PORT>
```
## Demo
Just point it at your targeted Docker host and then access Portainer by hitting [http://localhost:9000](http://localhost:9000) with a web browser.
<img src="http://portainer.io/images/screenshots/portainer.gif" width="77%"/>
If your target is a Docker Swarm cluster or a Docker cluster using *swarm mode*, just add the flag `--swarm`:
You can try out the public demo instance: http://demo.portainer.io/ (login with the username **demo** and the password **tryportainer**).
```shell
$ docker run -d -p 9000:9000 portainer/portainer -H tcp://<SWARM_HOST>:<SWARM_PORT> --swarm
```
Please note that the public demo cluster is **reset every 15min**.
If you don't specify any target, its default behaviour is to use a bind mount on the Docker socket so you can easily deploy it to manage your local Docker host:
## Getting started
```shell
$ docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer
```
* [Deploy Portainer](https://portainer.readthedocs.io/en/latest/deployment.html)
* [Documentation](https://portainer.readthedocs.io)
Have a look at our [documentation](http://portainer.readthedocs.io/en/stable/deployment.html) for more deployment options.
## Getting help
# Configuration
* Issues: https://github.com/portainer/portainer/issues
* FAQ: https://portainer.readthedocs.io/en/latest/faq.html
* Gitter (chat): https://gitter.im/portainer/Lobby
* Slack: http://portainer.io/slack/
Portainer is easy to tune using CLI flags.
## Reporting bugs and contributing
## Hiding specific containers
* Want to report a bug or request a feature? Please open [an issue](https://github.com/portainer/portainer/issues/new).
* Want to help us build **_portainer_**? Follow our [contribution guidelines](https://portainer.readthedocs.io/en/latest/contribute.html) to build it locally and make a pull request. We need all the help we can get!
Portainer allows you to hide container with a specific label by using the `-l` flag.
## Limitations
For example, take a container started with the label `owner=acme`:
```shell
$ docker run -d --label owner=acme nginx
```
Simply add the `-l owner=acme` option on the CLI when starting Portainer:
```shell
$ docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer -l owner=acme
```
## Use your own templates
Portainer allows you to rapidly deploy containers using `App Templates`.
By default [Portainer templates](https://raw.githubusercontent.com/portainer/templates/master/templates.json) will be used but you can also define your own templates.
Add the `--templates` flag and specify the external location of your templates when starting Portainer:
```shell
$ docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer --templates http://my-host.my-domain/templates.json
```
For more information about hosting your own template definitions and the format, see the [templates documentation](http://portainer.readthedocs.io/en/stable/templates.html).
Check our [documentation](http://portainer.readthedocs.io/en/stable/configuration.html) for more configuration options.
# FAQ
Be sure to check our [FAQ](http://portainer.readthedocs.io/en/stable/faq.html) if you are missing some information.
# Limitations
Portainer has full support for the following Docker versions:
**_Portainer_** has full support for the following Docker versions:
* Docker 1.10 to Docker 1.12 (including `swarm-mode`)
* Docker Swarm >= 1.2.3

View File

@ -6,7 +6,7 @@ import (
// main is the entry point of the program
func main() {
kingpin.Version("1.9.2")
kingpin.Version("1.9.3")
var (
endpoint = kingpin.Flag("host", "Dockerd endpoint").Default("unix:///var/run/docker.sock").Short('H').String()
addr = kingpin.Flag("bind", "Address and port to serve Portainer").Default(":9000").Short('p').String()

View File

@ -188,4 +188,4 @@ angular.module('portainer', [
.constant('DOCKER_PORT', '') // Docker port, leave as an empty string if no port is requred. If you have a port, prefix it with a ':' i.e. :4243
.constant('CONFIG_ENDPOINT', 'settings')
.constant('TEMPLATES_ENDPOINT', 'templates')
.constant('UI_VERSION', 'v1.9.2');
.constant('UI_VERSION', 'v1.9.3');

View File

@ -98,6 +98,9 @@
<span ng-if="container.Ports.length == 0" >-</span>
</td>
</tr>
<tr ng-if="!containers">
<td colspan="8" class="text-center text-muted">Loading...</td>
</tr>
<tr ng-if="containers.length == 0">
<td colspan="8" class="text-center text-muted">No containers available.</td>
</tr>

View File

@ -8,7 +8,6 @@ function ($scope, Container, ContainerHelper, Info, Settings, Messages, Config)
$scope.sortReverse = false;
$scope.state.selectedItemCount = 0;
$scope.swarm_mode = false;
$scope.containers = [];
$scope.order = function (sortType) {
$scope.sortReverse = ($scope.sortType === sortType) ? !$scope.sortReverse : false;
@ -34,6 +33,10 @@ function ($scope, Container, ContainerHelper, Info, Settings, Messages, Config)
return model;
});
$('#loadContainersSpinner').hide();
}, function (e) {
$('#loadContainersSpinner').hide();
Messages.error("Failure", e, "Unable to retrieve containers");
$scope.containers = [];
});
};

View File

@ -107,6 +107,9 @@
<td>{{ image.VirtualSize|humansize }}</td>
<td>{{ image.Created|getisodatefromtimestamp }}</td>
</tr>
<tr ng-if="!images">
<td colspan="5" class="text-center text-muted">Loading...</td>
</tr>
<tr ng-if="images.length == 0">
<td colspan="5" class="text-center text-muted">No images available.</td>
</tr>

View File

@ -5,7 +5,6 @@ function ($scope, $state, Config, Image, Messages) {
$scope.sortType = 'RepoTags';
$scope.sortReverse = true;
$scope.state.selectedItemCount = 0;
$scope.images = [];
$scope.config = {
Image: '',
@ -98,6 +97,7 @@ function ($scope, $state, Config, Image, Messages) {
}, function (e) {
$('#loadImagesSpinner').hide();
Messages.error("Failure", e, "Unable to retrieve images");
$scope.images = [];
});
}

View File

@ -131,6 +131,9 @@
<td>{{ network.IPAM.Config[0].Subnet ? network.IPAM.Config[0].Subnet : '-' }}</td>
<td>{{ network.IPAM.Config[0].Gateway ? network.IPAM.Config[0].Gateway : '-' }}</td>
</tr>
<tr ng-if="!networks">
<td colspan="8" class="text-center text-muted">Loading...</td>
</tr>
<tr ng-if="networks.length == 0">
<td colspan="8" class="text-center text-muted">No networks available.</td>
</tr>

View File

@ -6,8 +6,6 @@ function ($scope, $state, Network, Config, Messages) {
$scope.state.advancedSettings = false;
$scope.sortType = 'Name';
$scope.sortReverse = false;
$scope.networks = [];
$scope.config = {
Name: ''
};
@ -93,6 +91,7 @@ function ($scope, $state, Network, Config, Messages) {
}, function (e) {
$('#loadNetworksSpinner').hide();
Messages.error("Failure", e, "Unable to retrieve networks");
$scope.networks = [];
});
}

View File

@ -69,6 +69,12 @@
</span>
</td>
</tr>
<tr ng-if="!services">
<td colspan="4" class="text-center text-muted">Loading...</td>
</tr>
<tr ng-if="services.length == 0">
<td colspan="4" class="text-center text-muted">No services available.</td>
</tr>
</tbody>
</table>
</div>

View File

@ -1,8 +1,6 @@
angular.module('services', [])
.controller('ServicesController', ['$scope', '$stateParams', '$state', 'Service', 'ServiceHelper', 'Messages',
function ($scope, $stateParams, $state, Service, ServiceHelper, Messages) {
$scope.services = [];
$scope.state = {};
$scope.state.selectedItemCount = 0;
$scope.sortType = 'Name';
@ -77,6 +75,7 @@ function ($scope, $stateParams, $state, Service, ServiceHelper, Messages) {
}, function(e) {
$('#loadServicesSpinner').hide();
Messages.error("Failure", e, "Unable to retrieve services");
$scope.services = [];
});
}

View File

@ -77,11 +77,14 @@
</rd-widget-header>
<rd-widget-body classes="padding">
<div class="template-list">
<div ng-repeat="tpl in templates" class="container-template hvr-grow" id="template_{{ $index }}" ng-click="selectTemplate($index)">
<div ng-repeat="tpl in templates" class="container-template hvr-underline-from-center" id="template_{{ $index }}" ng-click="selectTemplate($index)">
<img class="logo" ng-src="{{ tpl.logo }}" />
<div class="title">{{ tpl.title }}</div>
<div class="description">{{ tpl.description }}</div>
</div>
<div ng-if="!templates" class="text-center text-muted">
Loading...
</div>
<div ng-if="templates.length == 0" class="text-center text-muted">
No templates available.
</div>

View File

@ -1,13 +1,11 @@
angular.module('templates', [])
.controller('TemplatesController', ['$scope', '$q', '$state', '$filter', 'Config', 'Info', 'Container', 'ContainerHelper', 'Image', 'Volume', 'Network', 'Templates', 'Messages',
function ($scope, $q, $state, $filter, Config, Info, Container, ContainerHelper, Image, Volume, Network, Templates, Messages) {
$scope.templates = [];
$scope.selectedTemplate = null;
$scope.formValues = {
network: "",
name: ""
};
$scope.templates = [];
var selectedItem = -1;
@ -161,6 +159,7 @@ function ($scope, $q, $state, $filter, Config, Info, Container, ContainerHelper,
}, function (e) {
$('#loadTemplatesSpinner').hide();
Messages.error("Failure", e, "Unable to retrieve apps list");
$scope.templates = [];
});
}

View File

@ -59,6 +59,9 @@
<td>{{ volume.Driver }}</td>
<td>{{ volume.Mountpoint }}</td>
</tr>
<tr ng-if="!volumes">
<td colspan="4" class="text-center text-muted">Loading...</td>
</tr>
<tr ng-if="volumes.length == 0">
<td colspan="4" class="text-center text-muted">No volumes available.</td>
</tr>

View File

@ -5,8 +5,6 @@ function ($scope, $state, Volume, Messages) {
$scope.state.selectedItemCount = 0;
$scope.sortType = 'Name';
$scope.sortReverse = true;
$scope.volumes = [];
$scope.config = {
Name: ''
};
@ -61,6 +59,7 @@ function ($scope, $state, Volume, Messages) {
}, function (e) {
$('#loadVolumesSpinner').hide();
Messages.error("Failure", e, "Unable to retrieve volumes");
$scope.volumes = [];
});
}
fetchVolumes();

View File

@ -8,7 +8,7 @@ angular
icon: '='
},
transclude: true,
template: '<div class="widget-header"><div class="row"><span class="pull-left"><img class="custom-header-ico" ng-src="{{icon}}"></img> <span class="small text-muted"> {{title}} </span> </span><span class="pull-right col-xs-6 col-sm-4" ng-transclude></span></div></div>',
template: '<div class="widget-header"><div class="row"><span class="pull-left"><img class="custom-header-ico" ng-src="{{icon}}"></img> <span class="text-muted"> {{title}} </span> </span><span class="pull-right col-xs-6 col-sm-4" ng-transclude></span></div></div>',
restrict: 'E'
};
return directive;

View File

@ -217,16 +217,67 @@ input[type="radio"] {
}
.custom-header-ico {
max-width: 16px;
max-height: 16px;
max-width: 32px;
max-height: 32px;
margin-right: 2px;
}
.btn-responsive {
padding: 5px 10px;
font-size: 12px;
line-height: 1.5;
border-radius: 3px;
}
@media screen and (min-width: 1107px) {
.btn-responsive {
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
border-radius: 4px;
}
}
/* Underline From Center */
.hvr-underline-from-center {
display: inline-block;
vertical-align: middle;
-webkit-transform: translateZ(0);
transform: translateZ(0);
box-shadow: 0 0 1px rgba(0, 0, 0, 0);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-moz-osx-font-smoothing: grayscale;
position: relative;
overflow: hidden;
}
.hvr-underline-from-center:before {
content: "";
position: absolute;
z-index: -1;
left: 50%;
right: 50%;
bottom: 0;
background: #85898b;
height: 2px;
-webkit-transition-property: left, right;
transition-property: left, right;
-webkit-transition-duration: 0.3s;
transition-duration: 0.3s;
-webkit-transition-timing-function: ease-out;
transition-timing-function: ease-out;
}
.hvr-underline-from-center:hover:before, .hvr-underline-from-center:focus:before, .hvr-underline-from-center:active:before {
left: 0;
right: 0;
}
.container-template {
font-size: 1em;
width: 256px;
height: 128px;
margin: 10px;
padding: 10px;
margin: 15px;
padding: 5px;
display: flex;
flex-direction: column;
justify-content: center;
@ -259,20 +310,5 @@ input[type="radio"] {
.container-template .description {
text-align: center;
font-size: 0.8em;
}
.btn-responsive {
padding: 5px 10px;
font-size: 12px;
line-height: 1.5;
border-radius: 3px;
}
@media screen and (min-width: 1107px) {
.btn-responsive {
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857143;
border-radius: 4px;
}
margin-bottom: 5px;
}

View File

@ -1,6 +1,6 @@
{
"name": "portainer",
"version": "1.9.2",
"version": "1.9.3",
"homepage": "https://github.com/portainer/portainer",
"authors": [
"Anthony Lapenna <anthony.lapenna at gmail dot com>"
@ -35,7 +35,6 @@
"bootstrap": "~3.3.6",
"font-awesome": "~4.6.3",
"filesize": "~3.3.0",
"Hover": "2.0.2",
"jquery": "1.11.1",
"jquery.gritter": "1.7.4",
"lodash": "4.12.0",

View File

@ -88,8 +88,7 @@ module.exports = function (grunt) {
'bower_components/font-awesome/css/font-awesome.min.css',
'bower_components/rdash-ui/dist/css/rdash.min.css',
'bower_components/angular-ui-select/dist/select.min.css',
'bower_components/xterm.js/dist/xterm.css',
'bower_components/Hover/css/hover-min.css'
'bower_components/xterm.js/dist/xterm.css'
]
},
clean: {

View File

@ -2,7 +2,7 @@
"author": "Portainer.io",
"name": "portainer",
"homepage": "http://portainer.io",
"version": "1.9.2",
"version": "1.9.3",
"repository": {
"type": "git",
"url": "git@github.com:portainer/portainer.git"