Fix the dependency issue (#231)
This commit is contained in:
3
vendor/github.com/hyperhq/hypercli/.dockerignore
generated
vendored
3
vendor/github.com/hyperhq/hypercli/.dockerignore
generated
vendored
@@ -1,3 +0,0 @@
|
||||
bundles
|
||||
.gopath
|
||||
vendor/pkg
|
||||
42
vendor/github.com/hyperhq/hypercli/.gitignore
generated
vendored
42
vendor/github.com/hyperhq/hypercli/.gitignore
generated
vendored
@@ -1,42 +0,0 @@
|
||||
# Docker project generated files to ignore
|
||||
# if you want to ignore files created by your editor/tools,
|
||||
# please consider a global .gitignore https://help.github.com/articles/ignoring-files
|
||||
*.exe
|
||||
*.exe~
|
||||
*.orig
|
||||
*.test
|
||||
.*.swp
|
||||
.DS_Store
|
||||
.bashrc
|
||||
.dotcloud
|
||||
.flymake*
|
||||
.git/
|
||||
.gopath/
|
||||
.hg/
|
||||
.vagrant*
|
||||
Vagrantfile
|
||||
a.out
|
||||
autogen/
|
||||
bin
|
||||
build_src
|
||||
bundles/
|
||||
docker/docker
|
||||
hyper/hyper
|
||||
dockerversion/version_autogen.go
|
||||
docs/AWS_S3_BUCKET
|
||||
docs/GITCOMMIT
|
||||
docs/GIT_BRANCH
|
||||
docs/VERSION
|
||||
docs/_build
|
||||
docs/_static
|
||||
docs/_templates
|
||||
docs/changed-files
|
||||
# generated by man/md2man-all.sh
|
||||
man/man1
|
||||
man/man5
|
||||
man/man8
|
||||
pyenv
|
||||
vendor/pkg/
|
||||
*.yml
|
||||
.idea
|
||||
integration-cli/util.conf
|
||||
171
vendor/github.com/hyperhq/hypercli/.mailmap
generated
vendored
171
vendor/github.com/hyperhq/hypercli/.mailmap
generated
vendored
@@ -1,171 +0,0 @@
|
||||
# Generate AUTHORS: hack/generate-authors.sh
|
||||
|
||||
# Tip for finding duplicates (besides scanning the output of AUTHORS for name
|
||||
# duplicates that aren't also email duplicates): scan the output of:
|
||||
# git log --format='%aE - %aN' | sort -uf
|
||||
#
|
||||
# For explanation on this file format: man git-shortlog
|
||||
|
||||
Patrick Stapleton <github@gdi2290.com>
|
||||
Shishir Mahajan <shishir.mahajan@redhat.com> <smahajan@redhat.com>
|
||||
Erwin van der Koogh <info@erronis.nl>
|
||||
Ahmed Kamal <email.ahmedkamal@googlemail.com>
|
||||
Tejesh Mehta <tejesh.mehta@gmail.com> <tj@init.me>
|
||||
Cristian Staretu <cristian.staretu@gmail.com>
|
||||
Cristian Staretu <cristian.staretu@gmail.com> <unclejacksons@gmail.com>
|
||||
Cristian Staretu <cristian.staretu@gmail.com> <unclejack@users.noreply.github.com>
|
||||
Marcus Linke <marcus.linke@gmx.de>
|
||||
Aleksandrs Fadins <aleks@s-ko.net>
|
||||
Christopher Latham <sudosurootdev@gmail.com>
|
||||
Hu Keping <hukeping@huawei.com>
|
||||
Wayne Chang <wayne@neverfear.org>
|
||||
Chen Chao <cc272309126@gmail.com>
|
||||
Daehyeok Mun <daehyeok@gmail.com>
|
||||
<daehyeok@gmail.com> <daehyeok@daehyeokui-MacBook-Air.local>
|
||||
<jt@yadutaf.fr> <admin@jtlebi.fr>
|
||||
<jeff@docker.com> <jefferya@programmerq.net>
|
||||
<charles.hooper@dotcloud.com> <chooper@plumata.com>
|
||||
<daniel.mizyrycki@dotcloud.com> <daniel@dotcloud.com>
|
||||
<daniel.mizyrycki@dotcloud.com> <mzdaniel@glidelink.net>
|
||||
Guillaume J. Charmes <guillaume.charmes@docker.com> <charmes.guillaume@gmail.com>
|
||||
<guillaume.charmes@docker.com> <guillaume@dotcloud.com>
|
||||
<guillaume.charmes@docker.com> <guillaume@docker.com>
|
||||
<guillaume.charmes@docker.com> <guillaume.charmes@dotcloud.com>
|
||||
<guillaume.charmes@docker.com> <guillaume@charmes.net>
|
||||
<kencochrane@gmail.com> <KenCochrane@gmail.com>
|
||||
Thatcher Peskens <thatcher@docker.com>
|
||||
Thatcher Peskens <thatcher@docker.com> <thatcher@dotcloud.com>
|
||||
Thatcher Peskens <thatcher@docker.com> dhrp <thatcher@gmx.net>
|
||||
Jérôme Petazzoni <jerome.petazzoni@dotcloud.com> jpetazzo <jerome.petazzoni@dotcloud.com>
|
||||
Jérôme Petazzoni <jerome.petazzoni@dotcloud.com> <jp@enix.org>
|
||||
Joffrey F <joffrey@docker.com>
|
||||
Joffrey F <joffrey@docker.com> <joffrey@dotcloud.com>
|
||||
Joffrey F <joffrey@docker.com> <f.joffrey@gmail.com>
|
||||
Tim Terhorst <mynamewastaken+git@gmail.com>
|
||||
Andy Smith <github@anarkystic.com>
|
||||
<kalessin@kalessin.fr> <louis@dotcloud.com>
|
||||
<victor.vieux@docker.com> <victor.vieux@dotcloud.com>
|
||||
<victor.vieux@docker.com> <victor@dotcloud.com>
|
||||
<victor.vieux@docker.com> <dev@vvieux.com>
|
||||
<victor.vieux@docker.com> <victor@docker.com>
|
||||
<victor.vieux@docker.com> <vieux@docker.com>
|
||||
<victor.vieux@docker.com> <victorvieux@gmail.com>
|
||||
<dominik@honnef.co> <dominikh@fork-bomb.org>
|
||||
<ehanchrow@ine.com> <eric.hanchrow@gmail.com>
|
||||
Walter Stanish <walter@pratyeka.org>
|
||||
<daniel@gasienica.ch> <dgasienica@zynga.com>
|
||||
Roberto Hashioka <roberto_hashioka@hotmail.com>
|
||||
Konstantin Pelykh <kpelykh@zettaset.com>
|
||||
David Sissitka <me@dsissitka.com>
|
||||
Nolan Darilek <nolan@thewordnerd.info>
|
||||
<mastahyeti@gmail.com> <mastahyeti@users.noreply.github.com>
|
||||
Benoit Chesneau <bchesneau@gmail.com>
|
||||
Jordan Arentsen <blissdev@gmail.com>
|
||||
Daniel Garcia <daniel@danielgarcia.info>
|
||||
Miguel Angel Fernández <elmendalerenda@gmail.com>
|
||||
Bhiraj Butala <abhiraj.butala@gmail.com>
|
||||
Faiz Khan <faizkhan00@gmail.com>
|
||||
Victor Lyuboslavsky <victor@victoreda.com>
|
||||
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
|
||||
Matthew Mueller <mattmuelle@gmail.com>
|
||||
<mosoni@ebay.com> <mohitsoni1989@gmail.com>
|
||||
Shih-Yuan Lee <fourdollars@gmail.com>
|
||||
Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com> root <root@vagrant-ubuntu-12.10.vagrantup.com>
|
||||
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
|
||||
<proppy@google.com> <proppy@aminche.com>
|
||||
<michael@docker.com> <michael@crosbymichael.com>
|
||||
<michael@docker.com> <crosby.michael@gmail.com>
|
||||
<michael@docker.com> <crosbymichael@gmail.com>
|
||||
<github@developersupport.net> <github@metaliveblog.com>
|
||||
<brandon@ifup.org> <brandon@ifup.co>
|
||||
<dano@spotify.com> <daniel.norberg@gmail.com>
|
||||
<danny@codeaholics.org> <Danny.Yates@mailonline.co.uk>
|
||||
<gurjeet@singh.im> <singh.gurjeet@gmail.com>
|
||||
<shawn@churchofgit.com> <shawnlandden@gmail.com>
|
||||
<sjoerd-github@linuxonly.nl> <sjoerd@byte.nl>
|
||||
<solomon@docker.com> <solomon.hykes@dotcloud.com>
|
||||
<solomon@docker.com> <solomon@dotcloud.com>
|
||||
<solomon@docker.com> <s@docker.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <SvenDowideit@fosiki.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <SvenDowideit@docker.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <¨SvenDowideit@home.org.au¨>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <SvenDowideit@users.noreply.github.com>
|
||||
Sven Dowideit <SvenDowideit@home.org.au> <sven@t440s.home.gateway>
|
||||
<alexl@redhat.com> <alexander.larsson@gmail.com>
|
||||
Alexandr Morozov <lk4d4math@gmail.com>
|
||||
<git.nivoc@neverbox.com> <kuehnle@online.de>
|
||||
O.S. Tezer <ostezer@gmail.com>
|
||||
<ostezer@gmail.com> <ostezer@users.noreply.github.com>
|
||||
Roberto G. Hashioka <roberto.hashioka@docker.com> <roberto_hashioka@hotmail.com>
|
||||
<justin.p.simonelis@gmail.com> <justin.simonelis@PTS-JSIMON2.toronto.exclamation.com>
|
||||
<taim@bosboot.org> <maztaim@users.noreply.github.com>
|
||||
<viktor.vojnovski@amadeus.com> <vojnovski@gmail.com>
|
||||
<vbatts@redhat.com> <vbatts@hashbangbash.com>
|
||||
<altsysrq@gmail.com> <iamironbob@gmail.com>
|
||||
Sridhar Ratnakumar <sridharr@activestate.com>
|
||||
Sridhar Ratnakumar <sridharr@activestate.com> <github@srid.name>
|
||||
Liang-Chi Hsieh <viirya@gmail.com>
|
||||
Aleksa Sarai <cyphar@cyphar.com>
|
||||
Will Weaver <monkey@buildingbananas.com>
|
||||
Timothy Hobbs <timothyhobbs@seznam.cz>
|
||||
Nathan LeClaire <nathan.leclaire@docker.com> <nathan.leclaire@gmail.com>
|
||||
Nathan LeClaire <nathan.leclaire@docker.com> <nathanleclaire@gmail.com>
|
||||
<github@hollensbe.org> <erik+github@hollensbe.org>
|
||||
<github@albersweb.de> <albers@users.noreply.github.com>
|
||||
<lsm5@fedoraproject.org> <lsm5@redhat.com>
|
||||
<marc@marc-abramowitz.com> <msabramo@gmail.com>
|
||||
Matthew Heon <mheon@redhat.com> <mheon@mheonlaptop.redhat.com>
|
||||
<bernat@luffy.cx> <vincent@bernat.im>
|
||||
<p@pwaller.net> <peter@scraperwiki.com>
|
||||
<andrew.weiss@outlook.com> <andrew.weiss@microsoft.com>
|
||||
Francisco Carriedo <fcarriedo@gmail.com>
|
||||
<julienbordellier@gmail.com> <git@julienbordellier.com>
|
||||
<ahmetb@microsoft.com> <ahmetalpbalkan@gmail.com>
|
||||
<lk4d4@docker.com> <lk4d4math@gmail.com>
|
||||
<arnaud.porterie@docker.com> <icecrime@gmail.com>
|
||||
<baloo@gandi.net> <superbaloo+registrations.github@superbaloo.net>
|
||||
Brian Goff <cpuguy83@gmail.com>
|
||||
<cpuguy83@gmail.com> <bgoff@cpuguy83-mbp.home>
|
||||
<ewindisch@docker.com> <eric@windisch.us>
|
||||
<frank.rosquin+github@gmail.com> <frank.rosquin@gmail.com>
|
||||
Hollie Teal <hollie@docker.com>
|
||||
<hollie@docker.com> <hollie.teal@docker.com>
|
||||
<hollie@docker.com> <hollietealok@users.noreply.github.com>
|
||||
<huu@prismskylabs.com> <whoshuu@gmail.com>
|
||||
Jessica Frazelle <jess@docker.com> Jessie Frazelle <jfrazelle@users.noreply.github.com>
|
||||
<jess@docker.com> <jfrazelle@users.noreply.github.com>
|
||||
<konrad.wilhelm.kleine@gmail.com> <kwk@users.noreply.github.com>
|
||||
<tintypemolly@gmail.com> <tintypemolly@Ohui-MacBook-Pro.local>
|
||||
<estesp@linux.vnet.ibm.com> <estesp@gmail.com>
|
||||
<github@gone.nl> <thaJeztah@users.noreply.github.com>
|
||||
Thomas LEVEIL <thomasleveil@gmail.com> Thomas LÉVEIL <thomasleveil@users.noreply.github.com>
|
||||
<oi@truffles.me.uk> <timruffles@googlemail.com>
|
||||
<Vincent.Bernat@exoscale.ch> <bernat@luffy.cx>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <me@runcom.ninja>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <runcom@linux.com>
|
||||
Antonio Murdaca <antonio.murdaca@gmail.com> <runcom@users.noreply.github.com>
|
||||
Darren Shepherd <darren.s.shepherd@gmail.com> <darren@rancher.com>
|
||||
Deshi Xiao <dxiao@redhat.com> <dsxiao@dataman-inc.com>
|
||||
Deshi Xiao <dxiao@redhat.com> <xiaods@gmail.com>
|
||||
Doug Davis <dug@us.ibm.com> <duglin@users.noreply.github.com>
|
||||
Jacob Atzen <jacob@jacobatzen.dk> <jatzen@gmail.com>
|
||||
Jeff Nickoloff <jeff.nickoloff@gmail.com> <jeff@allingeek.com>
|
||||
<jess@docker.com> <princess@docker.com>
|
||||
John Howard (VM) <John.Howard@microsoft.com> John Howard <jhoward@microsoft.com>
|
||||
Madhu Venugopal <madhu@socketplane.io> <madhu@docker.com>
|
||||
Mary Anthony <mary.anthony@docker.com> <mary@docker.com>
|
||||
Mary Anthony <mary.anthony@docker.com> moxiegirl <mary@docker.com>
|
||||
Mary Anthony <mary.anthony@docker.com> <moxieandmore@gmail.com>
|
||||
mattyw <mattyw@me.com> <gh@mattyw.net>
|
||||
resouer <resouer@163.com> <resouer@gmail.com>
|
||||
AJ Bowen <aj@gandi.net> soulshake <amy@gandi.net>
|
||||
AJ Bowen <aj@gandi.net> soulshake <aj@gandi.net>
|
||||
Tibor Vass <teabee89@gmail.com> <tibor@docker.com>
|
||||
Tibor Vass <teabee89@gmail.com> <tiborvass@users.noreply.github.com>
|
||||
Vincent Bernat <bernat@luffy.cx> <Vincent.Bernat@exoscale.ch>
|
||||
Yestin Sun <sunyi0804@gmail.com> <yestin.sun@polyera.com>
|
||||
bin liu <liubin0329@users.noreply.github.com> <liubin0329@gmail.com>
|
||||
John Howard (VM) <John.Howard@microsoft.com> jhowardmsft <jhoward@microsoft.com>
|
||||
Ankush Agarwal <ankushagarwal11@gmail.com> <ankushagarwal@users.noreply.github.com>
|
||||
Tangi COLIN <tangicolin@gmail.com> tangicolin <tangicolin@gmail.com>
|
||||
2131
vendor/github.com/hyperhq/hypercli/CHANGELOG.md
generated
vendored
2131
vendor/github.com/hyperhq/hypercli/CHANGELOG.md
generated
vendored
File diff suppressed because it is too large
Load Diff
434
vendor/github.com/hyperhq/hypercli/CONTRIBUTING.md
generated
vendored
434
vendor/github.com/hyperhq/hypercli/CONTRIBUTING.md
generated
vendored
@@ -1,434 +0,0 @@
|
||||
# Contributing to Docker
|
||||
|
||||
Want to hack on Docker? Awesome! We have a contributor's guide that explains
|
||||
[setting up a Docker development environment and the contribution
|
||||
process](https://docs.docker.com/opensource/project/who-written-for/).
|
||||
|
||||

|
||||
|
||||
This page contains information about reporting issues as well as some tips and
|
||||
guidelines useful to experienced open source contributors. Finally, make sure
|
||||
you read our [community guidelines](#docker-community-guidelines) before you
|
||||
start participating.
|
||||
|
||||
## Topics
|
||||
|
||||
* [Reporting Security Issues](#reporting-security-issues)
|
||||
* [Design and Cleanup Proposals](#design-and-cleanup-proposals)
|
||||
* [Reporting Issues](#reporting-other-issues)
|
||||
* [Quick Contribution Tips and Guidelines](#quick-contribution-tips-and-guidelines)
|
||||
* [Community Guidelines](#docker-community-guidelines)
|
||||
|
||||
## Reporting security issues
|
||||
|
||||
The Docker maintainers take security seriously. If you discover a security
|
||||
issue, please bring it to their attention right away!
|
||||
|
||||
Please **DO NOT** file a public issue, instead send your report privately to
|
||||
[security@docker.com](mailto:security@docker.com).
|
||||
|
||||
Security reports are greatly appreciated and we will publicly thank you for it.
|
||||
We also like to send gifts—if you're into Docker schwag, make sure to let
|
||||
us know. We currently do not offer a paid security bounty program, but are not
|
||||
ruling it out in the future.
|
||||
|
||||
|
||||
## Reporting other issues
|
||||
|
||||
A great way to contribute to the project is to send a detailed report when you
|
||||
encounter an issue. We always appreciate a well-written, thorough bug report,
|
||||
and will thank you for it!
|
||||
|
||||
Check that [our issue database](https://github.com/docker/docker/issues)
|
||||
doesn't already include that problem or suggestion before submitting an issue.
|
||||
If you find a match, you can use the "subscribe" button to get notified on
|
||||
updates. Do *not* leave random "+1" or "I have this too" comments, as they
|
||||
only clutter the discussion, and don't help resolving it. However, if you
|
||||
have ways to reproduce the issue or have additional information that may help
|
||||
resolving the issue, please leave a comment.
|
||||
|
||||
When reporting issues, always include:
|
||||
|
||||
* The output of `docker version`.
|
||||
* The output of `docker info`.
|
||||
|
||||
Also include the steps required to reproduce the problem if possible and
|
||||
applicable. This information will help us review and fix your issue faster.
|
||||
When sending lengthy log-files, consider posting them as a gist (https://gist.github.com).
|
||||
Don't forget to remove sensitive data from your logfiles before posting (you can
|
||||
replace those parts with "REDACTED").
|
||||
|
||||
**Issue Report Template**:
|
||||
|
||||
```
|
||||
Description of problem:
|
||||
|
||||
|
||||
`docker version`:
|
||||
|
||||
|
||||
`docker info`:
|
||||
|
||||
|
||||
`uname -a`:
|
||||
|
||||
|
||||
Environment details (AWS, VirtualBox, physical, etc.):
|
||||
|
||||
|
||||
How reproducible:
|
||||
|
||||
|
||||
Steps to Reproduce:
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
|
||||
Actual Results:
|
||||
|
||||
|
||||
Expected Results:
|
||||
|
||||
|
||||
Additional info:
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
##Quick contribution tips and guidelines
|
||||
|
||||
This section gives the experienced contributor some tips and guidelines.
|
||||
|
||||
###Pull requests are always welcome
|
||||
|
||||
Not sure if that typo is worth a pull request? Found a bug and know how to fix
|
||||
it? Do it! We will appreciate it. Any significant improvement should be
|
||||
documented as [a GitHub issue](https://github.com/docker/docker/issues) before
|
||||
anybody starts working on it.
|
||||
|
||||
We are always thrilled to receive pull requests. We do our best to process them
|
||||
quickly. If your pull request is not accepted on the first try,
|
||||
don't get discouraged! Our contributor's guide explains [the review process we
|
||||
use for simple changes](https://docs.docker.com/opensource/workflow/make-a-contribution/).
|
||||
|
||||
### Design and cleanup proposals
|
||||
|
||||
You can propose new designs for existing Docker features. You can also design
|
||||
entirely new features. We really appreciate contributors who want to refactor or
|
||||
otherwise cleanup our project. For information on making these types of
|
||||
contributions, see [the advanced contribution
|
||||
section](https://docs.docker.com/opensource/workflow/advanced-contributing/) in
|
||||
the contributors guide.
|
||||
|
||||
We try hard to keep Docker lean and focused. Docker can't do everything for
|
||||
everybody. This means that we might decide against incorporating a new feature.
|
||||
However, there might be a way to implement that feature *on top of* Docker.
|
||||
|
||||
### Talking to other Docker users and contributors
|
||||
|
||||
<table class="tg">
|
||||
<col width="45%">
|
||||
<col width="65%">
|
||||
<tr>
|
||||
<td>Internet Relay Chat (IRC)</td>
|
||||
<td>
|
||||
<p>
|
||||
IRC a direct line to our most knowledgeable Docker users; we have
|
||||
both the <code>#docker</code> and <code>#docker-dev</code> group on
|
||||
<strong>irc.freenode.net</strong>.
|
||||
IRC is a rich chat protocol but it can overwhelm new users. You can search
|
||||
<a href="https://botbot.me/freenode/docker/#" target="_blank">our chat archives</a>.
|
||||
</p>
|
||||
Read our <a href="https://docs.docker.com/opensource/get-help/#irc-quickstart" target="_blank">IRC quickstart guide</a> for an easy way to get started.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Google Groups</td>
|
||||
<td>
|
||||
There are two groups.
|
||||
<a href="https://groups.google.com/forum/#!forum/docker-user" target="_blank">Docker-user</a>
|
||||
is for people using Docker containers.
|
||||
The <a href="https://groups.google.com/forum/#!forum/docker-dev" target="_blank">docker-dev</a>
|
||||
group is for contributors and other people contributing to the Docker
|
||||
project.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Twitter</td>
|
||||
<td>
|
||||
You can follow <a href="https://twitter.com/docker/" target="_blank">Docker's Twitter feed</a>
|
||||
to get updates on our products. You can also tweet us questions or just
|
||||
share blogs or stories.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stack Overflow</td>
|
||||
<td>
|
||||
Stack Overflow has over 17000 Docker questions listed. We regularly
|
||||
monitor <a href="https://stackoverflow.com/search?tab=newest&q=docker" target="_blank">Docker questions</a>
|
||||
and so do many other knowledgeable Docker users.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
### Conventions
|
||||
|
||||
Fork the repository and make changes on your fork in a feature branch:
|
||||
|
||||
- If it's a bug fix branch, name it XXXX-something where XXXX is the number of
|
||||
the issue.
|
||||
- If it's a feature branch, create an enhancement issue to announce
|
||||
your intentions, and name it XXXX-something where XXXX is the number of the
|
||||
issue.
|
||||
|
||||
Submit unit tests for your changes. Go has a great test framework built in; use
|
||||
it! Take a look at existing tests for inspiration. [Run the full test
|
||||
suite](https://docs.docker.com/opensource/project/test-and-docs/) on your branch before
|
||||
submitting a pull request.
|
||||
|
||||
Update the documentation when creating or modifying features. Test your
|
||||
documentation changes for clarity, concision, and correctness, as well as a
|
||||
clean documentation build. See our contributors guide for [our style
|
||||
guide](https://docs.docker.com/opensource/doc-style) and instructions on [building
|
||||
the documentation](https://docs.docker.com/opensource/project/test-and-docs/#build-and-test-the-documentation).
|
||||
|
||||
Write clean code. Universally formatted code promotes ease of writing, reading,
|
||||
and maintenance. Always run `gofmt -s -w file.go` on each changed file before
|
||||
committing your changes. Most editors have plug-ins that do this automatically.
|
||||
|
||||
Pull request descriptions should be as clear as possible and include a reference
|
||||
to all the issues that they address.
|
||||
|
||||
Commit messages must start with a capitalized and short summary (max. 50 chars)
|
||||
written in the imperative, followed by an optional, more detailed explanatory
|
||||
text which is separated from the summary by an empty line.
|
||||
|
||||
Code review comments may be added to your pull request. Discuss, then make the
|
||||
suggested modifications and push additional commits to your feature branch. Post
|
||||
a comment after pushing. New commits show up in the pull request automatically,
|
||||
but the reviewers are notified only when you comment.
|
||||
|
||||
Pull requests must be cleanly rebased on top of master without multiple branches
|
||||
mixed into the PR.
|
||||
|
||||
**Git tip**: If your PR no longer merges cleanly, use `rebase master` in your
|
||||
feature branch to update your pull request rather than `merge master`.
|
||||
|
||||
Before you make a pull request, squash your commits into logical units of work
|
||||
using `git rebase -i` and `git push -f`. A logical unit of work is a consistent
|
||||
set of patches that should be reviewed together: for example, upgrading the
|
||||
version of a vendored dependency and taking advantage of its now available new
|
||||
feature constitute two separate units of work. Implementing a new function and
|
||||
calling it in another file constitute a single logical unit of work. The very
|
||||
high majority of submissions should have a single commit, so if in doubt: squash
|
||||
down to one.
|
||||
|
||||
After every commit, [make sure the test suite passes]
|
||||
(https://docs.docker.com/opensource/project/test-and-docs/). Include documentation
|
||||
changes in the same pull request so that a revert would remove all traces of
|
||||
the feature or fix.
|
||||
|
||||
Include an issue reference like `Closes #XXXX` or `Fixes #XXXX` in commits that
|
||||
close an issue. Including references automatically closes the issue on a merge.
|
||||
|
||||
Please do not add yourself to the `AUTHORS` file, as it is regenerated regularly
|
||||
from the Git history.
|
||||
|
||||
Please see the [Coding Style](#coding-style) for further guidelines.
|
||||
|
||||
### Merge approval
|
||||
|
||||
Docker maintainers use LGTM (Looks Good To Me) in comments on the code review to
|
||||
indicate acceptance.
|
||||
|
||||
A change requires LGTMs from an absolute majority of the maintainers of each
|
||||
component affected. For example, if a change affects `docs/` and `registry/`, it
|
||||
needs an absolute majority from the maintainers of `docs/` AND, separately, an
|
||||
absolute majority of the maintainers of `registry/`.
|
||||
|
||||
For more details, see the [MAINTAINERS](MAINTAINERS) page.
|
||||
|
||||
### Sign your work
|
||||
|
||||
The sign-off is a simple line at the end of the explanation for the patch. Your
|
||||
signature certifies that you wrote the patch or otherwise have the right to pass
|
||||
it on as an open-source patch. The rules are pretty simple: if you can certify
|
||||
the below (from [developercertificate.org](http://developercertificate.org/)):
|
||||
|
||||
```
|
||||
Developer Certificate of Origin
|
||||
Version 1.1
|
||||
|
||||
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
||||
660 York Street, Suite 102,
|
||||
San Francisco, CA 94110 USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
```
|
||||
|
||||
Then you just add a line to every git commit message:
|
||||
|
||||
Signed-off-by: Joe Smith <joe.smith@email.com>
|
||||
|
||||
Use your real name (sorry, no pseudonyms or anonymous contributions.)
|
||||
|
||||
If you set your `user.name` and `user.email` git configs, you can sign your
|
||||
commit automatically with `git commit -s`.
|
||||
|
||||
Note that the old-style `Docker-DCO-1.1-Signed-off-by: ...` format is still
|
||||
accepted, so there is no need to update outstanding pull requests to the new
|
||||
format right away, but please do adjust your processes for future contributions.
|
||||
|
||||
### How can I become a maintainer?
|
||||
|
||||
The procedures for adding new maintainers are explained in the
|
||||
global [MAINTAINERS](https://github.com/docker/opensource/blob/master/MAINTAINERS)
|
||||
file in the [https://github.com/docker/opensource/](https://github.com/docker/opensource/)
|
||||
repository.
|
||||
|
||||
Don't forget: being a maintainer is a time investment. Make sure you
|
||||
will have time to make yourself available. You don't have to be a
|
||||
maintainer to make a difference on the project!
|
||||
|
||||
## Docker community guidelines
|
||||
|
||||
We want to keep the Docker community awesome, growing and collaborative. We need
|
||||
your help to keep it that way. To help with this we've come up with some general
|
||||
guidelines for the community as a whole:
|
||||
|
||||
* Be nice: Be courteous, respectful and polite to fellow community members:
|
||||
no regional, racial, gender, or other abuse will be tolerated. We like
|
||||
nice people way better than mean ones!
|
||||
|
||||
* Encourage diversity and participation: Make everyone in our community feel
|
||||
welcome, regardless of their background and the extent of their
|
||||
contributions, and do everything possible to encourage participation in
|
||||
our community.
|
||||
|
||||
* Keep it legal: Basically, don't get us in trouble. Share only content that
|
||||
you own, do not share private or sensitive information, and don't break
|
||||
the law.
|
||||
|
||||
* Stay on topic: Make sure that you are posting to the correct channel and
|
||||
avoid off-topic discussions. Remember when you update an issue or respond
|
||||
to an email you are potentially sending to a large number of people. Please
|
||||
consider this before you update. Also remember that nobody likes spam.
|
||||
|
||||
* Don't send email to the maintainers: There's no need to send email to the
|
||||
maintainers to ask them to investigate an issue or to take a look at a
|
||||
pull request. Instead of sending an email, GitHub mentions should be
|
||||
used to ping maintainers to review a pull request, a proposal or an
|
||||
issue.
|
||||
|
||||
### Guideline violations — 3 strikes method
|
||||
|
||||
The point of this section is not to find opportunities to punish people, but we
|
||||
do need a fair way to deal with people who are making our community suck.
|
||||
|
||||
1. First occurrence: We'll give you a friendly, but public reminder that the
|
||||
behavior is inappropriate according to our guidelines.
|
||||
|
||||
2. Second occurrence: We will send you a private message with a warning that
|
||||
any additional violations will result in removal from the community.
|
||||
|
||||
3. Third occurrence: Depending on the violation, we may need to delete or ban
|
||||
your account.
|
||||
|
||||
**Notes:**
|
||||
|
||||
* Obvious spammers are banned on first occurrence. If we don't do this, we'll
|
||||
have spam all over the place.
|
||||
|
||||
* Violations are forgiven after 6 months of good behavior, and we won't hold a
|
||||
grudge.
|
||||
|
||||
* People who commit minor infractions will get some education, rather than
|
||||
hammering them in the 3 strikes process.
|
||||
|
||||
* The rules apply equally to everyone in the community, no matter how much
|
||||
you've contributed.
|
||||
|
||||
* Extreme violations of a threatening, abusive, destructive or illegal nature
|
||||
will be addressed immediately and are not subject to 3 strikes or forgiveness.
|
||||
|
||||
* Contact abuse@docker.com to report abuse or appeal violations. In the case of
|
||||
appeals, we know that mistakes happen, and we'll work with you to come up with a
|
||||
fair solution if there has been a misunderstanding.
|
||||
|
||||
## Coding Style
|
||||
|
||||
Unless explicitly stated, we follow all coding guidelines from the Go
|
||||
community. While some of these standards may seem arbitrary, they somehow seem
|
||||
to result in a solid, consistent codebase.
|
||||
|
||||
It is possible that the code base does not currently comply with these
|
||||
guidelines. We are not looking for a massive PR that fixes this, since that
|
||||
goes against the spirit of the guidelines. All new contributions should make a
|
||||
best effort to clean up and make the code base better than they left it.
|
||||
Obviously, apply your best judgement. Remember, the goal here is to make the
|
||||
code base easier for humans to navigate and understand. Always keep that in
|
||||
mind when nudging others to comply.
|
||||
|
||||
The rules:
|
||||
|
||||
1. All code should be formatted with `gofmt -s`.
|
||||
2. All code should pass the default levels of
|
||||
[`golint`](https://github.com/golang/lint).
|
||||
3. All code should follow the guidelines covered in [Effective
|
||||
Go](http://golang.org/doc/effective_go.html) and [Go Code Review
|
||||
Comments](https://github.com/golang/go/wiki/CodeReviewComments).
|
||||
4. Comment the code. Tell us the why, the history and the context.
|
||||
5. Document _all_ declarations and methods, even private ones. Declare
|
||||
expectations, caveats and anything else that may be important. If a type
|
||||
gets exported, having the comments already there will ensure it's ready.
|
||||
6. Variable name length should be proportional to it's context and no longer.
|
||||
`noCommaALongVariableNameLikeThisIsNotMoreClearWhenASimpleCommentWouldDo`.
|
||||
In practice, short methods will have short variable names and globals will
|
||||
have longer names.
|
||||
7. No underscores in package names. If you need a compound name, step back,
|
||||
and re-examine why you need a compound name. If you still think you need a
|
||||
compound name, lose the underscore.
|
||||
8. No utils or helpers packages. If a function is not general enough to
|
||||
warrant it's own package, it has not been written generally enough to be a
|
||||
part of a util package. Just leave it unexported and well-documented.
|
||||
9. All tests should run with `go test` and outside tooling should not be
|
||||
required. No, we don't need another unit testing framework. Assertion
|
||||
packages are acceptable if they provide _real_ incremental value.
|
||||
10. Even though we call these "rules" above, they are actually just
|
||||
guidelines. Since you've read all the rules, you now know that.
|
||||
|
||||
If you are having trouble getting into the mood of idiomatic Go, we recommend
|
||||
reading through [Effective Go](http://golang.org/doc/effective_go.html). The
|
||||
[Go Blog](http://blog.golang.org/) is also a great resource. Drinking the
|
||||
kool-aid is a lot easier than going thirsty.
|
||||
251
vendor/github.com/hyperhq/hypercli/Dockerfile
generated
vendored
251
vendor/github.com/hyperhq/hypercli/Dockerfile
generated
vendored
@@ -1,251 +0,0 @@
|
||||
# This file describes the standard way to build Docker, using docker
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker .
|
||||
#
|
||||
# # Mount your source in an interactive container for quick testing:
|
||||
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
|
||||
#
|
||||
# # Run the test suite:
|
||||
# docker run --privileged docker hack/make.sh test
|
||||
#
|
||||
# # Publish a release:
|
||||
# docker run --privileged \
|
||||
# -e AWS_S3_BUCKET=baz \
|
||||
# -e AWS_ACCESS_KEY=foo \
|
||||
# -e AWS_SECRET_KEY=bar \
|
||||
# -e GPG_PASSPHRASE=gloubiboulga \
|
||||
# docker hack/release.sh
|
||||
#
|
||||
# Note: AppArmor used to mess with privileged mode, but this is no longer
|
||||
# the case. Therefore, you don't have to disable it anymore.
|
||||
#
|
||||
|
||||
FROM ubuntu:trusty
|
||||
|
||||
# add zfs ppa
|
||||
RUN apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys E871F18B51E0147C77796AC81196BA81F6B0FC61
|
||||
RUN echo deb http://ppa.launchpad.net/zfs-native/stable/ubuntu trusty main > /etc/apt/sources.list.d/zfs.list
|
||||
|
||||
# add llvm repo
|
||||
RUN apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 6084F3CF814B57C1CF12EFD515CF4D18AF4F7421
|
||||
RUN echo deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty main > /etc/apt/sources.list.d/llvm.list
|
||||
|
||||
# Packaged dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apparmor \
|
||||
aufs-tools \
|
||||
automake \
|
||||
bash-completion \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
clang-3.8 \
|
||||
createrepo \
|
||||
curl \
|
||||
dpkg-sig \
|
||||
gcc-mingw-w64 \
|
||||
git \
|
||||
iptables \
|
||||
jq \
|
||||
libapparmor-dev \
|
||||
libcap-dev \
|
||||
libltdl-dev \
|
||||
libsqlite3-dev \
|
||||
libsystemd-journal-dev \
|
||||
libtool \
|
||||
mercurial \
|
||||
pkg-config \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-websocket \
|
||||
s3cmd=1.1.0* \
|
||||
ubuntu-zfs \
|
||||
xfsprogs \
|
||||
libzfs-dev \
|
||||
tar \
|
||||
--no-install-recommends \
|
||||
&& ln -snf /usr/bin/clang-3.8 /usr/local/bin/clang \
|
||||
&& ln -snf /usr/bin/clang++-3.8 /usr/local/bin/clang++
|
||||
|
||||
# Get lvm2 source for compiling statically
|
||||
ENV LVM2_VERSION 2.02.103
|
||||
RUN mkdir -p /usr/local/lvm2 \
|
||||
&& curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \
|
||||
| tar -xzC /usr/local/lvm2 --strip-components=1
|
||||
# see https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
|
||||
|
||||
# Compile and install lvm2
|
||||
RUN cd /usr/local/lvm2 \
|
||||
&& ./configure \
|
||||
--build="$(gcc -print-multiarch)" \
|
||||
--enable-static_link \
|
||||
&& make device-mapper \
|
||||
&& make install_device-mapper
|
||||
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# Configure the container for OSX cross compilation
|
||||
ENV OSX_SDK MacOSX10.11.sdk
|
||||
RUN set -x \
|
||||
&& export OSXCROSS_PATH="/osxcross" \
|
||||
&& git clone --depth 1 https://github.com/tpoechtrager/osxcross.git $OSXCROSS_PATH \
|
||||
&& curl -sSL https://s3.dockerproject.org/darwin/${OSX_SDK}.tar.xz -o "${OSXCROSS_PATH}/tarballs/${OSX_SDK}.tar.xz" \
|
||||
&& UNATTENDED=yes OSX_VERSION_MIN=10.6 ${OSXCROSS_PATH}/build.sh
|
||||
ENV PATH /osxcross/target/bin:$PATH
|
||||
|
||||
# install seccomp: the version shipped in trusty is too old
|
||||
ENV SECCOMP_VERSION 2.2.3
|
||||
RUN set -x \
|
||||
&& export SECCOMP_PATH="$(mktemp -d)" \
|
||||
&& curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
|
||||
| tar -xzC "$SECCOMP_PATH" --strip-components=1 \
|
||||
&& ( \
|
||||
cd "$SECCOMP_PATH" \
|
||||
&& ./configure --prefix=/usr/local \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig \
|
||||
) \
|
||||
&& rm -rf "$SECCOMP_PATH"
|
||||
|
||||
# Install Go
|
||||
# IMPORTANT: If the version of Go is updated, the Windows to Linux CI machines
|
||||
# will need updating, to avoid errors. Ping #docker-maintainers on IRC
|
||||
# with a heads-up.
|
||||
ENV GO_VERSION 1.5.3
|
||||
RUN curl -fsSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
ENV GOPATH /go:/go/src/github.com/docker/docker/vendor
|
||||
|
||||
# Compile Go for cross compilation
|
||||
ENV DOCKER_CROSSPLATFORMS \
|
||||
linux/386 linux/arm \
|
||||
darwin/amd64 \
|
||||
freebsd/amd64 freebsd/386 freebsd/arm \
|
||||
windows/amd64 windows/386
|
||||
|
||||
# (set an explicit GOARM of 5 for maximum compatibility)
|
||||
ENV GOARM 5
|
||||
|
||||
# This has been commented out and kept as reference because we don't support compiling with older Go anymore.
|
||||
# ENV GOFMT_VERSION 1.3.3
|
||||
# RUN curl -sSL https://storage.googleapis.com/golang/go${GOFMT_VERSION}.$(go env GOOS)-$(go env GOARCH).tar.gz | tar -C /go/bin -xz --strip-components=2 go/bin/gofmt
|
||||
|
||||
ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3
|
||||
# Grab Go's cover tool for dead-simple code coverage testing
|
||||
# Grab Go's vet tool for examining go code to find suspicious constructs
|
||||
# and help prevent errors that the compiler might not catch
|
||||
RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \
|
||||
&& (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT) \
|
||||
&& go install -v golang.org/x/tools/cmd/cover \
|
||||
&& go install -v golang.org/x/tools/cmd/vet
|
||||
# Grab Go's lint tool
|
||||
ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456
|
||||
RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \
|
||||
&& (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \
|
||||
&& go install -v github.com/golang/lint/golint
|
||||
|
||||
# Install two versions of the registry. The first is an older version that
|
||||
# only supports schema1 manifests. The second is a newer version that supports
|
||||
# both. This allows integration-cli tests to cover push/pull with both schema1
|
||||
# and schema2 manifests.
|
||||
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
|
||||
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Install notary server
|
||||
ENV NOTARY_VERSION docker-v1.10-5
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT e2878cbcc3a7eef99917adc1be252800b0e41ece
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT \
|
||||
&& pip install -r test-requirements.txt
|
||||
|
||||
# Setup s3cmd config
|
||||
RUN { \
|
||||
echo '[default]'; \
|
||||
echo 'access_key=$AWS_ACCESS_KEY'; \
|
||||
echo 'secret_key=$AWS_SECRET_KEY'; \
|
||||
} > ~/.s3cfg
|
||||
|
||||
# Set user.email so crosbymichael's in-container merge commits go smoothly
|
||||
RUN git config --global user.email 'docker-dummy@example.com'
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor seccomp selinux
|
||||
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv $PWD/.bashrc ~/.bashrc
|
||||
|
||||
# Register Docker's bash completion.
|
||||
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
|
||||
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
||||
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
||||
buildpack-deps:jessie@sha256:25785f89240fbcdd8a74bdaf30dd5599a9523882c6dfc567f2e9ef7cf6f79db6 \
|
||||
busybox:latest@sha256:e4f93f6ed15a0cdd342f5aae387886fba0ab98af0a102da6276eaf24d6e6ade0 \
|
||||
debian:jessie@sha256:f968f10b4b523737e253a97eac59b0d1420b5c19b69928d35801a6373ffe330e \
|
||||
hello-world:latest@sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7
|
||||
# see also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
||||
|
||||
# Download man page generator
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone --depth 1 -b v1.0.4 https://github.com/cpuguy83/go-md2man.git "$GOPATH/src/github.com/cpuguy83/go-md2man" \
|
||||
&& git clone --depth 1 -b v1.4 https://github.com/russross/blackfriday.git "$GOPATH/src/github.com/russross/blackfriday" \
|
||||
&& go get -v -d github.com/cpuguy83/go-md2man \
|
||||
&& go build -v -o /usr/local/bin/go-md2man github.com/cpuguy83/go-md2man \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Download toml validator
|
||||
ENV TOMLV_COMMIT 9baf8a8a9f2ed20a8e54160840c492f937eeaf9a
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/BurntSushi/toml.git "$GOPATH/src/github.com/BurntSushi/toml" \
|
||||
&& (cd "$GOPATH/src/github.com/BurntSushi/toml" && git checkout -q "$TOMLV_COMMIT") \
|
||||
&& go build -v -o /usr/local/bin/tomlv github.com/BurntSushi/toml/cmd/tomlv \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Build/install the tool for embedding resources in Windows binaries
|
||||
ENV RSRC_COMMIT ba14da1f827188454a4591717fff29999010887f
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/akavel/rsrc.git "$GOPATH/src/github.com/akavel/rsrc" \
|
||||
&& (cd "$GOPATH/src/github.com/akavel/rsrc" && git checkout -q "$RSRC_COMMIT") \
|
||||
&& go build -v -o /usr/local/bin/rsrc github.com/akavel/rsrc \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
# Upload docker source
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
203
vendor/github.com/hyperhq/hypercli/Dockerfile.aarch64
generated
vendored
203
vendor/github.com/hyperhq/hypercli/Dockerfile.aarch64
generated
vendored
@@ -1,203 +0,0 @@
|
||||
# This file describes the standard way to build Docker on aarch64, using docker
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker -f Dockerfile.aarch64 .
|
||||
#
|
||||
# # Mount your source in an interactive container for quick testing:
|
||||
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
|
||||
#
|
||||
# # Run the test suite:
|
||||
# docker run --privileged docker hack/make.sh test
|
||||
#
|
||||
# # Publish a release:
|
||||
# docker run --privileged \
|
||||
# -e AWS_S3_BUCKET=baz \
|
||||
# -e AWS_ACCESS_KEY=foo \
|
||||
# -e AWS_SECRET_KEY=bar \
|
||||
# -e GPG_PASSPHRASE=gloubiboulga \
|
||||
# docker hack/release.sh
|
||||
#
|
||||
# Note: AppArmor used to mess with privileged mode, but this is no longer
|
||||
# the case. Therefore, you don't have to disable it anymore.
|
||||
#
|
||||
|
||||
FROM aarch64/ubuntu:trusty
|
||||
|
||||
# Packaged dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apparmor \
|
||||
aufs-tools \
|
||||
automake \
|
||||
bash-completion \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
createrepo \
|
||||
curl \
|
||||
dpkg-sig \
|
||||
g++ \
|
||||
gcc \
|
||||
git \
|
||||
iptables \
|
||||
jq \
|
||||
libapparmor-dev \
|
||||
libc6-dev \
|
||||
libcap-dev \
|
||||
libsqlite3-dev \
|
||||
libsystemd-journal-dev \
|
||||
mercurial \
|
||||
parallel \
|
||||
pkg-config \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-websocket \
|
||||
s3cmd=1.1.0* \
|
||||
--no-install-recommends
|
||||
|
||||
# Install armhf loader to use armv6 binaries on armv8
|
||||
RUN dpkg --add-architecture armhf \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y libc6:armhf
|
||||
|
||||
# Get lvm2 source for compiling statically
|
||||
ENV LVM2_VERSION 2.02.103
|
||||
RUN mkdir -p /usr/local/lvm2 \
|
||||
&& curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \
|
||||
| tar -xzC /usr/local/lvm2 --strip-components=1
|
||||
# see https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
|
||||
|
||||
# fix platform enablement in lvm2 to support aarch64 properly
|
||||
RUN set -e \
|
||||
&& for f in config.guess config.sub; do \
|
||||
curl -fsSL -o "/usr/local/lvm2/autoconf/$f" "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=$f;hb=HEAD"; \
|
||||
done
|
||||
# "arch.c:78:2: error: #error the arch code needs to know about your machine type"
|
||||
|
||||
# Compile and install lvm2
|
||||
RUN cd /usr/local/lvm2 \
|
||||
&& ./configure \
|
||||
--build="$(gcc -print-multiarch)" \
|
||||
--enable-static_link \
|
||||
&& make device-mapper \
|
||||
&& make install_device-mapper
|
||||
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# install seccomp: the version shipped in trusty is too old
|
||||
ENV SECCOMP_VERSION 2.2.3
|
||||
RUN set -x \
|
||||
&& export SECCOMP_PATH="$(mktemp -d)" \
|
||||
&& curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
|
||||
| tar -xzC "$SECCOMP_PATH" --strip-components=1 \
|
||||
&& ( \
|
||||
cd "$SECCOMP_PATH" \
|
||||
&& ./configure --prefix=/usr/local \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig \
|
||||
) \
|
||||
&& rm -rf "$SECCOMP_PATH"
|
||||
|
||||
# Install Go
|
||||
# We don't have official binary tarballs for ARM64, eigher for Go or bootstrap,
|
||||
# so we use the official armv6 released binaries as a GOROOT_BOOTSTRAP, and
|
||||
# build Go from source code.
|
||||
ENV BOOT_STRAP_VERSION 1.6beta1
|
||||
ENV GO_VERSION 1.5.3
|
||||
RUN mkdir -p /usr/src/go-bootstrap \
|
||||
&& curl -fsSL https://storage.googleapis.com/golang/go${BOOT_STRAP_VERSION}.linux-arm6.tar.gz | tar -v -C /usr/src/go-bootstrap -xz --strip-components=1 \
|
||||
&& mkdir /usr/src/go \
|
||||
&& curl -fsSL https://storage.googleapis.com/golang/go${GO_VERSION}.src.tar.gz | tar -v -C /usr/src/go -xz --strip-components=1 \
|
||||
&& cd /usr/src/go/src \
|
||||
&& GOOS=linux GOARCH=arm64 GOROOT_BOOTSTRAP=/usr/src/go-bootstrap ./make.bash
|
||||
ENV PATH /usr/src/go/bin:$PATH
|
||||
ENV GOPATH /go:/go/src/github.com/docker/docker/vendor
|
||||
|
||||
# Only install one version of the registry, because old version which support
|
||||
# schema1 manifests is not working on ARM64, we should skip integration-cli
|
||||
# tests for schema1 manifests on ARM64.
|
||||
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Install notary server
|
||||
ENV NOTARY_VERSION docker-v1.10-5
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT e2878cbcc3a7eef99917adc1be252800b0e41ece
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT \
|
||||
&& pip install -r test-requirements.txt
|
||||
|
||||
# Setup s3cmd config
|
||||
RUN { \
|
||||
echo '[default]'; \
|
||||
echo 'access_key=$AWS_ACCESS_KEY'; \
|
||||
echo 'secret_key=$AWS_SECRET_KEY'; \
|
||||
} > ~/.s3cfg
|
||||
|
||||
# Set user.email so crosbymichael's in-container merge commits go smoothly
|
||||
RUN git config --global user.email 'docker-dummy@example.com'
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor seccomp selinux
|
||||
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv $PWD/.bashrc ~/.bashrc
|
||||
|
||||
# Register Docker's bash completion.
|
||||
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
|
||||
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
||||
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
||||
aarch64/buildpack-deps:jessie@sha256:6aa1d6910791b7ac78265fd0798e5abd6cb3f27ae992f6f960f6c303ec9535f2 \
|
||||
aarch64/busybox:latest@sha256:b23a6a37cf269dff6e46d2473b6e227afa42b037e6d23435f1d2bc40fc8c2828 \
|
||||
aarch64/debian:jessie@sha256:4be74a41a7c70ebe887b634b11ffe516cf4fcd56864a54941e56bb49883c3170 \
|
||||
aarch64/hello-world:latest@sha256:65a4a158587b307bb02db4de41b836addb0c35175bdc801367b1ac1ddeb9afda
|
||||
# see also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
||||
|
||||
# Download man page generator
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone --depth 1 -b v1.0.4 https://github.com/cpuguy83/go-md2man.git "$GOPATH/src/github.com/cpuguy83/go-md2man" \
|
||||
&& git clone --depth 1 -b v1.4 https://github.com/russross/blackfriday.git "$GOPATH/src/github.com/russross/blackfriday" \
|
||||
&& go get -v -d github.com/cpuguy83/go-md2man \
|
||||
&& go build -v -o /usr/local/bin/go-md2man github.com/cpuguy83/go-md2man \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Download toml validator
|
||||
ENV TOMLV_COMMIT 9baf8a8a9f2ed20a8e54160840c492f937eeaf9a
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/BurntSushi/toml.git "$GOPATH/src/github.com/BurntSushi/toml" \
|
||||
&& (cd "$GOPATH/src/github.com/BurntSushi/toml" && git checkout -q "$TOMLV_COMMIT") \
|
||||
&& go build -v -o /usr/local/bin/tomlv github.com/BurntSushi/toml/cmd/tomlv \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
# Upload docker source
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
220
vendor/github.com/hyperhq/hypercli/Dockerfile.armhf
generated
vendored
220
vendor/github.com/hyperhq/hypercli/Dockerfile.armhf
generated
vendored
@@ -1,220 +0,0 @@
|
||||
# This file describes the standard way to build Docker on ARMv7, using docker
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker -f Dockerfile.armhf .
|
||||
#
|
||||
# # Mount your source in an interactive container for quick testing:
|
||||
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
|
||||
#
|
||||
# # Run the test suite:
|
||||
# docker run --privileged docker hack/make.sh test
|
||||
#
|
||||
# # Publish a release:
|
||||
# docker run --privileged \
|
||||
# -e AWS_S3_BUCKET=baz \
|
||||
# -e AWS_ACCESS_KEY=foo \
|
||||
# -e AWS_SECRET_KEY=bar \
|
||||
# -e GPG_PASSPHRASE=gloubiboulga \
|
||||
# docker hack/release.sh
|
||||
#
|
||||
# Note: AppArmor used to mess with privileged mode, but this is no longer
|
||||
# the case. Therefore, you don't have to disable it anymore.
|
||||
#
|
||||
|
||||
FROM armhf/ubuntu:trusty
|
||||
|
||||
# Packaged dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apparmor \
|
||||
aufs-tools \
|
||||
automake \
|
||||
bash-completion \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
createrepo \
|
||||
curl \
|
||||
dpkg-sig \
|
||||
git \
|
||||
iptables \
|
||||
jq \
|
||||
net-tools \
|
||||
libapparmor-dev \
|
||||
libcap-dev \
|
||||
libltdl-dev \
|
||||
libsqlite3-dev \
|
||||
libsystemd-journal-dev \
|
||||
libtool \
|
||||
mercurial \
|
||||
pkg-config \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-websocket \
|
||||
xfsprogs \
|
||||
tar \
|
||||
--no-install-recommends
|
||||
|
||||
# Get lvm2 source for compiling statically
|
||||
ENV LVM2_VERSION 2.02.103
|
||||
RUN mkdir -p /usr/local/lvm2 \
|
||||
&& curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \
|
||||
| tar -xzC /usr/local/lvm2 --strip-components=1
|
||||
# see https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
|
||||
|
||||
# Compile and install lvm2
|
||||
RUN cd /usr/local/lvm2 \
|
||||
&& ./configure \
|
||||
--build="$(gcc -print-multiarch)" \
|
||||
--enable-static_link \
|
||||
&& make device-mapper \
|
||||
&& make install_device-mapper
|
||||
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# Install Go
|
||||
#ENV GO_VERSION 1.5.3
|
||||
# TODO update GO_TOOLS_COMMIT below when this updates to 1.5+
|
||||
ENV GO_VERSION 1.4.3
|
||||
RUN curl -fsSL "https://github.com/hypriot/golang-armbuilds/releases/download/v${GO_VERSION}/go${GO_VERSION}.linux-armv7.tar.gz" \
|
||||
| tar -xzC /usr/local
|
||||
# temporarily using Hypriot's tarballs while we wait for official 1.6+
|
||||
#RUN curl -fsSL https://golang.org/dl/go${GO_VERSION}.linux-arm6.tar.gz \
|
||||
# | tar -xzC /usr/local
|
||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
ENV GOPATH /go:/go/src/github.com/docker/docker/vendor
|
||||
|
||||
# we're building for armhf, which is ARMv7, so let's be explicit about that
|
||||
ENV GOARCH arm
|
||||
ENV GOARM 7
|
||||
|
||||
# This has been commented out and kept as reference because we don't support compiling with older Go anymore.
|
||||
# ENV GOFMT_VERSION 1.3.3
|
||||
# RUN curl -sSL https://storage.googleapis.com/golang/go${GOFMT_VERSION}.$(go env GOOS)-$(go env GOARCH).tar.gz | tar -C /go/bin -xz --strip-components=2 go/bin/gofmt
|
||||
|
||||
#ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3
|
||||
# TODO update this sha when we upgrade to Go 1.5+
|
||||
ENV GO_TOOLS_COMMIT 069d2f3bcb68257b627205f0486d6cc69a231ff9
|
||||
# Grab Go's cover tool for dead-simple code coverage testing
|
||||
# Grab Go's vet tool for examining go code to find suspicious constructs
|
||||
# and help prevent errors that the compiler might not catch
|
||||
RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \
|
||||
&& (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT) \
|
||||
&& go install -v golang.org/x/tools/cmd/cover \
|
||||
&& go install -v golang.org/x/tools/cmd/vet
|
||||
# Grab Go's lint tool
|
||||
#ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456
|
||||
# TODO update this sha when we upgrade to Go 1.5+
|
||||
ENV GO_LINT_COMMIT f42f5c1c440621302702cb0741e9d2ca547ae80f
|
||||
RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \
|
||||
&& (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \
|
||||
&& go install -v github.com/golang/lint/golint
|
||||
|
||||
# install seccomp: the version shipped in trusty is too old
|
||||
ENV SECCOMP_VERSION 2.2.3
|
||||
RUN set -x \
|
||||
&& export SECCOMP_PATH="$(mktemp -d)" \
|
||||
&& curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
|
||||
| tar -xzC "$SECCOMP_PATH" --strip-components=1 \
|
||||
&& ( \
|
||||
cd "$SECCOMP_PATH" \
|
||||
&& ./configure --prefix=/usr/local \
|
||||
&& make \
|
||||
&& make install \
|
||||
&& ldconfig \
|
||||
) \
|
||||
&& rm -rf "$SECCOMP_PATH"
|
||||
|
||||
# Install two versions of the registry. The first is an older version that
|
||||
# only supports schema1 manifests. The second is a newer version that supports
|
||||
# both. This allows integration-cli tests to cover push/pull with both schema1
|
||||
# and schema2 manifests.
|
||||
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
|
||||
ENV REGISTRY_COMMIT cb08de17d74bef86ce6c5abe8b240e282f5750be
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Install notary server
|
||||
ENV NOTARY_VERSION docker-v1.10-5
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT e2878cbcc3a7eef99917adc1be252800b0e41ece
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT \
|
||||
&& pip install -r test-requirements.txt
|
||||
|
||||
# Set user.email so crosbymichael's in-container merge commits go smoothly
|
||||
RUN git config --global user.email 'docker-dummy@example.com'
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor seccomp selinux
|
||||
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv $PWD/.bashrc ~/.bashrc
|
||||
|
||||
# Register Docker's bash completion.
|
||||
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
|
||||
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
||||
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
||||
armhf/buildpack-deps:jessie@sha256:ca6cce8e5bf5c952129889b5cc15cd6aa8d995d77e55e3749bbaadae50e476cb \
|
||||
armhf/busybox:latest@sha256:d98a7343ac750ffe387e3d514f8521ba69846c216778919b01414b8617cfb3d4 \
|
||||
armhf/debian:jessie@sha256:4a2187483f04a84f9830910fe3581d69b3c985cc045d9f01d8e2f3795b28107b \
|
||||
armhf/hello-world:latest@sha256:161dcecea0225975b2ad5f768058212c1e0d39e8211098666ffa1ac74cfb7791
|
||||
# see also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
||||
|
||||
# Download man page generator
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone --depth 1 -b v1.0.4 https://github.com/cpuguy83/go-md2man.git "$GOPATH/src/github.com/cpuguy83/go-md2man" \
|
||||
&& git clone --depth 1 -b v1.4 https://github.com/russross/blackfriday.git "$GOPATH/src/github.com/russross/blackfriday" \
|
||||
&& go get -v -d github.com/cpuguy83/go-md2man \
|
||||
&& go build -v -o /usr/local/bin/go-md2man github.com/cpuguy83/go-md2man \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Download toml validator
|
||||
ENV TOMLV_COMMIT 9baf8a8a9f2ed20a8e54160840c492f937eeaf9a
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/BurntSushi/toml.git "$GOPATH/src/github.com/BurntSushi/toml" \
|
||||
&& (cd "$GOPATH/src/github.com/BurntSushi/toml" && git checkout -q "$TOMLV_COMMIT") \
|
||||
&& go build -v -o /usr/local/bin/tomlv github.com/BurntSushi/toml/cmd/tomlv \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Build/install the tool for embedding resources in Windows binaries
|
||||
ENV RSRC_VERSION v2
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone --depth 1 -b "$RSRC_VERSION" https://github.com/akavel/rsrc.git "$GOPATH/src/github.com/akavel/rsrc" \
|
||||
&& go build -v -o /usr/local/bin/rsrc github.com/akavel/rsrc \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
# Upload docker source
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
69
vendor/github.com/hyperhq/hypercli/Dockerfile.dev
generated
vendored
69
vendor/github.com/hyperhq/hypercli/Dockerfile.dev
generated
vendored
@@ -1,69 +0,0 @@
|
||||
FROM centos:7.3.1611
|
||||
|
||||
#This Dockerfile is used for dev hypercli
|
||||
#REF: integration-cli/README.md
|
||||
|
||||
##########################################################################
|
||||
RUN yum install -y\
|
||||
automake\
|
||||
gcc\
|
||||
wget\
|
||||
time\
|
||||
git
|
||||
|
||||
|
||||
## Install Go
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN wget http://golangtc.com/static/go/${GO_VERSION}/go${GO_VERSION}.linux-amd64.tar.gz
|
||||
#RUN wget http://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz
|
||||
RUN tar -xzf go${GO_VERSION}.linux-amd64.tar.gz -C /usr/local
|
||||
|
||||
## Env
|
||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
ENV GOPATH /go:/go/src/github.com/hyperhq/hypercli/vendor
|
||||
|
||||
ENV HYPER_CONFIG=/root/.hyper
|
||||
ENV DOCKER_REMOTE_DAEMON=1
|
||||
ENV DOCKER_CERT_PATH=fixtures/hyper_ssl
|
||||
ENV DOCKER_TLS_VERIFY=
|
||||
ENV DOCKER_HOST=
|
||||
ENV ACCESS_KEY=
|
||||
ENV SECRET_KEY=
|
||||
ENV REGION=
|
||||
|
||||
## Ensure /usr/bin/hyper
|
||||
RUN ln -s /go/src/github.com/hyperhq/hypercli/hyper/hyper /usr/bin/hyper
|
||||
RUN echo alias hypercli=\"hyper --region \${DOCKER_HOST}\" >> /root/.bashrc
|
||||
|
||||
|
||||
## Ensure /go/src/github.com/docker/docker
|
||||
RUN mkdir -p /go/src/github.com/docker
|
||||
RUN ln -s /go/src/github.com/hyperhq/hypercli /go/src/github.com/docker/docker
|
||||
|
||||
|
||||
WORKDIR /go/src/github.com/hyperhq/hypercli
|
||||
VOLUME ["/go/src/github.com/hyperhq/hypercli"]
|
||||
ENTRYPOINT ["hack/generate-hyper-conf-dev.sh"]
|
||||
|
||||
|
||||
##########################################################################
|
||||
# install on-my-zsh
|
||||
RUN yum install -y zsh
|
||||
RUN sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
|
||||
RUN sed -i "s/^ZSH_THEME=.*/ZSH_THEME=\"gianu\"/g" /root/.zshrc
|
||||
RUN echo alias hypercli=\"hyper --region \${DOCKER_HOST}\" >> /root/.zshrc
|
||||
|
||||
# config git
|
||||
RUN git config --global color.ui true; \
|
||||
git config --global color.status auto; \
|
||||
git config --global color.diff auto; \
|
||||
git config --global color.branch auto; \
|
||||
git config --global color.interactive auto; \
|
||||
git config --global alias.st 'status'; \
|
||||
git config --global alias.ci 'commit'; \
|
||||
git config --global alias.co 'checkout'; \
|
||||
git config --global alias.br 'branch'; \
|
||||
git config --global alias.sr 'show-ref'; \
|
||||
git config --global alias.cm '!sh -c "br_name=`git symbolic-ref HEAD|sed s#refs/heads/##`; git commit -em \"[\${br_name}] \""'; \
|
||||
git config --global alias.lg "log --graph --pretty=format:'[%ci] %Cgreen(%cr) %Cred%h%Creset -%x09%C(yellow)%Creset %C(cyan)[%an]%Creset %x09 %s%Creset' --abbrev-commit --date=short"; \
|
||||
git config --global push.default current
|
||||
79
vendor/github.com/hyperhq/hypercli/Dockerfile.gccgo
generated
vendored
79
vendor/github.com/hyperhq/hypercli/Dockerfile.gccgo
generated
vendored
@@ -1,79 +0,0 @@
|
||||
# This file describes the standard way to build Docker, using docker
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker -f Dockerfile.gccgo .
|
||||
#
|
||||
|
||||
FROM gcc:5.3
|
||||
|
||||
# Packaged dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apparmor \
|
||||
aufs-tools \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
curl \
|
||||
git \
|
||||
iptables \
|
||||
jq \
|
||||
net-tools \
|
||||
libapparmor-dev \
|
||||
libcap-dev \
|
||||
libsqlite3-dev \
|
||||
mercurial \
|
||||
parallel \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-websocket \
|
||||
--no-install-recommends
|
||||
|
||||
# Get lvm2 source for compiling statically
|
||||
RUN git clone -b v2_02_103 https://git.fedorahosted.org/git/lvm2.git /usr/local/lvm2
|
||||
# see https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
|
||||
|
||||
# Compile and install lvm2
|
||||
RUN cd /usr/local/lvm2 \
|
||||
&& ./configure --enable-static_link \
|
||||
&& make device-mapper \
|
||||
&& make install_device-mapper
|
||||
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# install seccomp: the version shipped in jessie is too old
|
||||
ENV SECCOMP_VERSION v2.2.3
|
||||
RUN set -x \
|
||||
&& export SECCOMP_PATH=$(mktemp -d) \
|
||||
&& git clone https://github.com/seccomp/libseccomp.git "$SECCOMP_PATH" \
|
||||
&& ( \
|
||||
cd "$SECCOMP_PATH" \
|
||||
&& git checkout "$SECCOMP_VERSION" \
|
||||
&& ./autogen.sh \
|
||||
&& ./configure --prefix=/usr \
|
||||
&& make \
|
||||
&& make install \
|
||||
) \
|
||||
&& rm -rf "$SECCOMP_PATH"
|
||||
|
||||
ENV GOPATH /go:/go/src/github.com/docker/docker/vendor
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT e2878cbcc3a7eef99917adc1be252800b0e41ece
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor seccomp selinux
|
||||
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
# Upload docker source
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
198
vendor/github.com/hyperhq/hypercli/Dockerfile.ppc64le
generated
vendored
198
vendor/github.com/hyperhq/hypercli/Dockerfile.ppc64le
generated
vendored
@@ -1,198 +0,0 @@
|
||||
# This file describes the standard way to build Docker on ppc64le, using docker
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker -f Dockerfile.ppc64le .
|
||||
#
|
||||
# # Mount your source in an interactive container for quick testing:
|
||||
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
|
||||
#
|
||||
# # Run the test suite:
|
||||
# docker run --privileged docker hack/make.sh test
|
||||
#
|
||||
# # Publish a release:
|
||||
# docker run --privileged \
|
||||
# -e AWS_S3_BUCKET=baz \
|
||||
# -e AWS_ACCESS_KEY=foo \
|
||||
# -e AWS_SECRET_KEY=bar \
|
||||
# -e GPG_PASSPHRASE=gloubiboulga \
|
||||
# docker hack/release.sh
|
||||
#
|
||||
# Note: AppArmor used to mess with privileged mode, but this is no longer
|
||||
# the case. Therefore, you don't have to disable it anymore.
|
||||
#
|
||||
|
||||
FROM ppc64le/gcc:5.3
|
||||
|
||||
# Packaged dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apparmor \
|
||||
aufs-tools \
|
||||
automake \
|
||||
bash-completion \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
createrepo \
|
||||
curl \
|
||||
dpkg-sig \
|
||||
git \
|
||||
iptables \
|
||||
jq \
|
||||
net-tools \
|
||||
libapparmor-dev \
|
||||
libcap-dev \
|
||||
libltdl-dev \
|
||||
libsqlite3-dev \
|
||||
libsystemd-journal-dev \
|
||||
libtool \
|
||||
mercurial \
|
||||
pkg-config \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-websocket \
|
||||
xfsprogs \
|
||||
tar \
|
||||
--no-install-recommends
|
||||
|
||||
# Get lvm2 source for compiling statically
|
||||
ENV LVM2_VERSION 2.02.103
|
||||
RUN mkdir -p /usr/local/lvm2 \
|
||||
&& curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \
|
||||
| tar -xzC /usr/local/lvm2 --strip-components=1
|
||||
# see https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
|
||||
|
||||
# fix platform enablement in lvm2 to support ppc64le properly
|
||||
RUN set -e \
|
||||
&& for f in config.guess config.sub; do \
|
||||
curl -fsSL -o "/usr/local/lvm2/autoconf/$f" "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=$f;hb=HEAD"; \
|
||||
done
|
||||
# "arch.c:78:2: error: #error the arch code needs to know about your machine type"
|
||||
|
||||
# Compile and install lvm2
|
||||
RUN cd /usr/local/lvm2 \
|
||||
&& ./configure \
|
||||
--build="$(gcc -print-multiarch)" \
|
||||
--enable-static_link \
|
||||
&& make device-mapper \
|
||||
&& make install_device-mapper
|
||||
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# TODO install Go, using gccgo as GOROOT_BOOTSTRAP (Go 1.5+ supports ppc64le properly)
|
||||
# possibly a ppc64le/golang image?
|
||||
|
||||
ENV PATH /go/bin:$PATH
|
||||
ENV GOPATH /go:/go/src/github.com/docker/docker/vendor
|
||||
|
||||
# This has been commented out and kept as reference because we don't support compiling with older Go anymore.
|
||||
# ENV GOFMT_VERSION 1.3.3
|
||||
# RUN curl -sSL https://storage.googleapis.com/golang/go${GOFMT_VERSION}.$(go env GOOS)-$(go env GOARCH).tar.gz | tar -C /go/bin -xz --strip-components=2 go/bin/gofmt
|
||||
|
||||
# TODO update this sha when we upgrade to Go 1.5+
|
||||
ENV GO_TOOLS_COMMIT 069d2f3bcb68257b627205f0486d6cc69a231ff9
|
||||
# Grab Go's cover tool for dead-simple code coverage testing
|
||||
# Grab Go's vet tool for examining go code to find suspicious constructs
|
||||
# and help prevent errors that the compiler might not catch
|
||||
RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \
|
||||
&& (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT) \
|
||||
&& go install -v golang.org/x/tools/cmd/cover \
|
||||
&& go install -v golang.org/x/tools/cmd/vet
|
||||
# Grab Go's lint tool
|
||||
ENV GO_LINT_COMMIT f42f5c1c440621302702cb0741e9d2ca547ae80f
|
||||
RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \
|
||||
&& (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \
|
||||
&& go install -v github.com/golang/lint/golint
|
||||
|
||||
# Install two versions of the registry. The first is an older version that
|
||||
# only supports schema1 manifests. The second is a newer version that supports
|
||||
# both. This allows integration-cli tests to cover push/pull with both schema1
|
||||
# and schema2 manifests.
|
||||
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
|
||||
ENV REGISTRY_COMMIT cb08de17d74bef86ce6c5abe8b240e282f5750be
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# TODO update this when we upgrade to Go 1.5.1+
|
||||
# Install notary server
|
||||
#ENV NOTARY_VERSION docker-v1.10-5
|
||||
#RUN set -x \
|
||||
# && export GOPATH="$(mktemp -d)" \
|
||||
# && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
|
||||
# && (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
|
||||
# && GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
|
||||
# go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
|
||||
# && rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT e2878cbcc3a7eef99917adc1be252800b0e41ece
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT \
|
||||
&& pip install -r test-requirements.txt
|
||||
|
||||
# Set user.email so crosbymichael's in-container merge commits go smoothly
|
||||
RUN git config --global user.email 'docker-dummy@example.com'
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor selinux
|
||||
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv $PWD/.bashrc ~/.bashrc
|
||||
|
||||
# Register Docker's bash completion.
|
||||
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
|
||||
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
||||
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
||||
ppc64le/buildpack-deps:jessie@sha256:902bfe4ef1389f94d143d64516dd50a2de75bca2e66d4a44b1d73f63ddf05dda \
|
||||
ppc64le/busybox:latest@sha256:38bb82085248d5a3c24bd7a5dc146f2f2c191e189da0441f1c2ca560e3fc6f1b \
|
||||
ppc64le/debian:jessie@sha256:412845f51b6ab662afba71bc7a716e20fdb9b84f185d180d4c7504f8a75c4f91 \
|
||||
ppc64le/hello-world:latest@sha256:186a40a9a02ca26df0b6c8acdfb8ac2f3ae6678996a838f977e57fac9d963974
|
||||
# see also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
||||
|
||||
# Download man page generator
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone --depth 1 -b v1.0.4 https://github.com/cpuguy83/go-md2man.git "$GOPATH/src/github.com/cpuguy83/go-md2man" \
|
||||
&& git clone --depth 1 -b v1.4 https://github.com/russross/blackfriday.git "$GOPATH/src/github.com/russross/blackfriday" \
|
||||
&& go get -v -d github.com/cpuguy83/go-md2man \
|
||||
&& go build -v -o /usr/local/bin/go-md2man github.com/cpuguy83/go-md2man \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Download toml validator
|
||||
ENV TOMLV_COMMIT 9baf8a8a9f2ed20a8e54160840c492f937eeaf9a
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/BurntSushi/toml.git "$GOPATH/src/github.com/BurntSushi/toml" \
|
||||
&& (cd "$GOPATH/src/github.com/BurntSushi/toml" && git checkout -q "$TOMLV_COMMIT") \
|
||||
&& go build -v -o /usr/local/bin/tomlv github.com/BurntSushi/toml/cmd/tomlv \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Build/install the tool for embedding resources in Windows binaries
|
||||
ENV RSRC_VERSION v2
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone --depth 1 -b "$RSRC_VERSION" https://github.com/akavel/rsrc.git "$GOPATH/src/github.com/akavel/rsrc" \
|
||||
&& go build -v -o /usr/local/bin/rsrc github.com/akavel/rsrc \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
# Upload docker source
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
42
vendor/github.com/hyperhq/hypercli/Dockerfile.qa
generated
vendored
42
vendor/github.com/hyperhq/hypercli/Dockerfile.qa
generated
vendored
@@ -1,42 +0,0 @@
|
||||
FROM centos:7.3.1611
|
||||
|
||||
#This Dockerfile is used for autotest hypercli
|
||||
#REF: integration-cli/README.md
|
||||
|
||||
##########################################################################
|
||||
RUN yum install -y\
|
||||
automake\
|
||||
gcc\
|
||||
wget\
|
||||
time\
|
||||
git
|
||||
|
||||
|
||||
## Install Go
|
||||
ENV GO_VERSION 1.8.3
|
||||
RUN wget http://golangtc.com/static/go/${GO_VERSION}/go${GO_VERSION}.linux-amd64.tar.gz
|
||||
#RUN wget http://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz
|
||||
RUN tar -xzf go${GO_VERSION}.linux-amd64.tar.gz -C /usr/local
|
||||
|
||||
## Env
|
||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
||||
ENV GOPATH /go:/go/src/github.com/hyperhq/hypercli/integration-cli/vendor:/go/src/github.com/hyperhq/hypercli/vendor
|
||||
|
||||
ENV HYPER_CONFIG=/root/.hyper
|
||||
ENV DOCKER_REMOTE_DAEMON=1
|
||||
ENV DOCKER_CERT_PATH=fixtures/hyper_ssl
|
||||
ENV DOCKER_TLS_VERIFY=
|
||||
|
||||
ENV DOCKER_HOST="tcp://us-west-1.hyper.sh:443"
|
||||
## if BRANCH start with '#', then it means PR number, otherwise it means branch name
|
||||
ENV BRANCH="master"
|
||||
|
||||
ENV ACCESS_KEY=
|
||||
ENV SECRET_KEY=
|
||||
ENV REGION=
|
||||
|
||||
RUN mkdir -p /go/src/github.com/hyperhq
|
||||
WORKDIR /go/src/github.com/hyperhq
|
||||
|
||||
ADD hack/generate-hyper-conf-qa.sh /generate-hyper-conf-qa.sh
|
||||
ENTRYPOINT ["/generate-hyper-conf-qa.sh"]
|
||||
191
vendor/github.com/hyperhq/hypercli/Dockerfile.s390x
generated
vendored
191
vendor/github.com/hyperhq/hypercli/Dockerfile.s390x
generated
vendored
@@ -1,191 +0,0 @@
|
||||
# This file describes the standard way to build Docker on s390x, using docker
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time.
|
||||
# docker build -t docker -f Dockerfile.s390x .
|
||||
#
|
||||
# # Mount your source in an interactive container for quick testing:
|
||||
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
|
||||
#
|
||||
# # Run the test suite:
|
||||
# docker run --privileged docker hack/make.sh test
|
||||
#
|
||||
# # Publish a release:
|
||||
# docker run --privileged \
|
||||
# -e AWS_S3_BUCKET=baz \
|
||||
# -e AWS_ACCESS_KEY=foo \
|
||||
# -e AWS_SECRET_KEY=bar \
|
||||
# -e GPG_PASSPHRASE=gloubiboulga \
|
||||
# docker hack/release.sh
|
||||
#
|
||||
# Note: AppArmor used to mess with privileged mode, but this is no longer
|
||||
# the case. Therefore, you don't have to disable it anymore.
|
||||
#
|
||||
|
||||
FROM s390x/gcc:5.3
|
||||
|
||||
# Packaged dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
apparmor \
|
||||
aufs-tools \
|
||||
automake \
|
||||
bash-completion \
|
||||
btrfs-tools \
|
||||
build-essential \
|
||||
createrepo \
|
||||
curl \
|
||||
dpkg-sig \
|
||||
git \
|
||||
iptables \
|
||||
jq \
|
||||
net-tools \
|
||||
libapparmor-dev \
|
||||
libcap-dev \
|
||||
libltdl-dev \
|
||||
libsqlite3-dev \
|
||||
libsystemd-journal-dev \
|
||||
libtool \
|
||||
mercurial \
|
||||
pkg-config \
|
||||
python-dev \
|
||||
python-mock \
|
||||
python-pip \
|
||||
python-websocket \
|
||||
xfsprogs \
|
||||
tar \
|
||||
--no-install-recommends
|
||||
|
||||
# Get lvm2 source for compiling statically
|
||||
ENV LVM2_VERSION 2.02.103
|
||||
RUN mkdir -p /usr/local/lvm2 \
|
||||
&& curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \
|
||||
| tar -xzC /usr/local/lvm2 --strip-components=1
|
||||
# see https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags
|
||||
|
||||
# fix platform enablement in lvm2 to support s390x properly
|
||||
RUN set -e \
|
||||
&& for f in config.guess config.sub; do \
|
||||
curl -fsSL -o "/usr/local/lvm2/autoconf/$f" "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=$f;hb=HEAD"; \
|
||||
done
|
||||
# "arch.c:78:2: error: #error the arch code needs to know about your machine type"
|
||||
|
||||
# Compile and install lvm2
|
||||
RUN cd /usr/local/lvm2 \
|
||||
&& ./configure \
|
||||
--build="$(gcc -print-multiarch)" \
|
||||
--enable-static_link \
|
||||
&& make device-mapper \
|
||||
&& make install_device-mapper
|
||||
# see https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL
|
||||
|
||||
# Note: Go comes from the base image (gccgo, specifically)
|
||||
# We can't compile Go proper because s390x isn't an officially supported architecture yet.
|
||||
|
||||
ENV PATH /go/bin:$PATH
|
||||
ENV GOPATH /go:/go/src/github.com/docker/docker/vendor
|
||||
|
||||
# This has been commented out and kept as reference because we don't support compiling with older Go anymore.
|
||||
# ENV GOFMT_VERSION 1.3.3
|
||||
# RUN curl -sSL https://storage.googleapis.com/golang/go${GOFMT_VERSION}.$(go env GOOS)-$(go env GOARCH).tar.gz | tar -C /go/bin -xz --strip-components=2 go/bin/gofmt
|
||||
|
||||
# TODO update this sha when we upgrade to Go 1.5+
|
||||
ENV GO_TOOLS_COMMIT 069d2f3bcb68257b627205f0486d6cc69a231ff9
|
||||
# Grab Go's cover tool for dead-simple code coverage testing
|
||||
# Grab Go's vet tool for examining go code to find suspicious constructs
|
||||
# and help prevent errors that the compiler might not catch
|
||||
RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \
|
||||
&& (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT) \
|
||||
&& go install -v golang.org/x/tools/cmd/cover \
|
||||
&& go install -v golang.org/x/tools/cmd/vet
|
||||
# Grab Go's lint tool
|
||||
ENV GO_LINT_COMMIT f42f5c1c440621302702cb0741e9d2ca547ae80f
|
||||
RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \
|
||||
&& (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \
|
||||
&& go install -v github.com/golang/lint/golint
|
||||
|
||||
|
||||
# Install registry
|
||||
ENV REGISTRY_COMMIT ec87e9b6971d831f0eff752ddb54fb64693e51cd
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||
go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Install notary server
|
||||
ENV NOTARY_VERSION docker-v1.10-5
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
|
||||
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
|
||||
&& GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
|
||||
go build -gccgoflags=-lpthread -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Get the "docker-py" source so we can run their integration tests
|
||||
ENV DOCKER_PY_COMMIT e2878cbcc3a7eef99917adc1be252800b0e41ece
|
||||
RUN git clone https://github.com/docker/docker-py.git /docker-py \
|
||||
&& cd /docker-py \
|
||||
&& git checkout -q $DOCKER_PY_COMMIT \
|
||||
&& pip install -r test-requirements.txt
|
||||
|
||||
# Set user.email so crosbymichael's in-container merge commits go smoothly
|
||||
RUN git config --global user.email 'docker-dummy@example.com'
|
||||
|
||||
# Add an unprivileged user to be used for tests which need it
|
||||
RUN groupadd -r docker
|
||||
RUN useradd --create-home --gid docker unprivilegeduser
|
||||
|
||||
VOLUME /var/lib/docker
|
||||
WORKDIR /go/src/github.com/docker/docker
|
||||
ENV DOCKER_BUILDTAGS apparmor selinux
|
||||
|
||||
# Let us use a .bashrc file
|
||||
RUN ln -sfv $PWD/.bashrc ~/.bashrc
|
||||
|
||||
# Register Docker's bash completion.
|
||||
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker
|
||||
|
||||
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
|
||||
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
|
||||
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
|
||||
s390x/buildpack-deps:jessie@sha256:4d1381224acaca6c4bfe3604de3af6972083a8558a99672cb6989c7541780099 \
|
||||
s390x/busybox:latest@sha256:dd61522c983884a66ed72d60301925889028c6d2d5e0220a8fe1d9b4c6a4f01b \
|
||||
s390x/debian:jessie@sha256:b74c863400909eff3c5e196cac9bfd1f6333ce47aae6a38398d87d5875da170a \
|
||||
s390x/hello-world:latest@sha256:780d80b3a7677c3788c0d5cd9168281320c8d4a6d9183892d8ee5cdd610f5699
|
||||
# see also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
|
||||
|
||||
# Download man page generator
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone --depth 1 -b v1.0.4 https://github.com/cpuguy83/go-md2man.git "$GOPATH/src/github.com/cpuguy83/go-md2man" \
|
||||
&& git clone --depth 1 -b v1.4 https://github.com/russross/blackfriday.git "$GOPATH/src/github.com/russross/blackfriday" \
|
||||
&& go get -v -d github.com/cpuguy83/go-md2man \
|
||||
&& go build -v -o /usr/local/bin/go-md2man github.com/cpuguy83/go-md2man \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Download toml validator
|
||||
ENV TOMLV_COMMIT 9baf8a8a9f2ed20a8e54160840c492f937eeaf9a
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/BurntSushi/toml.git "$GOPATH/src/github.com/BurntSushi/toml" \
|
||||
&& (cd "$GOPATH/src/github.com/BurntSushi/toml" && git checkout -q "$TOMLV_COMMIT") \
|
||||
&& go build -v -o /usr/local/bin/tomlv github.com/BurntSushi/toml/cmd/tomlv \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Build/install the tool for embedding resources in Windows binaries
|
||||
ENV RSRC_VERSION v2
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone --depth 1 -b "$RSRC_VERSION" https://github.com/akavel/rsrc.git "$GOPATH/src/github.com/akavel/rsrc" \
|
||||
&& go build -v -o /usr/local/bin/rsrc github.com/akavel/rsrc \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||
ENTRYPOINT ["hack/dind"]
|
||||
|
||||
# Upload docker source
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
34
vendor/github.com/hyperhq/hypercli/Dockerfile.simple
generated
vendored
34
vendor/github.com/hyperhq/hypercli/Dockerfile.simple
generated
vendored
@@ -1,34 +0,0 @@
|
||||
# docker build -t docker:simple -f Dockerfile.simple .
|
||||
# docker run --rm docker:simple hack/make.sh dynbinary
|
||||
# docker run --rm --privileged docker:simple hack/dind hack/make.sh test-unit
|
||||
# docker run --rm --privileged -v /var/lib/docker docker:simple hack/dind hack/make.sh dynbinary test-integration-cli
|
||||
|
||||
# This represents the bare minimum required to build and test Docker.
|
||||
|
||||
FROM debian:jessie
|
||||
|
||||
# compile and runtime deps
|
||||
# https://github.com/docker/docker/blob/master/project/PACKAGERS.md#build-dependencies
|
||||
# https://github.com/docker/docker/blob/master/project/PACKAGERS.md#runtime-dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
btrfs-tools \
|
||||
curl \
|
||||
gcc \
|
||||
git \
|
||||
golang \
|
||||
libdevmapper-dev \
|
||||
libsqlite3-dev \
|
||||
\
|
||||
ca-certificates \
|
||||
e2fsprogs \
|
||||
iptables \
|
||||
procps \
|
||||
xfsprogs \
|
||||
xz-utils \
|
||||
\
|
||||
aufs-tools \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV AUTO_GOPATH 1
|
||||
WORKDIR /usr/src/docker
|
||||
COPY . /usr/src/docker
|
||||
93
vendor/github.com/hyperhq/hypercli/Dockerfile.windows
generated
vendored
93
vendor/github.com/hyperhq/hypercli/Dockerfile.windows
generated
vendored
@@ -1,93 +0,0 @@
|
||||
# This file describes the standard way to build Docker, using a docker container on Windows
|
||||
# Server 2016
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# # Assemble the full dev environment. This is slow the first time. Run this from
|
||||
# # a directory containing the sources you are validating. For example from
|
||||
# # c:\go\src\github.com\docker\docker
|
||||
#
|
||||
# docker build -t docker -f Dockerfile.windows .
|
||||
#
|
||||
#
|
||||
# # Build docker in a container. Run the following from a Windows cmd command prommpt,
|
||||
# # replacing c:\built with the directory you want the binaries to be placed on the
|
||||
# # host system.
|
||||
#
|
||||
# docker run --rm -v "c:\built:c:\target" docker sh -c 'cd /c/go/src/github.com/docker/docker; hack/make.sh binary; ec=$?; if [ $ec -eq 0 ]; then robocopy /c/go/src/github.com/docker/docker/bundles/$(cat VERSION)/binary /c/target/binary; fi; exit $ec'
|
||||
#
|
||||
# Important notes:
|
||||
# ---------------
|
||||
#
|
||||
# Multiple commands in a single powershell RUN command are deliberately not done. This is
|
||||
# because PS doesn't have a concept quite like set -e in bash. It would be possible to use
|
||||
# try-catch script blocks, but that would make this file unreadable. The problem is that
|
||||
# if there are two commands eg "RUN powershell -command fail; succeed", as far as docker
|
||||
# would be concerned, the return code from the overall RUN is succeed. This doesn't apply to
|
||||
# RUN which uses cmd as the command interpreter such as "RUN fail; succeed".
|
||||
#
|
||||
# 'sleep 5' is a deliberate workaround for a current problem on containers in Windows
|
||||
# Server 2016. It ensures that the network is up and available for when the command is
|
||||
# network related. This bug is being tracked internally at Microsoft and exists in TP4.
|
||||
# Generally sleep 1 or 2 is probably enough, but making it 5 to make the build file
|
||||
# as bullet proof as possible. This isn't a big deal as this only runs the first time.
|
||||
#
|
||||
# The cygwin posix utilities from GIT aren't usable interactively as at January 2016. This
|
||||
# is because they require a console window which isn't present in a container in Windows.
|
||||
# See the example at the top of this file. Do NOT use -it in that docker run!!!
|
||||
#
|
||||
# Don't try to use a volume for passing the source through. The cygwin posix utilities will
|
||||
# balk at reparse points. Again, see the example at the top of this file on how use a volume
|
||||
# to get the built binary out of the container.
|
||||
|
||||
FROM windowsservercore
|
||||
|
||||
# Environment variable notes:
|
||||
# - GOLANG_VERSION should be updated to be consistent with the Linux dockerfile.
|
||||
# - FROM_DOCKERFILE is used for detection of building within a container.
|
||||
ENV GOLANG_VERSION=1.5.3 \
|
||||
GIT_VERSION=2.7.0 \
|
||||
RSRC_COMMIT=ba14da1f827188454a4591717fff29999010887f \
|
||||
GOPATH=C:/go;C:/go/src/github.com/docker/docker/vendor \
|
||||
FROM_DOCKERFILE=1
|
||||
|
||||
# Make sure we're in temp for the downloads
|
||||
WORKDIR c:/windows/temp
|
||||
|
||||
# Download everything else we need to install
|
||||
# We want a 64-bit make.exe, not 16 or 32-bit. This was hard to find, so documenting the links
|
||||
# - http://sourceforge.net/p/mingw-w64/wiki2/Make/ -->
|
||||
# - http://sourceforge.net/projects/mingw-w64/files/External%20binary%20packages%20%28Win64%20hosted%29/ -->
|
||||
# - http://sourceforge.net/projects/mingw-w64/files/External binary packages %28Win64 hosted%29/make/
|
||||
RUN powershell -command sleep 5; Invoke-WebRequest -UserAgent 'DockerCI' -outfile make.zip http://downloads.sourceforge.net/project/mingw-w64/External%20binary%20packages%20%28Win64%20hosted%29/make/make-3.82.90-20111115.zip
|
||||
RUN powershell -command sleep 5; Invoke-WebRequest -UserAgent 'DockerCI' -outfile gcc.zip http://downloads.sourceforge.net/project/tdm-gcc/TDM-GCC%205%20series/5.1.0-tdm64-1/gcc-5.1.0-tdm64-1-core.zip
|
||||
RUN powershell -command sleep 5; Invoke-WebRequest -UserAgent 'DockerCI' -outfile runtime.zip http://downloads.sourceforge.net/project/tdm-gcc/MinGW-w64%20runtime/GCC%205%20series/mingw64runtime-v4-git20150618-gcc5-tdm64-1.zip
|
||||
RUN powershell -command sleep 5; Invoke-WebRequest -UserAgent 'DockerCI' -outfile binutils.zip http://downloads.sourceforge.net/project/tdm-gcc/GNU%20binutils/binutils-2.25-tdm64-1.zip
|
||||
RUN powershell -command sleep 5; Invoke-WebRequest -UserAgent 'DockerCI' -outfile 7zsetup.exe http://www.7-zip.org/a/7z1514-x64.exe
|
||||
RUN powershell -command sleep 5; Invoke-WebRequest -UserAgent 'DockerCI' -outfile lzma.7z http://www.7-zip.org/a/lzma1514.7z
|
||||
RUN powershell -command sleep 5; Invoke-WebRequest -UserAgent 'DockerCI' -outfile gitsetup.exe https://github.com/git-for-windows/git/releases/download/v%GIT_VERSION%.windows.1/Git-%GIT_VERSION%-64-bit.exe
|
||||
RUN powershell -command sleep 5; Invoke-WebRequest -UserAgent 'DockerCI' -outfile go.msi https://storage.googleapis.com/golang/go%GOLANG_VERSION%.windows-amd64.msi
|
||||
|
||||
# Path
|
||||
RUN setx /M Path "c:\git\cmd;c:\git\bin;c:\git\usr\bin;%Path%;c:\gcc\bin;c:\7zip"
|
||||
|
||||
# Install and expand the bits we downloaded.
|
||||
# Note: The git, 7z and go.msi installers execute asynchronously.
|
||||
RUN powershell -command start-process .\gitsetup.exe -ArgumentList '/VERYSILENT /SUPPRESSMSGBOXES /CLOSEAPPLICATIONS /DIR=c:\git' -Wait
|
||||
RUN powershell -command start-process .\7zsetup -ArgumentList '/S /D=c:/7zip' -Wait
|
||||
RUN powershell -command start-process .\go.msi -ArgumentList '/quiet' -Wait
|
||||
RUN powershell -command Expand-Archive gcc.zip \gcc -Force
|
||||
RUN powershell -command Expand-Archive runtime.zip \gcc -Force
|
||||
RUN powershell -command Expand-Archive binutils.zip \gcc -Force
|
||||
RUN powershell -command 7z e lzma.7z bin/lzma.exe
|
||||
RUN powershell -command 7z x make.zip make-3.82.90-20111115/bin_amd64/make.exe
|
||||
RUN powershell -command mv make-3.82.90-20111115/bin_amd64/make.exe /gcc/bin/
|
||||
|
||||
# RSRC for manifest and icon
|
||||
RUN powershell -command sleep 5 ; git clone https://github.com/akavel/rsrc.git c:\go\src\github.com\akavel\rsrc
|
||||
RUN cd c:/go/src/github.com/akavel/rsrc && git checkout -q %RSRC_COMMIT% && go install -v
|
||||
|
||||
# Prepare for building
|
||||
WORKDIR c:/
|
||||
COPY . /go/src/github.com/docker/docker
|
||||
|
||||
242
vendor/github.com/hyperhq/hypercli/MAINTAINERS
generated
vendored
242
vendor/github.com/hyperhq/hypercli/MAINTAINERS
generated
vendored
@@ -1,242 +0,0 @@
|
||||
# Docker maintainers file
|
||||
#
|
||||
# This file describes who runs the docker/docker project and how.
|
||||
# This is a living document - if you see something out of date or missing, speak up!
|
||||
#
|
||||
# It is structured to be consumable by both humans and programs.
|
||||
# To extract its contents programmatically, use any TOML-compliant
|
||||
# parser.
|
||||
#
|
||||
# This file is compiled into the MAINTAINERS file in docker/opensource.
|
||||
#
|
||||
[Org]
|
||||
|
||||
[Org."Core maintainers"]
|
||||
|
||||
# The Core maintainers are the ghostbusters of the project: when there's a problem others
|
||||
# can't solve, they show up and fix it with bizarre devices and weaponry.
|
||||
# They have final say on technical implementation and coding style.
|
||||
# They are ultimately responsible for quality in all its forms: usability polish,
|
||||
# bugfixes, performance, stability, etc. When ownership can cleanly be passed to
|
||||
# a subsystem, they are responsible for doing so and holding the
|
||||
# subsystem maintainers accountable. If ownership is unclear, they are the de facto owners.
|
||||
|
||||
# For each release (including minor releases), a "release captain" is assigned from the
|
||||
# pool of core maintainers. Rotation is encouraged across all maintainers, to ensure
|
||||
# the release process is clear and up-to-date.
|
||||
|
||||
people = [
|
||||
"calavera",
|
||||
"coolljt0725",
|
||||
"cpuguy83",
|
||||
"crosbymichael",
|
||||
"duglin",
|
||||
"estesp",
|
||||
"icecrime",
|
||||
"jfrazelle",
|
||||
"lk4d4",
|
||||
"mhbauer",
|
||||
"runcom",
|
||||
"tianon",
|
||||
"tibor",
|
||||
"tonistiigi",
|
||||
"unclejack",
|
||||
"vbatts",
|
||||
"vdemeester"
|
||||
]
|
||||
|
||||
[Org."Docs maintainers"]
|
||||
|
||||
# TODO Describe the docs maintainers role.
|
||||
|
||||
people = [
|
||||
"jamtur01",
|
||||
"moxiegirl",
|
||||
"sven",
|
||||
"thajeztah"
|
||||
]
|
||||
|
||||
[Org.Curators]
|
||||
|
||||
# The curators help ensure that incoming issues and pull requests are properly triaged and
|
||||
# that our various contribution and reviewing processes are respected. With their knowledge of
|
||||
# the repository activity, they can also guide contributors to relevant material or
|
||||
# discussions.
|
||||
#
|
||||
# They are neither code nor docs reviewers, so they are never expected to merge. They can
|
||||
# however:
|
||||
# - close an issue or pull request when it's an exact duplicate
|
||||
# - close an issue or pull request when it's inappropriate or off-topic
|
||||
|
||||
people = [
|
||||
"thajeztah"
|
||||
]
|
||||
|
||||
[Org.Alumni]
|
||||
|
||||
# This list contains maintainers that are no longer active on the project.
|
||||
# It is thanks to these people that the project has become what it is today.
|
||||
# Thank you!
|
||||
|
||||
people = [
|
||||
# As a maintainer, Erik was responsible for the "builder", and
|
||||
# started the first designs for the new networking model in
|
||||
# Docker. Erik is now working on all kinds of plugins for Docker
|
||||
# (https://github.com/contiv) and various open source projects
|
||||
# in his own repository https://github.com/erikh. You may
|
||||
# still stumble into him in our issue tracker, or on IRC.
|
||||
"erikh",
|
||||
|
||||
# Victor is one of the earliest contributors to Docker, having worked on the
|
||||
# project when it was still "dotCloud" in April 2013. He's been responsible
|
||||
# for multiple releases (https://github.com/docker/docker/pulls?q=is%3Apr+bump+in%3Atitle+author%3Avieux),
|
||||
# and up until today (2015), our number 2 contributor. Although he's no longer
|
||||
# a maintainer for the Docker "Engine", he's still actively involved in other
|
||||
# Docker projects, and most likely can be found in the Docker Swarm repository,
|
||||
# for which he's a core maintainer.
|
||||
"vieux",
|
||||
|
||||
# Vishnu became a maintainer to help out on the daemon codebase and
|
||||
# libcontainer integration. He's currently involved in the
|
||||
# Open Containers Initiative, working on the specifications,
|
||||
# besides his work on cAdvisor and Kubernetes for Google.
|
||||
"vishh"
|
||||
]
|
||||
|
||||
[people]
|
||||
|
||||
# A reference list of all people associated with the project.
|
||||
# All other sections should refer to people by their canonical key
|
||||
# in the people section.
|
||||
|
||||
# ADD YOURSELF HERE IN ALPHABETICAL ORDER
|
||||
|
||||
[people.calavera]
|
||||
Name = "David Calavera"
|
||||
Email = "david.calavera@gmail.com"
|
||||
GitHub = "calavera"
|
||||
|
||||
[people.coolljt0725]
|
||||
Name = "Lei Jitang"
|
||||
Email = "leijitang@huawei.com"
|
||||
GitHub = "coolljt0725"
|
||||
|
||||
[people.cpuguy83]
|
||||
Name = "Brian Goff"
|
||||
Email = "cpuguy83@gmail.com"
|
||||
Github = "cpuguy83"
|
||||
|
||||
[people.crosbymichael]
|
||||
Name = "Michael Crosby"
|
||||
Email = "crosbymichael@gmail.com"
|
||||
GitHub = "crosbymichael"
|
||||
|
||||
[people.duglin]
|
||||
Name = "Doug Davis"
|
||||
Email = "dug@us.ibm.com"
|
||||
GitHub = "duglin"
|
||||
|
||||
[people.erikh]
|
||||
Name = "Erik Hollensbe"
|
||||
Email = "erik@docker.com"
|
||||
GitHub = "erikh"
|
||||
|
||||
[people.estesp]
|
||||
Name = "Phil Estes"
|
||||
Email = "estesp@linux.vnet.ibm.com"
|
||||
GitHub = "estesp"
|
||||
|
||||
[people.icecrime]
|
||||
Name = "Arnaud Porterie"
|
||||
Email = "arnaud@docker.com"
|
||||
GitHub = "icecrime"
|
||||
|
||||
[people.jamtur01]
|
||||
Name = "James Turnbull"
|
||||
Email = "james@lovedthanlost.net"
|
||||
GitHub = "jamtur01"
|
||||
|
||||
[people.jfrazelle]
|
||||
Name = "Jessie Frazelle"
|
||||
Email = "j@docker.com"
|
||||
GitHub = "jfrazelle"
|
||||
|
||||
[people.lk4d4]
|
||||
Name = "Alexander Morozov"
|
||||
Email = "lk4d4@docker.com"
|
||||
GitHub = "lk4d4"
|
||||
|
||||
[people.mhbauer]
|
||||
Name = "Morgan Bauer"
|
||||
Email = "mbauer@us.ibm.com"
|
||||
GitHub = "mhbauer"
|
||||
|
||||
[people.moxiegirl]
|
||||
Name = "Mary Anthony"
|
||||
Email = "mary.anthony@docker.com"
|
||||
GitHub = "moxiegirl"
|
||||
|
||||
[people.runcom]
|
||||
Name = "Antonio Murdaca"
|
||||
Email = "runcom@redhat.com"
|
||||
GitHub = "runcom"
|
||||
|
||||
[people.shykes]
|
||||
Name = "Solomon Hykes"
|
||||
Email = "solomon@docker.com"
|
||||
GitHub = "shykes"
|
||||
|
||||
[people.sven]
|
||||
Name = "Sven Dowideit"
|
||||
Email = "SvenDowideit@home.org.au"
|
||||
GitHub = "SvenDowideit"
|
||||
|
||||
[people.thajeztah]
|
||||
Name = "Sebastiaan van Stijn"
|
||||
Email = "github@gone.nl"
|
||||
GitHub = "thaJeztah"
|
||||
|
||||
[people.theadactyl]
|
||||
Name = "Thea Lamkin"
|
||||
Email = "thea@docker.com"
|
||||
GitHub = "theadactyl"
|
||||
|
||||
[people.tianon]
|
||||
Name = "Tianon Gravi"
|
||||
Email = "admwiggin@gmail.com"
|
||||
GitHub = "tianon"
|
||||
|
||||
[people.tibor]
|
||||
Name = "Tibor Vass"
|
||||
Email = "tibor@docker.com"
|
||||
GitHub = "tiborvass"
|
||||
|
||||
[people.tonistiigi]
|
||||
Name = "Tõnis Tiigi"
|
||||
Email = "tonis@docker.com"
|
||||
GitHub = "tonistiigi"
|
||||
|
||||
[people.unclejack]
|
||||
Name = "Cristian Staretu"
|
||||
Email = "cristian.staretu@gmail.com"
|
||||
GitHub = "unclejack"
|
||||
|
||||
[people.vbatts]
|
||||
Name = "Vincent Batts"
|
||||
Email = "vbatts@redhat.com"
|
||||
GitHub = "vbatts"
|
||||
|
||||
[people.vdemeester]
|
||||
Name = "Vincent Demeester"
|
||||
Email = "vincent@sbr.pm"
|
||||
GitHub = "vdemeester"
|
||||
|
||||
[people.vieux]
|
||||
Name = "Victor Vieux"
|
||||
Email = "vieux@docker.com"
|
||||
GitHub = "vieux"
|
||||
|
||||
[people.vishh]
|
||||
Name = "Vishnu Kannan"
|
||||
Email = "vishnuk@google.com"
|
||||
GitHub = "vishh"
|
||||
119
vendor/github.com/hyperhq/hypercli/Makefile
generated
vendored
119
vendor/github.com/hyperhq/hypercli/Makefile
generated
vendored
@@ -1,119 +0,0 @@
|
||||
.PHONY: all binary build cross default docs docs-build docs-shell shell test test-docker-py test-integration-cli test-unit validate
|
||||
|
||||
# get OS/Arch of docker engine
|
||||
DOCKER_OSARCH := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $${DOCKER_ENGINE_OSARCH:+$$DOCKER_CLIENT_OSARCH}')
|
||||
# default for linux/amd64 and others
|
||||
DOCKERFILE := Dockerfile
|
||||
# switch to different Dockerfile for linux/arm
|
||||
ifeq ($(DOCKER_OSARCH), linux/arm)
|
||||
DOCKERFILE := Dockerfile.armhf
|
||||
else
|
||||
ifeq ($(DOCKER_OSARCH), linux/arm64)
|
||||
DOCKERFILE := Dockerfile.aarch64
|
||||
else
|
||||
ifeq ($(DOCKER_OSARCH), linux/ppc64le)
|
||||
DOCKERFILE := Dockerfile.ppc64le
|
||||
else
|
||||
ifeq ($(DOCKER_OSARCH), linux/s390x)
|
||||
DOCKERFILE := Dockerfile.s390x
|
||||
else
|
||||
ifeq ($(DOCKER_OSARCH), windows/amd64)
|
||||
DOCKERFILE := Dockerfile.windows
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
export DOCKERFILE
|
||||
|
||||
# env vars passed through directly to Docker's build scripts
|
||||
# to allow things like `make DOCKER_CLIENTONLY=1 binary` easily
|
||||
# `docs/sources/contributing/devenvironment.md ` and `project/PACKAGERS.md` have some limited documentation of some of these
|
||||
DOCKER_ENVS := \
|
||||
-e BUILDFLAGS \
|
||||
-e KEEPBUNDLE \
|
||||
-e DOCKER_BUILD_GOGC \
|
||||
-e DOCKER_BUILD_PKGS \
|
||||
-e DOCKER_CLIENTONLY \
|
||||
-e DOCKER_DEBUG \
|
||||
-e DOCKER_EXPERIMENTAL \
|
||||
-e DOCKERFILE \
|
||||
-e DOCKER_GRAPHDRIVER \
|
||||
-e DOCKER_INCREMENTAL_BINARY \
|
||||
-e DOCKER_REMAP_ROOT \
|
||||
-e DOCKER_STORAGE_OPTS \
|
||||
-e DOCKER_USERLANDPROXY \
|
||||
-e TESTDIRS \
|
||||
-e TESTFLAGS \
|
||||
-e TIMEOUT
|
||||
# note: we _cannot_ add "-e DOCKER_BUILDTAGS" here because even if it's unset in the shell, that would shadow the "ENV DOCKER_BUILDTAGS" set in our Dockerfile, which is very important for our official builds
|
||||
|
||||
# to allow `make BIND_DIR=. shell` or `make BIND_DIR= test`
|
||||
# (default to no bind mount if DOCKER_HOST is set)
|
||||
# note: BINDDIR is supported for backwards-compatibility here
|
||||
BIND_DIR := $(if $(BINDDIR),$(BINDDIR),$(if $(DOCKER_HOST),,bundles))
|
||||
DOCKER_MOUNT := $(if $(BIND_DIR),-v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/docker/docker/$(BIND_DIR)")
|
||||
|
||||
|
||||
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
||||
DOCKER_IMAGE := docker-dev$(if $(GIT_BRANCH),:$(GIT_BRANCH))
|
||||
DOCKER_DOCS_IMAGE := docker-docs$(if $(GIT_BRANCH),:$(GIT_BRANCH))
|
||||
|
||||
DOCKER_FLAGS := docker run --rm -i --privileged $(DOCKER_ENVS) $(DOCKER_MOUNT)
|
||||
|
||||
# if this session isn't interactive, then we don't want to allocate a
|
||||
# TTY, which would fail, but if it is interactive, we do want to attach
|
||||
# so that the user can send e.g. ^C through.
|
||||
INTERACTIVE := $(shell [ -t 0 ] && echo 1 || echo 0)
|
||||
ifeq ($(INTERACTIVE), 1)
|
||||
DOCKER_FLAGS += -t
|
||||
endif
|
||||
|
||||
DOCKER_RUN_DOCKER := $(DOCKER_FLAGS) "$(DOCKER_IMAGE)"
|
||||
|
||||
default: binary
|
||||
|
||||
all: build
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh
|
||||
|
||||
binary: build
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh binary
|
||||
|
||||
build: bundles
|
||||
docker build ${DOCKER_BUILD_ARGS} -t "$(DOCKER_IMAGE)" -f "$(DOCKERFILE)" .
|
||||
|
||||
bundles:
|
||||
mkdir bundles
|
||||
|
||||
cross: build
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary binary cross
|
||||
|
||||
deb: build
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary build-deb
|
||||
|
||||
docs:
|
||||
$(MAKE) -C docs docs
|
||||
|
||||
gccgo: build
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh gccgo
|
||||
|
||||
rpm: build
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary build-rpm
|
||||
|
||||
shell: build
|
||||
$(DOCKER_RUN_DOCKER) bash
|
||||
|
||||
test: build
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary cross test-unit test-integration-cli test-docker-py
|
||||
|
||||
test-docker-py: build
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary test-docker-py
|
||||
|
||||
test-integration-cli: build
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary test-integration-cli
|
||||
|
||||
test-unit: build
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh test-unit
|
||||
|
||||
validate: build
|
||||
$(DOCKER_RUN_DOCKER) hack/make.sh validate-dco validate-gofmt validate-pkg validate-lint validate-test validate-toml validate-vet validate-vendor
|
||||
52
vendor/github.com/hyperhq/hypercli/README.md
generated
vendored
52
vendor/github.com/hyperhq/hypercli/README.md
generated
vendored
@@ -1,52 +0,0 @@
|
||||
# HyperCLI [](https://travis-ci.org/hyperhq/hypercli)
|
||||
|
||||
Go version of Hyper.sh client command line tools.
|
||||
|
||||
## Install
|
||||
|
||||
### Quick and Easy (Recommended)
|
||||
|
||||
Grab the latest version for your system on the [Releases](https://github.com/hyperhq/hypercli/releases) page or build it by yourself as the [instruction](#how-to-build).
|
||||
|
||||
You can either run the binary directly or add somewhere in your $PATH.
|
||||
|
||||
## Getting Started
|
||||
|
||||
#### Before Getting Started
|
||||
|
||||
Before you can use Hyper.sh, be sure you've [created a free account with Hyper.sh](http://www.hyper.sh) and [generate your credentials on Hyper.sh](https://docs.hyper.sh/GettingStarted/generate_api_credential.html).
|
||||
|
||||
Once the installation and setup completes, enter `hyper config` in your terminal. The CLI will prompt to ask for your API credential:
|
||||
|
||||

|
||||
|
||||
The credential is stored in a local configuration file `$HOME/.hyper/config.json`. The configuration file is similar to Docker's, with an extra section `clouds`.
|
||||
|
||||

|
||||
|
||||
Or you can use environmental vairables `HYPER_ACCESS` and `HYPER_SECRET` to pass the access key and secret key (CLI will search for these envs before loading the configuration file).
|
||||
|
||||
You only need to do that once for your machine. If you've done that, then you can continue.
|
||||
|
||||
[See the official docs](http://docs.hyper.sh/) for more detailed info on using Hyper.sh.
|
||||
|
||||
#### Actually Getting Started
|
||||
|
||||
The easiest way to get started is by digging around.
|
||||
|
||||
`$ hyper --help` for example usage and a list of commands
|
||||
|
||||
## How to build
|
||||
|
||||
```
|
||||
$ mkdir $GOPATH/src/github.com/hyperhq/
|
||||
$ cd $GOPATH/src/github.com/hyperhq/
|
||||
$ git clone https://github.com/hyperhq/hypercli hypercli
|
||||
$ cd hypercli
|
||||
$ ./build.sh
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Give us a pull request! File a bug!
|
||||
|
||||
183
vendor/github.com/hyperhq/hypercli/ROADMAP.md
generated
vendored
183
vendor/github.com/hyperhq/hypercli/ROADMAP.md
generated
vendored
@@ -1,183 +0,0 @@
|
||||
Docker Engine Roadmap
|
||||
=====================
|
||||
|
||||
### How should I use this document?
|
||||
|
||||
This document provides description of items that the project decided to prioritize. This should
|
||||
serve as a reference point for Docker contributors to understand where the project is going, and
|
||||
help determine if a contribution could be conflicting with some longer terms plans.
|
||||
|
||||
The fact that a feature isn't listed here doesn't mean that a patch for it will automatically be
|
||||
refused (except for those mentioned as "frozen features" below)! We are always happy to receive
|
||||
patches for new cool features we haven't thought about, or didn't judge priority. Please however
|
||||
understand that such patches might take longer for us to review.
|
||||
|
||||
### How can I help?
|
||||
|
||||
Short term objectives are listed in the [wiki](https://github.com/docker/docker/wiki) and described
|
||||
in [Issues](https://github.com/docker/docker/issues?q=is%3Aopen+is%3Aissue+label%3Aroadmap). Our
|
||||
goal is to split down the workload in such way that anybody can jump in and help. Please comment on
|
||||
issues if you want to take it to avoid duplicating effort! Similarly, if a maintainer is already
|
||||
assigned on an issue you'd like to participate in, pinging him on IRC or GitHub to offer your help is
|
||||
the best way to go.
|
||||
|
||||
### How can I add something to the roadmap?
|
||||
|
||||
The roadmap process is new to the Docker Engine: we are only beginning to structure and document the
|
||||
project objectives. Our immediate goal is to be more transparent, and work with our community to
|
||||
focus our efforts on fewer prioritized topics.
|
||||
|
||||
We hope to offer in the near future a process allowing anyone to propose a topic to the roadmap, but
|
||||
we are not quite there yet. For the time being, the BDFL remains the keeper of the roadmap, and we
|
||||
won't be accepting pull requests adding or removing items from this file.
|
||||
|
||||
# 1. Features and refactoring
|
||||
|
||||
## 1.1 Security
|
||||
|
||||
Security is a top objective for the Docker Engine. The most notable items we intend to provide in
|
||||
the near future are:
|
||||
|
||||
- Trusted distribution of images: the effort is driven by the [distribution](https://github.com/docker/distribution)
|
||||
group but will have significant impact on the Engine
|
||||
- [User namespaces](https://github.com/docker/docker/pull/12648)
|
||||
- [Seccomp support](https://github.com/docker/libcontainer/pull/613)
|
||||
|
||||
## 1.2 Plumbing project
|
||||
|
||||
We define a plumbing tool as a standalone piece of software usable and meaningful on its own. In
|
||||
the current state of the Docker Engine, most subsystems provide independent functionalities (such
|
||||
the builder, pushing and pulling images, running applications in a containerized environment, etc)
|
||||
but all are coupled in a single binary. We want to offer the users to flexibility to use only the
|
||||
pieces they need, and we will also gain in maintainability by splitting the project among multiple
|
||||
repositories.
|
||||
|
||||
As it currently stands, the rough design outlines is to have:
|
||||
- Low level plumbing tools, each dealing with one responsibility (e.g., [runC](https://runc.io))
|
||||
- Docker subsystems services, each exposing an elementary concept over an API, and relying on one or
|
||||
multiple lower level plumbing tools for their implementation (e.g., network management)
|
||||
- Docker Engine to expose higher level actions (e.g., create a container with volume `V` and network
|
||||
`N`), while still providing pass-through access to the individual subsystems.
|
||||
|
||||
The architectural details are still being worked on, but one thing we know for sure is that we need
|
||||
to technically decouple the pieces.
|
||||
|
||||
### 1.2.1 Runtime
|
||||
|
||||
A Runtime tool already exists today in the form of [runC](https://github.com/opencontainers/runc).
|
||||
We intend to modify the Engine to directly call out to a binary implementing the Open Containers
|
||||
Specification such as runC rather than relying on libcontainer to set the container runtime up.
|
||||
|
||||
This plan will deprecate the existing [`execdriver`](https://github.com/docker/docker/tree/master/daemon/execdriver)
|
||||
as different runtime backends will be implemented as separated binaries instead of being compiled
|
||||
into the Engine.
|
||||
|
||||
### 1.2.2 Builder
|
||||
|
||||
The Builder (i.e., the ability to build an image from a Dockerfile) is already nicely decoupled,
|
||||
but would benefit from being entirely separated from the Engine, and rely on the standard Engine
|
||||
API for its operations.
|
||||
|
||||
### 1.2.3 Distribution
|
||||
|
||||
Distribution already has a [dedicated repository](https://github.com/docker/distribution) which
|
||||
holds the implementation for Registry v2 and client libraries. We could imagine going further by
|
||||
having the Engine call out to a binary providing image distribution related functionalities.
|
||||
|
||||
There are two short term goals related to image distribution. The first is stabilize and simplify
|
||||
the push/pull code. Following that is the conversion to the more secure Registry V2 protocol.
|
||||
|
||||
### 1.2.4 Networking
|
||||
|
||||
Most of networking related code was already decoupled today in [libnetwork](https://github.com/docker/libnetwork).
|
||||
As with other ingredients, we might want to take it a step further and make it a meaningful utility
|
||||
that the Engine would call out to instead of a library.
|
||||
|
||||
## 1.3 Plugins
|
||||
|
||||
An initiative around plugins started with Docker 1.7.0, with the goal of allowing for out of
|
||||
process extensibility of some Docker functionalities, starting with volumes and networking. The
|
||||
approach is to provide specific extension points rather than generic hooking facilities. We also
|
||||
deliberately keep the extensions API the simplest possible, expanding as we discover valid use
|
||||
cases that cannot be implemented.
|
||||
|
||||
At the time of writing:
|
||||
|
||||
- Plugin support is merged as an experimental feature: real world use cases and user feedback will
|
||||
help us refine the UX to make the feature more user friendly.
|
||||
- There are no immediate plans to expand on the number of pluggable subsystems.
|
||||
- Golang 1.5 might add language support for [plugins](https://docs.google.com/document/d/1nr-TQHw_er6GOQRsF6T43GGhFDelrAP0NqSS_00RgZQ)
|
||||
which we consider supporting as an alternative to JSON/HTTP.
|
||||
|
||||
## 1.4 Volume management
|
||||
|
||||
Volumes are not a first class citizen in the Engine today: we would like better volume management,
|
||||
similar to the way network are managed in the new [CNM](https://github.com/docker/docker/issues/9983).
|
||||
|
||||
## 1.5 Better API implementation
|
||||
|
||||
The current Engine API is insufficiently typed, versioned, and ultimately hard to maintain. We
|
||||
also suffer from the lack of a common implementation with [Swarm](https://github.com/docker/swarm).
|
||||
|
||||
## 1.6 Checkpoint/restore
|
||||
|
||||
Support for checkpoint/restore was [merged](https://github.com/docker/libcontainer/pull/479) in
|
||||
[libcontainer](https://github.com/docker/libcontainer) and made available through [runC](https://runc.io):
|
||||
we intend to take advantage of it in the Engine.
|
||||
|
||||
# 2 Frozen features
|
||||
|
||||
## 2.1 Docker exec
|
||||
|
||||
We won't accept patches expanding the surface of `docker exec`, which we intend to keep as a
|
||||
*debugging* feature, as well as being strongly dependent on the Runtime ingredient effort.
|
||||
|
||||
## 2.2 Dockerfile syntax
|
||||
|
||||
The Dockerfile syntax as we know it is simple, and has proven successful in supporting all our
|
||||
[official images](https://github.com/docker-library/official-images). Although this is *not* a
|
||||
definitive move, we temporarily won't accept more patches to the Dockerfile syntax for several
|
||||
reasons:
|
||||
|
||||
- Long term impact of syntax changes is a sensitive matter that require an amount of attention
|
||||
the volume of Engine codebase and activity today doesn't allow us to provide.
|
||||
- Allowing the Builder to be implemented as a separate utility consuming the Engine's API will
|
||||
open the door for many possibilities, such as offering alternate syntaxes or DSL for existing
|
||||
languages without cluttering the Engine's codebase.
|
||||
- A standalone Builder will also offer the opportunity for a better dedicated group of maintainers
|
||||
to own the Dockerfile syntax and decide collectively on the direction to give it.
|
||||
- Our experience with official images tend to show that no new instruction or syntax expansion is
|
||||
*strictly* necessary for the majority of use cases, and although we are aware many things are still
|
||||
lacking for many, we cannot make it a priority yet for the above reasons.
|
||||
|
||||
Again, this is not about saying that the Dockerfile syntax is done, it's about making choices about
|
||||
what we want to do first!
|
||||
|
||||
## 2.3 Remote Registry Operations
|
||||
|
||||
A large amount of work is ongoing in the area of image distribution and
|
||||
provenance. This includes moving to the V2 Registry API and heavily
|
||||
refactoring the code that powers these features. The desired result is more
|
||||
secure, reliable and easier to use image distribution.
|
||||
|
||||
Part of the problem with this part of the code base is the lack of a stable
|
||||
and flexible interface. If new features are added that access the registry
|
||||
without solidifying these interfaces, achieving feature parity will continue
|
||||
to be elusive. While we get a handle on this situation, we are imposing a
|
||||
moratorium on new code that accesses the Registry API in commands that don't
|
||||
already make remote calls.
|
||||
|
||||
Currently, only the following commands cause interaction with a remote
|
||||
registry:
|
||||
|
||||
- push
|
||||
- pull
|
||||
- run
|
||||
- build
|
||||
- search
|
||||
- login
|
||||
|
||||
In the interest of stabilizing the registry access model during this ongoing
|
||||
work, we are not accepting additions to other commands that will cause remote
|
||||
interaction with the Registry API. This moratorium will lift when the goals of
|
||||
the distribution project have been met.
|
||||
45
vendor/github.com/hyperhq/hypercli/VENDORING.md
generated
vendored
45
vendor/github.com/hyperhq/hypercli/VENDORING.md
generated
vendored
@@ -1,45 +0,0 @@
|
||||
# Vendoring policies
|
||||
|
||||
This document outlines recommended Vendoring policies for Docker repositories.
|
||||
(Example, libnetwork is a Docker repo and logrus is not.)
|
||||
|
||||
## Vendoring using tags
|
||||
|
||||
Commit ID based vendoring provides little/no information about the updates
|
||||
vendored. To fix this, vendors will now require that repositories use annotated
|
||||
tags along with commit ids to snapshot commits. Annotated tags by themselves
|
||||
are not sufficient, since the same tag can be force updated to reference
|
||||
different commits.
|
||||
|
||||
Each tag should:
|
||||
- Follow Semantic Versioning rules (refer to section on "Semantic Versioning")
|
||||
- Have a corresponding entry in the change tracking document.
|
||||
|
||||
Each repo should:
|
||||
- Have a change tracking document between tags/releases. Ex: CHANGELOG.md,
|
||||
github releases file.
|
||||
|
||||
The goal here is for consuming repos to be able to use the tag version and
|
||||
changelog updates to determine whether the vendoring will cause any breaking or
|
||||
backward incompatible changes. This also means that repos can specify having
|
||||
dependency on a package of a specific version or greater up to the next major
|
||||
release, without encountering breaking changes.
|
||||
|
||||
## Semantic Versioning
|
||||
Annotated version tags should follow Schema Versioning policies.
|
||||
According to http://semver.org:
|
||||
|
||||
"Given a version number MAJOR.MINOR.PATCH, increment the:
|
||||
MAJOR version when you make incompatible API changes,
|
||||
MINOR version when you add functionality in a backwards-compatible manner, and
|
||||
PATCH version when you make backwards-compatible bug fixes.
|
||||
Additional labels for pre-release and build metadata are available as extensions
|
||||
to the MAJOR.MINOR.PATCH format."
|
||||
|
||||
## Vendoring cadence
|
||||
In order to avoid huge vendoring changes, it is recommended to have a regular
|
||||
cadence for vendoring updates. eg. monthly.
|
||||
|
||||
## Pre-merge vendoring tests
|
||||
All related repos will be vendored into docker/docker.
|
||||
CI on docker/docker should catch any breaking changes involving multiple repos.
|
||||
1
vendor/github.com/hyperhq/hypercli/VERSION
generated
vendored
1
vendor/github.com/hyperhq/hypercli/VERSION
generated
vendored
@@ -1 +0,0 @@
|
||||
1.10.16
|
||||
5
vendor/github.com/hyperhq/hypercli/api/README.md
generated
vendored
5
vendor/github.com/hyperhq/hypercli/api/README.md
generated
vendored
@@ -1,5 +0,0 @@
|
||||
This directory contains code pertaining to the Docker API:
|
||||
|
||||
- Used by the docker client when communicating with the docker daemon
|
||||
|
||||
- Used by third party tools wishing to interface with the docker daemon
|
||||
101
vendor/github.com/hyperhq/hypercli/api/client/attach.go
generated
vendored
101
vendor/github.com/hyperhq/hypercli/api/client/attach.go
generated
vendored
@@ -1,101 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/pkg/signal"
|
||||
)
|
||||
|
||||
// CmdAttach attaches to a running container.
|
||||
//
|
||||
// Usage: docker attach [OPTIONS] CONTAINER
|
||||
func (cli *DockerCli) CmdAttach(args ...string) error {
|
||||
cmd := Cli.Subcmd("attach", []string{"CONTAINER"}, Cli.DockerCommands["attach"].Description, true)
|
||||
noStdin := cmd.Bool([]string{"-no-stdin"}, false, "Do not attach STDIN")
|
||||
proxy := cmd.Bool([]string{}, true, "Proxy all received signals to the process")
|
||||
detachKeys := cmd.String([]string{}, "", "Override the key sequence for detaching a container")
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
ctx := context.Background()
|
||||
containerID := cmd.Arg(0)
|
||||
|
||||
c, err := cli.client.ContainerInspect(ctx, containerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !c.State.Running {
|
||||
return fmt.Errorf("You cannot attach to a stopped container, start it first")
|
||||
}
|
||||
|
||||
if c.State.Paused {
|
||||
return fmt.Errorf("You cannot attach to a paused container, unpause it first")
|
||||
}
|
||||
|
||||
if err := cli.CheckTtyInput(!*noStdin, c.Config.Tty); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.Config.Tty && cli.isTerminalOut {
|
||||
if err := cli.monitorTtySize(ctx, cmd.Arg(0), false); err != nil {
|
||||
logrus.Debugf("Error monitoring TTY size: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if *detachKeys != "" {
|
||||
cli.configFile.DetachKeys = *detachKeys
|
||||
}
|
||||
|
||||
options := types.ContainerAttachOptions{
|
||||
Stream: true,
|
||||
Stdin: !*noStdin && c.Config.OpenStdin,
|
||||
Stdout: true,
|
||||
Stderr: true,
|
||||
DetachKeys: cli.configFile.DetachKeys,
|
||||
}
|
||||
|
||||
var in io.ReadCloser
|
||||
if options.Stdin {
|
||||
in = cli.in
|
||||
}
|
||||
|
||||
if *proxy && !c.Config.Tty {
|
||||
sigc := cli.forwardAllSignals(ctx, containerID)
|
||||
defer signal.StopCatch(sigc)
|
||||
}
|
||||
|
||||
resp, err := cli.client.ContainerAttach(ctx, containerID, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Close()
|
||||
if in != nil && c.Config.Tty {
|
||||
if err := cli.setRawTerminal(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.restoreTerminal(in)
|
||||
}
|
||||
|
||||
if err := cli.holdHijackedConnection(c.Config.Tty, in, cli.out, cli.err, resp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, status, err := getExitCode(ctx, cli, containerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if status != 0 {
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
651
vendor/github.com/hyperhq/hypercli/api/client/build.go
generated
vendored
651
vendor/github.com/hyperhq/hypercli/api/client/build.go
generated
vendored
@@ -1,651 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hypercli/api"
|
||||
"github.com/hyperhq/hypercli/builder/dockerignore"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/opts"
|
||||
"github.com/hyperhq/hypercli/pkg/archive"
|
||||
"github.com/hyperhq/hypercli/pkg/fileutils"
|
||||
"github.com/hyperhq/hypercli/pkg/gitutils"
|
||||
"github.com/hyperhq/hypercli/pkg/httputils"
|
||||
"github.com/hyperhq/hypercli/pkg/ioutils"
|
||||
"github.com/hyperhq/hypercli/pkg/jsonmessage"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/pkg/progress"
|
||||
"github.com/hyperhq/hypercli/pkg/streamformatter"
|
||||
"github.com/hyperhq/hypercli/pkg/urlutil"
|
||||
"github.com/hyperhq/hypercli/reference"
|
||||
runconfigopts "github.com/hyperhq/hypercli/runconfig/opts"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type translatorFunc func(context.Context, reference.NamedTagged) (reference.Canonical, error)
|
||||
|
||||
// CmdBuild builds a new image from the source code at a given path.
|
||||
//
|
||||
// If '-' is provided instead of a path or URL, Docker will build an image from either a Dockerfile or tar archive read from STDIN.
|
||||
//
|
||||
// Usage: docker build [OPTIONS] PATH | URL | -
|
||||
func (cli *DockerCli) Build(args ...string) error {
|
||||
cmd := Cli.Subcmd("build", []string{"PATH | URL | -"}, Cli.DockerCommands["build"].Description, true)
|
||||
flTags := opts.NewListOpts(validateTag)
|
||||
cmd.Var(&flTags, []string{"t", "-tag"}, "Name and optionally a tag in the 'name:tag' format")
|
||||
suppressOutput := cmd.Bool([]string{"q", "-quiet"}, false, "Suppress the build output and print image ID on success")
|
||||
noCache := cmd.Bool([]string{"-no-cache"}, false, "Do not use cache when building the image")
|
||||
rm := cmd.Bool([]string{"-rm"}, true, "Remove intermediate containers after a successful build")
|
||||
forceRm := cmd.Bool([]string{"-force-rm"}, false, "Always remove intermediate containers")
|
||||
pull := cmd.Bool([]string{"-pull"}, false, "Always attempt to pull a newer version of the image")
|
||||
dockerfileName := cmd.String([]string{"f", "-file"}, "", "Name of the Dockerfile (Default is 'PATH/Dockerfile')")
|
||||
flMemoryString := cmd.String([]string{"m", "-memory"}, "", "Memory limit")
|
||||
flMemorySwap := cmd.String([]string{"-memory-swap"}, "", "Swap limit equal to memory plus swap: '-1' to enable unlimited swap")
|
||||
flShmSize := cmd.String([]string{"-shm-size"}, "", "Size of /dev/shm, default value is 64MB")
|
||||
flCPUShares := cmd.Int64([]string{"#c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
|
||||
flCPUPeriod := cmd.Int64([]string{"-cpu-period"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) period")
|
||||
flCPUQuota := cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) quota")
|
||||
flCPUSetCpus := cmd.String([]string{"-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)")
|
||||
flCPUSetMems := cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)")
|
||||
flCgroupParent := cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup for the container")
|
||||
flBuildArg := opts.NewListOpts(runconfigopts.ValidateEnv)
|
||||
cmd.Var(&flBuildArg, []string{"-build-arg"}, "Set build-time variables")
|
||||
|
||||
ulimits := make(map[string]*units.Ulimit)
|
||||
flUlimits := runconfigopts.NewUlimitOpt(&ulimits)
|
||||
cmd.Var(flUlimits, []string{"-ulimit"}, "Ulimit options")
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
|
||||
// For trusted pull on "FROM <image>" instruction.
|
||||
addTrustedFlags(cmd, true)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
var (
|
||||
buildCtx io.ReadCloser
|
||||
err error
|
||||
)
|
||||
|
||||
specifiedContext := cmd.Arg(0)
|
||||
|
||||
var (
|
||||
contextDir string
|
||||
tempDir string
|
||||
relDockerfile string
|
||||
progBuff io.Writer
|
||||
buildBuff io.Writer
|
||||
)
|
||||
|
||||
progBuff = cli.out
|
||||
buildBuff = cli.out
|
||||
if *suppressOutput {
|
||||
progBuff = bytes.NewBuffer(nil)
|
||||
buildBuff = bytes.NewBuffer(nil)
|
||||
}
|
||||
|
||||
switch {
|
||||
case specifiedContext == "-":
|
||||
buildCtx, relDockerfile, err = getContextFromReader(cli.in, *dockerfileName)
|
||||
case urlutil.IsGitURL(specifiedContext):
|
||||
tempDir, relDockerfile, err = getContextFromGitURL(specifiedContext, *dockerfileName)
|
||||
case urlutil.IsURL(specifiedContext):
|
||||
buildCtx, relDockerfile, err = getContextFromURL(progBuff, specifiedContext, *dockerfileName)
|
||||
default:
|
||||
contextDir, relDockerfile, err = getContextFromLocalDir(specifiedContext, *dockerfileName)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if *suppressOutput && urlutil.IsURL(specifiedContext) {
|
||||
fmt.Fprintln(cli.err, progBuff)
|
||||
}
|
||||
return fmt.Errorf("unable to prepare context: %s", err)
|
||||
}
|
||||
|
||||
if tempDir != "" {
|
||||
defer os.RemoveAll(tempDir)
|
||||
contextDir = tempDir
|
||||
}
|
||||
|
||||
if buildCtx == nil {
|
||||
// And canonicalize dockerfile name to a platform-independent one
|
||||
relDockerfile, err = archive.CanonicalTarNameForPath(relDockerfile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot canonicalize dockerfile path %s: %v", relDockerfile, err)
|
||||
}
|
||||
|
||||
f, err := os.Open(filepath.Join(contextDir, ".dockerignore"))
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
var excludes []string
|
||||
if err == nil {
|
||||
excludes, err = dockerignore.ReadAll(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := validateContextDirectory(contextDir, excludes); err != nil {
|
||||
return fmt.Errorf("Error checking context: '%s'.", err)
|
||||
}
|
||||
|
||||
// If .dockerignore mentions .dockerignore or the Dockerfile
|
||||
// then make sure we send both files over to the daemon
|
||||
// because Dockerfile is, obviously, needed no matter what, and
|
||||
// .dockerignore is needed to know if either one needs to be
|
||||
// removed. The daemon will remove them for us, if needed, after it
|
||||
// parses the Dockerfile. Ignore errors here, as they will have been
|
||||
// caught by validateContextDirectory above.
|
||||
var includes = []string{"."}
|
||||
keepThem1, _ := fileutils.Matches(".dockerignore", excludes)
|
||||
keepThem2, _ := fileutils.Matches(relDockerfile, excludes)
|
||||
if keepThem1 || keepThem2 {
|
||||
includes = append(includes, ".dockerignore", relDockerfile)
|
||||
}
|
||||
|
||||
buildCtx, err = archive.TarWithOptions(contextDir, &archive.TarOptions{
|
||||
Compression: archive.Uncompressed,
|
||||
ExcludePatterns: excludes,
|
||||
IncludeFiles: includes,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
var resolvedTags []*resolvedTag
|
||||
if isTrusted() {
|
||||
// Wrap the tar archive to replace the Dockerfile entry with the rewritten
|
||||
// Dockerfile which uses trusted pulls.
|
||||
buildCtx = replaceDockerfileTarWrapper(ctx, buildCtx, relDockerfile, cli.trustedReference, &resolvedTags)
|
||||
}
|
||||
|
||||
// Setup an upload progress bar
|
||||
progressOutput := streamformatter.NewStreamFormatter().NewProgressOutput(progBuff, true)
|
||||
|
||||
var body io.Reader = progress.NewProgressReader(buildCtx, progressOutput, 0, "", "Sending build context to Docker daemon")
|
||||
|
||||
var memory int64
|
||||
if *flMemoryString != "" {
|
||||
parsedMemory, err := units.RAMInBytes(*flMemoryString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
memory = parsedMemory
|
||||
}
|
||||
|
||||
var memorySwap int64
|
||||
if *flMemorySwap != "" {
|
||||
if *flMemorySwap == "-1" {
|
||||
memorySwap = -1
|
||||
} else {
|
||||
parsedMemorySwap, err := units.RAMInBytes(*flMemorySwap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
memorySwap = parsedMemorySwap
|
||||
}
|
||||
}
|
||||
|
||||
var shmSize int64
|
||||
if *flShmSize != "" {
|
||||
shmSize, err = units.RAMInBytes(*flShmSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
options := types.ImageBuildOptions{
|
||||
Memory: memory,
|
||||
MemorySwap: memorySwap,
|
||||
Tags: flTags.GetAll(),
|
||||
SuppressOutput: *suppressOutput,
|
||||
NoCache: *noCache,
|
||||
Remove: *rm,
|
||||
ForceRemove: *forceRm,
|
||||
PullParent: *pull,
|
||||
CPUSetCPUs: *flCPUSetCpus,
|
||||
CPUSetMems: *flCPUSetMems,
|
||||
CPUShares: *flCPUShares,
|
||||
CPUQuota: *flCPUQuota,
|
||||
CPUPeriod: *flCPUPeriod,
|
||||
CgroupParent: *flCgroupParent,
|
||||
Dockerfile: relDockerfile,
|
||||
ShmSize: shmSize,
|
||||
Ulimits: flUlimits.GetList(),
|
||||
BuildArgs: runconfigopts.ConvertKVStringsToMap(flBuildArg.GetAll()),
|
||||
AuthConfigs: cli.configFile.AuthConfigs,
|
||||
}
|
||||
|
||||
response, err := cli.client.ImageBuild(ctx, body, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = jsonmessage.DisplayJSONMessagesStream(response.Body, buildBuff, cli.outFd, cli.isTerminalOut, nil)
|
||||
if err != nil {
|
||||
if jerr, ok := err.(*jsonmessage.JSONError); ok {
|
||||
// If no error code is set, default to 1
|
||||
if jerr.Code == 0 {
|
||||
jerr.Code = 1
|
||||
}
|
||||
if *suppressOutput {
|
||||
fmt.Fprintf(cli.err, "%s%s", progBuff, buildBuff)
|
||||
}
|
||||
return Cli.StatusError{Status: jerr.Message, StatusCode: jerr.Code}
|
||||
}
|
||||
}
|
||||
|
||||
// Windows: show error message about modified file permissions if the
|
||||
// daemon isn't running Windows.
|
||||
if response.OSType != "windows" && runtime.GOOS == "windows" {
|
||||
fmt.Fprintln(cli.err, `SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.`)
|
||||
}
|
||||
|
||||
// Everything worked so if -q was provided the output from the daemon
|
||||
// should be just the image ID and we'll print that to stdout.
|
||||
if *suppressOutput {
|
||||
fmt.Fprintf(cli.out, "%s", buildBuff)
|
||||
}
|
||||
|
||||
if isTrusted() {
|
||||
// Since the build was successful, now we must tag any of the resolved
|
||||
// images from the above Dockerfile rewrite.
|
||||
for _, resolved := range resolvedTags {
|
||||
if err := cli.tagTrusted(ctx, resolved.digestRef, resolved.tagRef); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateContextDirectory checks if all the contents of the directory
|
||||
// can be read and returns an error if some files can't be read
|
||||
// symlinks which point to non-existing files don't trigger an error
|
||||
func validateContextDirectory(srcPath string, excludes []string) error {
|
||||
contextRoot, err := getContextRoot(srcPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return filepath.Walk(contextRoot, func(filePath string, f os.FileInfo, err error) error {
|
||||
// skip this directory/file if it's not in the path, it won't get added to the context
|
||||
if relFilePath, err := filepath.Rel(contextRoot, filePath); err != nil {
|
||||
return err
|
||||
} else if skip, err := fileutils.Matches(relFilePath, excludes); err != nil {
|
||||
return err
|
||||
} else if skip {
|
||||
if f.IsDir() {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if os.IsPermission(err) {
|
||||
return fmt.Errorf("can't stat '%s'", filePath)
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// skip checking if symlinks point to non-existing files, such symlinks can be useful
|
||||
// also skip named pipes, because they hanging on open
|
||||
if f.Mode()&(os.ModeSymlink|os.ModeNamedPipe) != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !f.IsDir() {
|
||||
currentFile, err := os.Open(filePath)
|
||||
if err != nil && os.IsPermission(err) {
|
||||
return fmt.Errorf("no permission to read from '%s'", filePath)
|
||||
}
|
||||
currentFile.Close()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// validateTag checks if the given image name can be resolved.
|
||||
func validateTag(rawRepo string) (string, error) {
|
||||
_, err := reference.ParseNamed(rawRepo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return rawRepo, nil
|
||||
}
|
||||
|
||||
// isUNC returns true if the path is UNC (one starting \\). It always returns
|
||||
// false on Linux.
|
||||
func isUNC(path string) bool {
|
||||
return runtime.GOOS == "windows" && strings.HasPrefix(path, `\\`)
|
||||
}
|
||||
|
||||
// getDockerfileRelPath uses the given context directory for a `docker build`
|
||||
// and returns the absolute path to the context directory, the relative path of
|
||||
// the dockerfile in that context directory, and a non-nil error on success.
|
||||
func getDockerfileRelPath(givenContextDir, givenDockerfile string) (absContextDir, relDockerfile string, err error) {
|
||||
if absContextDir, err = filepath.Abs(givenContextDir); err != nil {
|
||||
return "", "", fmt.Errorf("unable to get absolute context directory: %v", err)
|
||||
}
|
||||
|
||||
// The context dir might be a symbolic link, so follow it to the actual
|
||||
// target directory.
|
||||
//
|
||||
// FIXME. We use isUNC (always false on non-Windows platforms) to workaround
|
||||
// an issue in golang. On Windows, EvalSymLinks does not work on UNC file
|
||||
// paths (those starting with \\). This hack means that when using links
|
||||
// on UNC paths, they will not be followed.
|
||||
if !isUNC(absContextDir) {
|
||||
absContextDir, err = filepath.EvalSymlinks(absContextDir)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("unable to evaluate symlinks in context path: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
stat, err := os.Lstat(absContextDir)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("unable to stat context directory %q: %v", absContextDir, err)
|
||||
}
|
||||
|
||||
if !stat.IsDir() {
|
||||
return "", "", fmt.Errorf("context must be a directory: %s", absContextDir)
|
||||
}
|
||||
|
||||
absDockerfile := givenDockerfile
|
||||
if absDockerfile == "" {
|
||||
// No -f/--file was specified so use the default relative to the
|
||||
// context directory.
|
||||
absDockerfile = filepath.Join(absContextDir, api.DefaultDockerfileName)
|
||||
|
||||
// Just to be nice ;-) look for 'dockerfile' too but only
|
||||
// use it if we found it, otherwise ignore this check
|
||||
if _, err = os.Lstat(absDockerfile); os.IsNotExist(err) {
|
||||
altPath := filepath.Join(absContextDir, strings.ToLower(api.DefaultDockerfileName))
|
||||
if _, err = os.Lstat(altPath); err == nil {
|
||||
absDockerfile = altPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If not already an absolute path, the Dockerfile path should be joined to
|
||||
// the base directory.
|
||||
if !filepath.IsAbs(absDockerfile) {
|
||||
absDockerfile = filepath.Join(absContextDir, absDockerfile)
|
||||
}
|
||||
|
||||
// Evaluate symlinks in the path to the Dockerfile too.
|
||||
//
|
||||
// FIXME. We use isUNC (always false on non-Windows platforms) to workaround
|
||||
// an issue in golang. On Windows, EvalSymLinks does not work on UNC file
|
||||
// paths (those starting with \\). This hack means that when using links
|
||||
// on UNC paths, they will not be followed.
|
||||
if !isUNC(absDockerfile) {
|
||||
absDockerfile, err = filepath.EvalSymlinks(absDockerfile)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("unable to evaluate symlinks in Dockerfile path: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := os.Lstat(absDockerfile); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return "", "", fmt.Errorf("Cannot locate Dockerfile: %q", absDockerfile)
|
||||
}
|
||||
return "", "", fmt.Errorf("unable to stat Dockerfile: %v", err)
|
||||
}
|
||||
|
||||
if relDockerfile, err = filepath.Rel(absContextDir, absDockerfile); err != nil {
|
||||
return "", "", fmt.Errorf("unable to get relative Dockerfile path: %v", err)
|
||||
}
|
||||
|
||||
if strings.HasPrefix(relDockerfile, ".."+string(filepath.Separator)) {
|
||||
return "", "", fmt.Errorf("The Dockerfile (%s) must be within the build context (%s)", givenDockerfile, givenContextDir)
|
||||
}
|
||||
|
||||
return absContextDir, relDockerfile, nil
|
||||
}
|
||||
|
||||
// writeToFile copies from the given reader and writes it to a file with the
|
||||
// given filename.
|
||||
func writeToFile(r io.Reader, filename string) error {
|
||||
file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create file: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if _, err := io.Copy(file, r); err != nil {
|
||||
return fmt.Errorf("unable to write file: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getContextFromReader will read the contents of the given reader as either a
|
||||
// Dockerfile or tar archive. Returns a tar archive used as a context and a
|
||||
// path to the Dockerfile inside the tar.
|
||||
func getContextFromReader(r io.ReadCloser, dockerfileName string) (out io.ReadCloser, relDockerfile string, err error) {
|
||||
buf := bufio.NewReader(r)
|
||||
|
||||
magic, err := buf.Peek(archive.HeaderSize)
|
||||
if err != nil && err != io.EOF {
|
||||
return nil, "", fmt.Errorf("failed to peek context header from STDIN: %v", err)
|
||||
}
|
||||
|
||||
if archive.IsArchive(magic) {
|
||||
return ioutils.NewReadCloserWrapper(buf, func() error { return r.Close() }), dockerfileName, nil
|
||||
}
|
||||
|
||||
// Input should be read as a Dockerfile.
|
||||
tmpDir, err := ioutil.TempDir("", "docker-build-context-")
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("unbale to create temporary context directory: %v", err)
|
||||
}
|
||||
|
||||
f, err := os.Create(filepath.Join(tmpDir, api.DefaultDockerfileName))
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
_, err = io.Copy(f, buf)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
if err := f.Close(); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if err := r.Close(); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
tar, err := archive.Tar(tmpDir, archive.Uncompressed)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
return ioutils.NewReadCloserWrapper(tar, func() error {
|
||||
err := tar.Close()
|
||||
os.RemoveAll(tmpDir)
|
||||
return err
|
||||
}), api.DefaultDockerfileName, nil
|
||||
|
||||
}
|
||||
|
||||
// getContextFromGitURL uses a Git URL as context for a `docker build`. The
|
||||
// git repo is cloned into a temporary directory used as the context directory.
|
||||
// Returns the absolute path to the temporary context directory, the relative
|
||||
// path of the dockerfile in that context directory, and a non-nil error on
|
||||
// success.
|
||||
func getContextFromGitURL(gitURL, dockerfileName string) (absContextDir, relDockerfile string, err error) {
|
||||
if _, err := exec.LookPath("git"); err != nil {
|
||||
return "", "", fmt.Errorf("unable to find 'git': %v", err)
|
||||
}
|
||||
if absContextDir, err = gitutils.Clone(gitURL); err != nil {
|
||||
return "", "", fmt.Errorf("unable to 'git clone' to temporary context directory: %v", err)
|
||||
}
|
||||
|
||||
return getDockerfileRelPath(absContextDir, dockerfileName)
|
||||
}
|
||||
|
||||
// getContextFromURL uses a remote URL as context for a `docker build`. The
|
||||
// remote resource is downloaded as either a Dockerfile or a tar archive.
|
||||
// Returns the tar archive used for the context and a path of the
|
||||
// dockerfile inside the tar.
|
||||
func getContextFromURL(out io.Writer, remoteURL, dockerfileName string) (io.ReadCloser, string, error) {
|
||||
response, err := httputils.Download(remoteURL)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("unable to download remote context %s: %v", remoteURL, err)
|
||||
}
|
||||
progressOutput := streamformatter.NewStreamFormatter().NewProgressOutput(out, true)
|
||||
|
||||
// Pass the response body through a progress reader.
|
||||
progReader := progress.NewProgressReader(response.Body, progressOutput, response.ContentLength, "", fmt.Sprintf("Downloading build context from remote url: %s", remoteURL))
|
||||
|
||||
return getContextFromReader(ioutils.NewReadCloserWrapper(progReader, func() error { return response.Body.Close() }), dockerfileName)
|
||||
}
|
||||
|
||||
// getContextFromLocalDir uses the given local directory as context for a
|
||||
// `docker build`. Returns the absolute path to the local context directory,
|
||||
// the relative path of the dockerfile in that context directory, and a non-nil
|
||||
// error on success.
|
||||
func getContextFromLocalDir(localDir, dockerfileName string) (absContextDir, relDockerfile string, err error) {
|
||||
// When using a local context directory, when the Dockerfile is specified
|
||||
// with the `-f/--file` option then it is considered relative to the
|
||||
// current directory and not the context directory.
|
||||
if dockerfileName != "" {
|
||||
if dockerfileName, err = filepath.Abs(dockerfileName); err != nil {
|
||||
return "", "", fmt.Errorf("unable to get absolute path to Dockerfile: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return getDockerfileRelPath(localDir, dockerfileName)
|
||||
}
|
||||
|
||||
var dockerfileFromLinePattern = regexp.MustCompile(`(?i)^[\s]*FROM[ \f\r\t\v]+(?P<image>[^ \f\r\t\v\n#]+)`)
|
||||
|
||||
// resolvedTag records the repository, tag, and resolved digest reference
|
||||
// from a Dockerfile rewrite.
|
||||
type resolvedTag struct {
|
||||
digestRef reference.Canonical
|
||||
tagRef reference.NamedTagged
|
||||
}
|
||||
|
||||
// rewriteDockerfileFrom rewrites the given Dockerfile by resolving images in
|
||||
// "FROM <image>" instructions to a digest reference. `translator` is a
|
||||
// function that takes a repository name and tag reference and returns a
|
||||
// trusted digest reference.
|
||||
func rewriteDockerfileFrom(ctx context.Context, dockerfile io.Reader, translator translatorFunc) (newDockerfile []byte, resolvedTags []*resolvedTag, err error) {
|
||||
scanner := bufio.NewScanner(dockerfile)
|
||||
buf := bytes.NewBuffer(nil)
|
||||
|
||||
// Scan the lines of the Dockerfile, looking for a "FROM" line.
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
matches := dockerfileFromLinePattern.FindStringSubmatch(line)
|
||||
if matches != nil && matches[1] != api.NoBaseImageSpecifier {
|
||||
// Replace the line with a resolved "FROM repo@digest"
|
||||
ref, err := reference.ParseNamed(matches[1])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
ref = reference.WithDefaultTag(ref)
|
||||
if ref, ok := ref.(reference.NamedTagged); ok && isTrusted() {
|
||||
trustedRef, err := translator(ctx, ref)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
line = dockerfileFromLinePattern.ReplaceAllLiteralString(line, fmt.Sprintf("FROM %s", trustedRef.String()))
|
||||
resolvedTags = append(resolvedTags, &resolvedTag{
|
||||
digestRef: trustedRef,
|
||||
tagRef: ref,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
_, err := fmt.Fprintln(buf, line)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return buf.Bytes(), resolvedTags, scanner.Err()
|
||||
}
|
||||
|
||||
// replaceDockerfileTarWrapper wraps the given input tar archive stream and
|
||||
// replaces the entry with the given Dockerfile name with the contents of the
|
||||
// new Dockerfile. Returns a new tar archive stream with the replaced
|
||||
// Dockerfile.
|
||||
func replaceDockerfileTarWrapper(ctx context.Context, inputTarStream io.ReadCloser, dockerfileName string, translator translatorFunc, resolvedTags *[]*resolvedTag) io.ReadCloser {
|
||||
pipeReader, pipeWriter := io.Pipe()
|
||||
go func() {
|
||||
tarReader := tar.NewReader(inputTarStream)
|
||||
tarWriter := tar.NewWriter(pipeWriter)
|
||||
|
||||
defer inputTarStream.Close()
|
||||
|
||||
for {
|
||||
hdr, err := tarReader.Next()
|
||||
if err == io.EOF {
|
||||
// Signals end of archive.
|
||||
tarWriter.Close()
|
||||
pipeWriter.Close()
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
pipeWriter.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
var content io.Reader = tarReader
|
||||
if hdr.Name == dockerfileName {
|
||||
// This entry is the Dockerfile. Since the tar archive was
|
||||
// generated from a directory on the local filesystem, the
|
||||
// Dockerfile will only appear once in the archive.
|
||||
var newDockerfile []byte
|
||||
newDockerfile, *resolvedTags, err = rewriteDockerfileFrom(ctx, content, translator)
|
||||
if err != nil {
|
||||
pipeWriter.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
hdr.Size = int64(len(newDockerfile))
|
||||
content = bytes.NewBuffer(newDockerfile)
|
||||
}
|
||||
|
||||
if err := tarWriter.WriteHeader(hdr); err != nil {
|
||||
pipeWriter.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := io.Copy(tarWriter, content); err != nil {
|
||||
pipeWriter.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return pipeReader
|
||||
}
|
||||
247
vendor/github.com/hyperhq/hypercli/api/client/cli.go
generated
vendored
247
vendor/github.com/hyperhq/hypercli/api/client/cli.go
generated
vendored
@@ -1,247 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/go-connections/sockets"
|
||||
"github.com/docker/go-connections/tlsconfig"
|
||||
"github.com/hyperhq/hyper-api/client"
|
||||
"github.com/hyperhq/hypercli/api"
|
||||
"github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/cliconfig"
|
||||
"github.com/hyperhq/hypercli/dockerversion"
|
||||
"github.com/hyperhq/hypercli/opts"
|
||||
"github.com/hyperhq/hypercli/pkg/term"
|
||||
)
|
||||
|
||||
// DockerCli represents the docker command line client.
|
||||
// Instances of the client can be returned from NewDockerCli.
|
||||
type DockerCli struct {
|
||||
// initializing closure
|
||||
init func() error
|
||||
|
||||
// configFile has the client configuration file
|
||||
configFile *cliconfig.ConfigFile
|
||||
// in holds the input stream and closer (io.ReadCloser) for the client.
|
||||
in io.ReadCloser
|
||||
// out holds the output stream (io.Writer) for the client.
|
||||
out io.Writer
|
||||
// err holds the error stream (io.Writer) for the client.
|
||||
err io.Writer
|
||||
// keyFile holds the key file as a string.
|
||||
keyFile string
|
||||
// inFd holds the file descriptor of the client's STDIN (if valid).
|
||||
inFd uintptr
|
||||
// outFd holds file descriptor of the client's STDOUT (if valid).
|
||||
outFd uintptr
|
||||
// isTerminalIn indicates whether the client's STDIN is a TTY
|
||||
isTerminalIn bool
|
||||
// isTerminalOut indicates whether the client's STDOUT is a TTY
|
||||
isTerminalOut bool
|
||||
// client is the http client that performs all API operations
|
||||
client client.APIClient
|
||||
// state holds the terminal state
|
||||
state *term.State
|
||||
region string
|
||||
host string
|
||||
}
|
||||
|
||||
// Initialize calls the init function that will setup the configuration for the client
|
||||
// such as the TLS, tcp and other parameters used to run the client.
|
||||
func (cli *DockerCli) Initialize() error {
|
||||
if cli.init == nil {
|
||||
return nil
|
||||
}
|
||||
return cli.init()
|
||||
}
|
||||
|
||||
// CheckTtyInput checks if we are trying to attach to a container tty
|
||||
// from a non-tty client input stream, and if so, returns an error.
|
||||
func (cli *DockerCli) CheckTtyInput(attachStdin, ttyMode bool) error {
|
||||
// In order to attach to a container tty, input stream for the client must
|
||||
// be a tty itself: redirecting or piping the client standard input is
|
||||
// incompatible with `docker run -t`, `docker exec -t` or `docker attach`.
|
||||
if ttyMode && attachStdin && !cli.isTerminalIn {
|
||||
return errors.New("cannot enable tty mode on non tty input")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PsFormat returns the format string specified in the configuration.
|
||||
// String contains columns and format specification, for example {{ID}}\t{{Name}}.
|
||||
func (cli *DockerCli) PsFormat() string {
|
||||
return cli.configFile.PsFormat
|
||||
}
|
||||
|
||||
// ImagesFormat returns the format string specified in the configuration.
|
||||
// String contains columns and format specification, for example {{ID}}\t{{Name}}.
|
||||
func (cli *DockerCli) ImagesFormat() string {
|
||||
return cli.configFile.ImagesFormat
|
||||
}
|
||||
|
||||
// VolumesFormat returns the format string specified in the configuration.
|
||||
// String contains columns and format specification, for example {{ID}}\t{{Name}}.
|
||||
func (cli *DockerCli) VolumesFormat() string {
|
||||
return cli.configFile.VolumesFormat
|
||||
}
|
||||
|
||||
func (cli *DockerCli) setRawTerminal() error {
|
||||
if cli.isTerminalIn && os.Getenv("NORAW") == "" {
|
||||
state, err := term.SetRawTerminal(cli.inFd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cli.state = state
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) restoreTerminal(in io.Closer) error {
|
||||
if cli.state != nil {
|
||||
term.RestoreTerminal(cli.inFd, cli.state)
|
||||
}
|
||||
// WARNING: DO NOT REMOVE THE OS CHECK !!!
|
||||
// For some reason this Close call blocks on darwin..
|
||||
// As the client exists right after, simply discard the close
|
||||
// until we find a better solution.
|
||||
if in != nil && runtime.GOOS != "darwin" {
|
||||
return in.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err.
|
||||
// The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config
|
||||
// is set the client scheme will be set to https.
|
||||
// The client will be given a 32-second timeout (see https://github.com/hyperhq/hypercli/pull/8035).
|
||||
func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientFlags) *DockerCli {
|
||||
cli := &DockerCli{
|
||||
in: in,
|
||||
out: out,
|
||||
err: err,
|
||||
keyFile: clientFlags.Common.TrustKey,
|
||||
}
|
||||
|
||||
cli.init = func() error {
|
||||
clientFlags.PostParse()
|
||||
configFile, e := cliconfig.Load(cliconfig.ConfigDir())
|
||||
if e != nil {
|
||||
fmt.Fprintf(cli.err, "WARNING: Error loading config file:%v\n", e)
|
||||
}
|
||||
cli.configFile = configFile
|
||||
|
||||
host, dft, err := cli.getServerHost(clientFlags.Common.Region, clientFlags.Common.TLSOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
customHeaders := cli.configFile.HTTPHeaders
|
||||
if customHeaders == nil {
|
||||
customHeaders = map[string]string{}
|
||||
}
|
||||
customHeaders["User-Agent"] = "Docker-Client/" + dockerversion.Version + " (" + runtime.GOOS + ")"
|
||||
|
||||
verStr := api.DefaultVersion.String()
|
||||
if tmpStr := os.Getenv("HYPER_API_VERSION"); tmpStr != "" {
|
||||
verStr = tmpStr
|
||||
}
|
||||
|
||||
httpClient, err := newHTTPClient(host, clientFlags.Common.TLSOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var cloudConfig cliconfig.CloudConfig
|
||||
cc, ok := configFile.CloudConfig[cliconfig.DefaultHyperFormat]
|
||||
if ok && dft {
|
||||
cloudConfig.AccessKey = cc.AccessKey
|
||||
cloudConfig.SecretKey = cc.SecretKey
|
||||
} else {
|
||||
cc, ok = configFile.CloudConfig[host]
|
||||
if ok {
|
||||
cloudConfig.AccessKey = cc.AccessKey
|
||||
cloudConfig.SecretKey = cc.SecretKey
|
||||
} else {
|
||||
cloudConfig.AccessKey = os.Getenv("HYPER_ACCESS")
|
||||
cloudConfig.SecretKey = os.Getenv("HYPER_SECRET")
|
||||
}
|
||||
}
|
||||
if cloudConfig.AccessKey == "" || cloudConfig.SecretKey == "" {
|
||||
fmt.Fprintf(cli.err, "WARNING: null cloud config\n")
|
||||
}
|
||||
cli.region = clientFlags.Common.Region
|
||||
if cli.region == "" {
|
||||
if cli.region = cc.Region; cli.region == "" {
|
||||
cli.region = cli.getDefaultRegion()
|
||||
}
|
||||
}
|
||||
if !dft {
|
||||
if cli.region = cc.Region; cli.region == "" {
|
||||
cli.region = cliconfig.DefaultHyperRegion
|
||||
}
|
||||
}
|
||||
|
||||
client, err := client.NewClient(host, verStr, httpClient, customHeaders, cloudConfig.AccessKey, cloudConfig.SecretKey, cli.region)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cli.client = client
|
||||
cli.host = host
|
||||
if cli.in != nil {
|
||||
cli.inFd, cli.isTerminalIn = term.GetFdInfo(cli.in)
|
||||
}
|
||||
if cli.out != nil {
|
||||
cli.outFd, cli.isTerminalOut = term.GetFdInfo(cli.out)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return cli
|
||||
}
|
||||
|
||||
func (cli *DockerCli) getServerHost(region string, tlsOptions *tlsconfig.Options) (host string, dft bool, err error) {
|
||||
dft = false
|
||||
host = region
|
||||
if host == "" {
|
||||
host = os.Getenv("HYPER_DEFAULT_REGION")
|
||||
region = cli.getDefaultRegion()
|
||||
}
|
||||
if _, err := url.ParseRequestURI(host); err != nil {
|
||||
host = "tcp://" + region + "." + cliconfig.DefaultHyperEndpoint
|
||||
dft = true
|
||||
}
|
||||
|
||||
host, err = opts.ParseHost(tlsOptions != nil, host)
|
||||
return
|
||||
}
|
||||
|
||||
func newHTTPClient(host string, tlsOptions *tlsconfig.Options) (*http.Client, error) {
|
||||
if tlsOptions == nil {
|
||||
// let the api client configure the default transport.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
config, err := tlsconfig.Client(*tlsOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: config,
|
||||
}
|
||||
proto, addr, _, err := client.ParseHost(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sockets.ConfigureTransport(tr, proto, addr)
|
||||
|
||||
return &http.Client{
|
||||
Transport: tr,
|
||||
}, nil
|
||||
}
|
||||
5
vendor/github.com/hyperhq/hypercli/api/client/client.go
generated
vendored
5
vendor/github.com/hyperhq/hypercli/api/client/client.go
generated
vendored
@@ -1,5 +0,0 @@
|
||||
// Package client provides a command-line interface for Docker.
|
||||
//
|
||||
// Run "docker help SUBCOMMAND" or "docker SUBCOMMAND --help" to see more information on any Docker subcommand, including the full list of options supported for the subcommand.
|
||||
// See https://docs.docker.com/installation/ for instructions on installing Docker.
|
||||
package client
|
||||
61
vendor/github.com/hyperhq/hypercli/api/client/commit.go
generated
vendored
61
vendor/github.com/hyperhq/hypercli/api/client/commit.go
generated
vendored
@@ -1,61 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hyper-api/types/container"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/opts"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// CmdCommit creates a new image from a container's changes.
|
||||
//
|
||||
// Usage: hyper commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
|
||||
func (cli *DockerCli) CmdCommit(args ...string) error {
|
||||
cmd := Cli.Subcmd("commit", []string{"CONTAINER [REPOSITORY[:TAG]]"}, Cli.DockerCommands["commit"].Description, true)
|
||||
flPause := cmd.Bool([]string{}, true, "Pause container during commit")
|
||||
flComment := cmd.String([]string{"m", "-message"}, "", "Commit message")
|
||||
flAuthor := cmd.String([]string{"a", "-author"}, "", "Author (e.g., \"John Hannibal Smith <hannibal@a-team.com>\")")
|
||||
flChanges := opts.NewListOpts(nil)
|
||||
cmd.Var(&flChanges, []string{"c", "-change"}, "Apply Dockerfile instruction to the created image")
|
||||
// FIXME: --run is deprecated, it will be replaced with inline Dockerfile commands.
|
||||
flConfig := cmd.String([]string{}, "", "This option is deprecated and will be removed in a future version in favor of inline Dockerfile-compatible commands")
|
||||
cmd.Require(flag.Max, 2)
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
var (
|
||||
name = cmd.Arg(0)
|
||||
reference = cmd.Arg(1)
|
||||
)
|
||||
|
||||
var config *container.Config
|
||||
if *flConfig != "" {
|
||||
config = &container.Config{}
|
||||
if err := json.Unmarshal([]byte(*flConfig), config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
options := types.ContainerCommitOptions{
|
||||
Reference: reference,
|
||||
Comment: *flComment,
|
||||
Author: *flAuthor,
|
||||
Changes: flChanges.GetAll(),
|
||||
Pause: *flPause,
|
||||
Config: config,
|
||||
}
|
||||
|
||||
response, err := cli.client.ContainerCommit(context.Background(), name, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintln(cli.out, response.ID)
|
||||
return nil
|
||||
}
|
||||
519
vendor/github.com/hyperhq/hypercli/api/client/compose.go
generated
vendored
519
vendor/github.com/hyperhq/hypercli/api/client/compose.go
generated
vendored
@@ -1,519 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/hyperhq/hyper-api/client"
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hyper-api/types/filters"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/pkg/jsonmessage"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/libcompose/docker"
|
||||
"github.com/hyperhq/libcompose/logger"
|
||||
"github.com/hyperhq/libcompose/project"
|
||||
"github.com/hyperhq/libcompose/project/options"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
const ComposeFipAuto = "auto"
|
||||
|
||||
// CmdCompose is the parent subcommand for all compose commands
|
||||
//
|
||||
// Usage: hyper compose <COMMAND> [OPTIONS]
|
||||
func (cli *DockerCli) CmdCompose(args ...string) error {
|
||||
cmd := Cli.Subcmd("compose", []string{"<COMMAND>"}, composeUsage(), false)
|
||||
cmd.Require(flag.Min, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
// CmdComposeRun
|
||||
//
|
||||
// Usage: hyper compose run [OPTIONS] SERVICE [COMMAND] [ARGS...]
|
||||
func (cli *DockerCli) CmdComposeRun(args ...string) error {
|
||||
cmd := Cli.Subcmd("compose run", []string{"SERVICE [COMMAND] [ARGS...]"}, "Run a one-off command on a service", false)
|
||||
composeFile := cmd.String([]string{"f", "-file"}, "docker-compose.yml", "Specify an alternate compose file")
|
||||
projectName := cmd.String([]string{"p", "-project-name"}, "", "Specify an alternate project name")
|
||||
rm := cmd.Bool([]string{"-rm"}, false, "Remove container after run, ignored in detached mode")
|
||||
|
||||
cmd.Require(flag.Min, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *projectName == "" {
|
||||
*projectName = getBaseDir()
|
||||
}
|
||||
project, err := docker.NewProject(&docker.Context{
|
||||
Context: project.Context{
|
||||
ComposeFiles: []string{*composeFile},
|
||||
ProjectName: *projectName,
|
||||
Autoremove: *rm,
|
||||
},
|
||||
ClientFactory: cli,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
service := cmd.Args()[0]
|
||||
status, err := project.Run(context.Background(), service, cmd.Args()[1:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *rm {
|
||||
opts := options.Delete{RemoveVolume: true}
|
||||
if err = project.Delete(opts, service); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if status != 0 {
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdComposeDown
|
||||
//
|
||||
// Usage: hyper compose down [OPTIONS]
|
||||
func (cli *DockerCli) CmdComposeDown(args ...string) error {
|
||||
cmd := Cli.Subcmd("compose down", []string{}, "Stop and remove containers, images, and volumes\ncreated by `up`. Only containers and networks are removed by default.", false)
|
||||
projectName := cmd.String([]string{"p", "-project-name"}, "", "Specify an alternate project name")
|
||||
rmi := cmd.String([]string{"-rmi"}, "", "Remove images, type may be one of: 'all' to remove\nall images, or 'local' to remove only images that\ndon't have an custom name set by the `image` field")
|
||||
vol := cmd.Bool([]string{"v", "-volumes"}, false, "Remove data volumes")
|
||||
rmorphans := cmd.Bool([]string{"-remove-orphans"}, false, "Remove containers for services not defined in the Compose file")
|
||||
|
||||
cmd.Require(flag.Exact, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imageType := options.ImageType(*rmi)
|
||||
if !imageType.Valid() {
|
||||
return fmt.Errorf("rmi with %s is not valid", *rmi)
|
||||
}
|
||||
if *projectName == "" {
|
||||
*projectName = getBaseDir()
|
||||
}
|
||||
body, err := cli.client.ComposeDown(*projectName, cmd.Args(), *rmi, *vol, *rmorphans)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer body.Close()
|
||||
return jsonmessage.DisplayJSONMessagesStream(body, cli.out, cli.outFd, cli.isTerminalOut, nil)
|
||||
}
|
||||
|
||||
// CmdComposeUp
|
||||
//
|
||||
// Usage: hyper compose up [OPTIONS]
|
||||
func (cli *DockerCli) CmdComposeUp(args ...string) error {
|
||||
cmd := Cli.Subcmd("compose up", []string{"[SERVICE...]"}, "Builds, (re)creates, starts, and attaches to containers for a service.\n\nUnless they are already running, this command also starts any linked services.\n\n"+
|
||||
"The `hyper compose up` command aggregates the output of each container. When\n"+
|
||||
"the command exits, all containers are stopped. Running `hyper compose up -d`\n"+
|
||||
"starts the containers in the background and leaves them running.\n\n"+
|
||||
"If there are existing containers for a service, and the service's configuration\n"+
|
||||
"or image was changed after the container's creation, `hyper compose up` picks\n"+
|
||||
"up the changes by stopping and recreating the containers (preserving mounted\n"+
|
||||
"volumes). To prevent Compose from picking up changes, use the `--no-recreate`\n"+
|
||||
"flag.\n\n"+
|
||||
"If you want to force Compose to stop and recreate all containers, use the\n"+
|
||||
"`--force-recreate` flag.", false)
|
||||
composeFile := cmd.String([]string{"f", "-file"}, "docker-compose.yml", "Specify an alternate compose file")
|
||||
projectName := cmd.String([]string{"p", "-project-name"}, "", "Specify an alternate project name")
|
||||
detach := cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: Run containers in the background,\nprint new container names.\nIncompatible with --abort-on-container-exit.")
|
||||
forcerecreate := cmd.Bool([]string{"-force-recreate"}, false, "Recreate containers even if their configuration\nand image haven't changed.\nIncompatible with --no-recreate.")
|
||||
norecreate := cmd.Bool([]string{"-no-recreate"}, false, "If containers already exist, don't recreate them.\nIncompatible with --force-recreate.")
|
||||
|
||||
cmd.Require(flag.Min, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
project, err := docker.NewProject(&docker.Context{
|
||||
Context: project.Context{
|
||||
ComposeFiles: []string{*composeFile},
|
||||
ProjectName: *projectName,
|
||||
LoggerFactory: logger.NewColorLoggerFactory(),
|
||||
},
|
||||
ClientFactory: cli,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
services := cmd.Args()
|
||||
c, vc, nc := project.GetConfig()
|
||||
if *projectName == "" {
|
||||
*projectName = getBaseDir()
|
||||
}
|
||||
var fips = []string{}
|
||||
var newFipNum = 0
|
||||
for _, svconfig := range c.M {
|
||||
if svconfig.Fip == ComposeFipAuto {
|
||||
newFipNum++
|
||||
}
|
||||
}
|
||||
fipFilterArgs, _ := filters.FromParam("dangling=true")
|
||||
options := types.NetworkListOptions{
|
||||
Filters: fipFilterArgs,
|
||||
}
|
||||
fipList, err := cli.client.FipList(context.Background(), options)
|
||||
if err == nil {
|
||||
for _, fip := range fipList {
|
||||
if fip["container"] == "" && fip["service"] == "" {
|
||||
fips = append(fips, fip["fip"])
|
||||
}
|
||||
}
|
||||
}
|
||||
if newFipNum > len(fips) {
|
||||
if askForConfirmation(warnMessage) == true {
|
||||
newFips, err := cli.client.FipAllocate(context.Background(), fmt.Sprintf("%d", newFipNum-len(fips)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fips = append(fips, newFips...)
|
||||
}
|
||||
}
|
||||
i := 0
|
||||
for _, svconfig := range c.M {
|
||||
if svconfig.Fip == ComposeFipAuto {
|
||||
if i >= newFipNum {
|
||||
svconfig.Fip = ""
|
||||
} else {
|
||||
svconfig.Fip = fips[i]
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
body, err := cli.client.ComposeUp(*projectName, services, c, vc, nc, cli.configFile.AuthConfigs, *forcerecreate, *norecreate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer body.Close()
|
||||
err = jsonmessage.DisplayJSONMessagesStream(body, cli.out, cli.outFd, cli.isTerminalOut, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !*detach {
|
||||
signalChan := make(chan os.Signal, 1)
|
||||
cleanupDone := make(chan bool)
|
||||
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
errChan := make(chan error)
|
||||
go func() {
|
||||
errChan <- project.Log(true, services...)
|
||||
}()
|
||||
go func() {
|
||||
select {
|
||||
case <-signalChan:
|
||||
fmt.Printf("\nGracefully stopping...\n")
|
||||
project.Stop(0, services...)
|
||||
cleanupDone <- true
|
||||
case err := <-errChan:
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
cleanupDone <- true
|
||||
}
|
||||
}()
|
||||
<-cleanupDone
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdComposeStart
|
||||
//
|
||||
// Usage: hyper compose start [OPTIONS] [SERVICE]
|
||||
func (cli *DockerCli) CmdComposeStart(args ...string) error {
|
||||
cmd := Cli.Subcmd("compose start", []string{"[SERVICE...]"}, "Start existing containers.", false)
|
||||
projectName := cmd.String([]string{"p", "-project-name"}, "", "Specify an alternate project name")
|
||||
cmd.Require(flag.Min, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
services := cmd.Args()
|
||||
if *projectName == "" {
|
||||
*projectName = getBaseDir()
|
||||
}
|
||||
body, err := cli.client.ComposeStart(*projectName, services)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer body.Close()
|
||||
return jsonmessage.DisplayJSONMessagesStream(body, cli.out, cli.outFd, cli.isTerminalOut, nil)
|
||||
}
|
||||
|
||||
// CmdComposeStop
|
||||
//
|
||||
// Usage: hyper compose stop [OPTIONS]
|
||||
func (cli *DockerCli) CmdComposeStop(args ...string) error {
|
||||
cmd := Cli.Subcmd("compose stop", []string{"[SERVICE...]"}, "Stop running containers without removing them.\n\nThey can be started again with `hyper compose start`.", false)
|
||||
projectName := cmd.String([]string{"p", "-project-name"}, "", "Specify an alternate project name")
|
||||
nSeconds := cmd.Int([]string{"t", "-timeout"}, 10, "Specify a shutdown timeout in seconds.")
|
||||
cmd.Require(flag.Min, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
services := cmd.Args()
|
||||
if *projectName == "" {
|
||||
*projectName = getBaseDir()
|
||||
}
|
||||
body, err := cli.client.ComposeStop(*projectName, services, *nSeconds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer body.Close()
|
||||
return jsonmessage.DisplayJSONMessagesStream(body, cli.out, cli.outFd, cli.isTerminalOut, nil)
|
||||
}
|
||||
|
||||
// CmdComposeCreate
|
||||
//
|
||||
// Usage: hyper compose create [OPTIONS]
|
||||
func (cli *DockerCli) CmdComposeCreate(args ...string) error {
|
||||
cmd := Cli.Subcmd("compose create", []string{"[SERVICE...]"}, "Creates containers for a service.", false)
|
||||
composeFile := cmd.String([]string{"f", "-file"}, "docker-compose.yml", "Specify an alternate compose file")
|
||||
projectName := cmd.String([]string{"p", "-project-name"}, "", "Specify an alternate project name")
|
||||
forcerecreate := cmd.Bool([]string{"-force-recreate"}, false, "Recreate containers even if their configuration\nand image haven't changed.\nIncompatible with --no-recreate.")
|
||||
norecreate := cmd.Bool([]string{"-no-recreate"}, false, "If containers already exist, don't recreate them.\nIncompatible with --force-recreate.")
|
||||
cmd.Require(flag.Min, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
project, err := docker.NewProject(&docker.Context{
|
||||
Context: project.Context{
|
||||
ComposeFiles: []string{*composeFile},
|
||||
ProjectName: *projectName,
|
||||
LoggerFactory: logger.NewColorLoggerFactory(),
|
||||
},
|
||||
ClientFactory: cli,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
services := cmd.Args()
|
||||
c, vc, nc := project.GetConfig()
|
||||
if *projectName == "" {
|
||||
*projectName = getBaseDir()
|
||||
}
|
||||
body, err := cli.client.ComposeCreate(*projectName, services, c, vc, nc, cli.configFile.AuthConfigs, *forcerecreate, *norecreate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer body.Close()
|
||||
|
||||
return jsonmessage.DisplayJSONMessagesStream(body, cli.out, cli.outFd, cli.isTerminalOut, nil)
|
||||
}
|
||||
|
||||
// CmdComposePs
|
||||
//
|
||||
// Usage: hyper compose ps [OPTIONS]
|
||||
func (cli *DockerCli) CmdComposePs(args ...string) error {
|
||||
cmd := Cli.Subcmd("compose ps", []string{"[SERVICE...]"}, "List containers.", false)
|
||||
composeFile := cmd.String([]string{"f", "-file"}, "docker-compose.yml", "Specify an alternate compose file")
|
||||
projectName := cmd.String([]string{"p", "-project-name"}, "", "Specify an alternate project name")
|
||||
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display IDs")
|
||||
cmd.Require(flag.Min, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *projectName == "" {
|
||||
*projectName = getBaseDir()
|
||||
}
|
||||
project, err := docker.NewProject(&docker.Context{
|
||||
Context: project.Context{
|
||||
ComposeFiles: []string{*composeFile},
|
||||
ProjectName: *projectName,
|
||||
},
|
||||
ClientFactory: cli,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ps, err := project.Ps(*quiet, cmd.Args()...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf(ps.String(true))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdComposeKill
|
||||
//
|
||||
// Usage: hyper compose kill [OPTIONS]
|
||||
func (cli *DockerCli) CmdComposeKill(args ...string) error {
|
||||
cmd := Cli.Subcmd("compose kill", []string{"[SERVICE...]"}, "Force stop service containers.", false)
|
||||
projectName := cmd.String([]string{"p", "-project-name"}, "", "Specify an alternate project name")
|
||||
signal := cmd.String([]string{}, "KILL", "Signal to send to the container")
|
||||
cmd.Require(flag.Min, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
services := cmd.Args()
|
||||
if *projectName == "" {
|
||||
*projectName = getBaseDir()
|
||||
}
|
||||
body, err := cli.client.ComposeKill(*projectName, services, *signal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer body.Close()
|
||||
return jsonmessage.DisplayJSONMessagesStream(body, cli.out, cli.outFd, cli.isTerminalOut, nil)
|
||||
}
|
||||
|
||||
// CmdComposeRm
|
||||
//
|
||||
// Usage: hyper compose rm [OPTIONS] [SERVICE]
|
||||
func (cli *DockerCli) CmdComposeRm(args ...string) error {
|
||||
cmd := Cli.Subcmd("compose rm", []string{"[SERVICE...]"}, "Remove stopped service containers.", false)
|
||||
projectName := cmd.String([]string{"p", "-project-name"}, "", "Specify an alternate project name")
|
||||
removeVol := cmd.Bool([]string{"v"}, false, "Remove volumes associated with containers")
|
||||
cmd.Require(flag.Min, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
services := cmd.Args()
|
||||
if *projectName == "" {
|
||||
*projectName = getBaseDir()
|
||||
}
|
||||
body, err := cli.client.ComposeRm(*projectName, services, *removeVol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer body.Close()
|
||||
return jsonmessage.DisplayJSONMessagesStream(body, cli.out, cli.outFd, cli.isTerminalOut, nil)
|
||||
}
|
||||
|
||||
// CmdComposeScale
|
||||
//
|
||||
// Usage: hyper compose scale [OPTIONS] [SERVICE=NUM...]
|
||||
func (cli *DockerCli) CmdComposeScale(args ...string) error {
|
||||
cmd := Cli.Subcmd("compose scale", []string{"[SERVICE=NUM...]"}, "Set number of containers to run for a service.", false)
|
||||
composeFile := cmd.String([]string{"f", "-file"}, "docker-compose.yml", "Specify an alternate compose file")
|
||||
projectName := cmd.String([]string{"p", "-project-name"}, "", "Specify an alternate project name")
|
||||
timeout := cmd.Int([]string{"t", "-timeout"}, 10, "Specify a shutdown timeout in seconds")
|
||||
cmd.Require(flag.Min, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *projectName == "" {
|
||||
*projectName = getBaseDir()
|
||||
}
|
||||
project, err := docker.NewProject(&docker.Context{
|
||||
Context: project.Context{
|
||||
ComposeFiles: []string{*composeFile},
|
||||
ProjectName: *projectName,
|
||||
},
|
||||
ClientFactory: cli,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
servicesScale := map[string]int{}
|
||||
for _, ss := range cmd.Args() {
|
||||
fields := strings.SplitN(ss, "=", 2)
|
||||
if len(fields) != 2 {
|
||||
continue
|
||||
}
|
||||
num, err := strconv.Atoi(fields[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
servicesScale[fields[0]] = num
|
||||
}
|
||||
err = project.Scale(*timeout, servicesScale)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdComposePull
|
||||
//
|
||||
// Usage: hyper compose pull [OPTIONS]
|
||||
func (cli *DockerCli) CmdComposePull(args ...string) error {
|
||||
cmd := Cli.Subcmd("compose pull", []string{"[SERVICE...]"}, "Pull images of services.", false)
|
||||
composeFile := cmd.String([]string{"f", "-file"}, "docker-compose.yml", "Specify an alternate compose file")
|
||||
cmd.Require(flag.Min, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
project, err := docker.NewProject(&docker.Context{
|
||||
Context: project.Context{
|
||||
ComposeFiles: []string{*composeFile},
|
||||
},
|
||||
ClientFactory: cli,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = project.Pull(cmd.Args()...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func composeUsage() string {
|
||||
composeCommands := [][]string{
|
||||
{"create", "Creates containers for a service"},
|
||||
{"down", "Stop and remove containers, images, and volumes"},
|
||||
{"kill", "Force stop service containers"},
|
||||
{"ps", "List containers"},
|
||||
{"pull", "Pull images of services"},
|
||||
{"rm", "Remove stopped service containers"},
|
||||
{"run", "Run a one-off command"},
|
||||
{"scale", "Set number of containers for a service"},
|
||||
{"start", "Start services"},
|
||||
{"stop", "Stop services"},
|
||||
{"up", "Create and start containers"},
|
||||
}
|
||||
|
||||
help := "Commands:\n"
|
||||
|
||||
for _, cmd := range composeCommands {
|
||||
help += fmt.Sprintf(" %-25.25s%s\n", cmd[0], cmd[1])
|
||||
}
|
||||
|
||||
help += fmt.Sprintf("\nRun 'hyper compose COMMAND --help' for more information on a command.")
|
||||
return help
|
||||
}
|
||||
|
||||
func (cli *DockerCli) Create(s project.Service) client.APIClient {
|
||||
return cli.client
|
||||
}
|
||||
|
||||
func getBaseDir() string {
|
||||
file, err := os.Getwd()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return filepath.Base(file)
|
||||
}
|
||||
123
vendor/github.com/hyperhq/hypercli/api/client/config.go
generated
vendored
123
vendor/github.com/hyperhq/hypercli/api/client/config.go
generated
vendored
@@ -1,123 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/cliconfig"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdConfig
|
||||
//
|
||||
// Usage: hyper config
|
||||
func (cli *DockerCli) CmdConfig(args ...string) error {
|
||||
cmd := Cli.Subcmd("config", []string{"[REGION]"}, Cli.DockerCommands["config"].Description+".\nIf no region is specified, the default is defined as "+cliconfig.DefaultHyperRegion, true)
|
||||
cmd.Require(flag.Max, 1)
|
||||
|
||||
flAccesskey := cmd.String([]string{"-accesskey"}, "", "Access Key")
|
||||
flSecretkey := cmd.String([]string{"-secretkey"}, "", "Secret Key")
|
||||
flDefaultRegion := cmd.String([]string{"-default-region"}, "", "Default Region Endpoint")
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
// On Windows, force the use of the regular OS stdin stream. Fixes #14336/#14210
|
||||
if runtime.GOOS == "windows" {
|
||||
cli.in = os.Stdin
|
||||
}
|
||||
|
||||
var serverAddress string
|
||||
if len(cmd.Args()) > 0 {
|
||||
serverAddress = cmd.Arg(0)
|
||||
} else {
|
||||
serverAddress = cliconfig.DefaultHyperFormat
|
||||
}
|
||||
|
||||
_, err := cli.configureCloud(serverAddress, *flDefaultRegion, *flAccesskey, *flSecretkey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cli.configFile.Save(); err != nil {
|
||||
return fmt.Errorf("Error saving config file: %v", err)
|
||||
}
|
||||
fmt.Fprintf(cli.out, "WARNING: Your login credentials has been saved in %s\n", cli.configFile.Filename())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) configureCloud(serverAddress, flRegion, flAccesskey, flSecretkey string) (cliconfig.CloudConfig, error) {
|
||||
cloudConfig := cliconfig.CloudConfig{}
|
||||
if serverAddress != "" {
|
||||
if cc, ok := cli.configFile.CloudConfig[serverAddress]; ok {
|
||||
cloudConfig = cc
|
||||
} else {
|
||||
// for legacy format
|
||||
defaultHost := "tcp://" + cliconfig.DefaultHyperRegion + "." + cliconfig.DefaultHyperEndpoint
|
||||
cloudConfig, ok = cli.configFile.CloudConfig[defaultHost]
|
||||
if ok {
|
||||
delete(cli.configFile.CloudConfig, defaultHost)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defaultRegion := cli.getDefaultRegion()
|
||||
if cloudConfig.Region != "" {
|
||||
defaultRegion = cloudConfig.Region
|
||||
}
|
||||
if flAccesskey = strings.TrimSpace(flAccesskey); flAccesskey == "" {
|
||||
cli.promptWithDefault("Enter Access Key", cloudConfig.AccessKey)
|
||||
flAccesskey = readInput(cli.in, cli.out)
|
||||
flAccesskey = strings.TrimSpace(flAccesskey)
|
||||
if flAccesskey == "" {
|
||||
flAccesskey = cloudConfig.AccessKey
|
||||
}
|
||||
}
|
||||
if flSecretkey = strings.TrimSpace(flSecretkey); flSecretkey == "" {
|
||||
cli.promptWithDefault("Enter Secret Key", cloudConfig.SecretKey)
|
||||
flSecretkey = readInput(cli.in, cli.out)
|
||||
flSecretkey = strings.TrimSpace(flSecretkey)
|
||||
if flSecretkey == "" {
|
||||
flSecretkey = cloudConfig.SecretKey
|
||||
}
|
||||
}
|
||||
if flRegion = strings.TrimSpace(flRegion); flRegion == "" {
|
||||
cli.promptWithDefault("Enter Default Region", defaultRegion)
|
||||
flRegion = readInput(cli.in, cli.out)
|
||||
flRegion = strings.TrimSpace(flRegion)
|
||||
if flRegion == "" {
|
||||
flRegion = defaultRegion
|
||||
}
|
||||
}
|
||||
|
||||
cloudConfig.AccessKey = flAccesskey
|
||||
cloudConfig.SecretKey = flSecretkey
|
||||
cloudConfig.Region = flRegion
|
||||
if serverAddress != "" {
|
||||
cli.configFile.CloudConfig[serverAddress] = cloudConfig
|
||||
}
|
||||
|
||||
return cloudConfig, nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) checkCloudConfig() error {
|
||||
_, ok := cli.configFile.CloudConfig[cli.host]
|
||||
if !ok {
|
||||
_, ok = cli.configFile.CloudConfig[cliconfig.DefaultHyperFormat]
|
||||
if !ok {
|
||||
return fmt.Errorf("Config info for the host is not found, please run 'hyper config %s' first.", cli.host)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) getDefaultRegion() string {
|
||||
cc, ok := cli.configFile.CloudConfig[cliconfig.DefaultHyperFormat]
|
||||
if ok && cc.Region != "" {
|
||||
return cc.Region
|
||||
}
|
||||
return cliconfig.DefaultHyperRegion
|
||||
}
|
||||
297
vendor/github.com/hyperhq/hypercli/api/client/cp.go
generated
vendored
297
vendor/github.com/hyperhq/hypercli/api/client/cp.go
generated
vendored
@@ -1,297 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/pkg/archive"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/pkg/system"
|
||||
)
|
||||
|
||||
type copyDirection int
|
||||
|
||||
const (
|
||||
fromContainer copyDirection = (1 << iota)
|
||||
toContainer
|
||||
acrossContainers = fromContainer | toContainer
|
||||
)
|
||||
|
||||
type cpConfig struct {
|
||||
followLink bool
|
||||
}
|
||||
|
||||
// CmdCp copies files/folders to or from a path in a container.
|
||||
//
|
||||
// When copying from a container, if DEST_PATH is '-' the data is written as a
|
||||
// tar archive file to STDOUT.
|
||||
//
|
||||
// When copying to a container, if SRC_PATH is '-' the data is read as a tar
|
||||
// archive file from STDIN, and the destination CONTAINER:DEST_PATH, must specify
|
||||
// a directory.
|
||||
//
|
||||
// Usage:
|
||||
// docker cp CONTAINER:SRC_PATH DEST_PATH|-
|
||||
// docker cp SRC_PATH|- CONTAINER:DEST_PATH
|
||||
func (cli *DockerCli) Cp(args ...string) error {
|
||||
cmd := Cli.Subcmd(
|
||||
"cp",
|
||||
[]string{"CONTAINER:SRC_PATH DEST_PATH|-", "SRC_PATH|- CONTAINER:DEST_PATH"},
|
||||
strings.Join([]string{
|
||||
Cli.DockerCommands["cp"].Description,
|
||||
"\nUse '-' as the source to read a tar archive from stdin\n",
|
||||
"and extract it to a directory destination in a container.\n",
|
||||
"Use '-' as the destination to stream a tar archive of a\n",
|
||||
"container source to stdout.",
|
||||
}, ""),
|
||||
true,
|
||||
)
|
||||
|
||||
followLink := cmd.Bool([]string{"L", "-follow-link"}, false, "Always follow symbol link in SRC_PATH")
|
||||
|
||||
cmd.Require(flag.Exact, 2)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
if cmd.Arg(0) == "" {
|
||||
return fmt.Errorf("source can not be empty")
|
||||
}
|
||||
if cmd.Arg(1) == "" {
|
||||
return fmt.Errorf("destination can not be empty")
|
||||
}
|
||||
|
||||
srcContainer, srcPath := splitCpArg(cmd.Arg(0))
|
||||
dstContainer, dstPath := splitCpArg(cmd.Arg(1))
|
||||
|
||||
var direction copyDirection
|
||||
if srcContainer != "" {
|
||||
direction |= fromContainer
|
||||
}
|
||||
if dstContainer != "" {
|
||||
direction |= toContainer
|
||||
}
|
||||
|
||||
cpParam := &cpConfig{
|
||||
followLink: *followLink,
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
switch direction {
|
||||
case fromContainer:
|
||||
return cli.copyFromContainer(ctx, srcContainer, srcPath, dstPath, cpParam)
|
||||
case toContainer:
|
||||
return cli.copyToContainer(ctx, srcPath, dstContainer, dstPath, cpParam)
|
||||
case acrossContainers:
|
||||
// Copying between containers isn't supported.
|
||||
return fmt.Errorf("copying between containers is not supported")
|
||||
default:
|
||||
// User didn't specify any container.
|
||||
return fmt.Errorf("must specify at least one container source")
|
||||
}
|
||||
}
|
||||
|
||||
// We use `:` as a delimiter between CONTAINER and PATH, but `:` could also be
|
||||
// in a valid LOCALPATH, like `file:name.txt`. We can resolve this ambiguity by
|
||||
// requiring a LOCALPATH with a `:` to be made explicit with a relative or
|
||||
// absolute path:
|
||||
// `/path/to/file:name.txt` or `./file:name.txt`
|
||||
//
|
||||
// This is apparently how `scp` handles this as well:
|
||||
// http://www.cyberciti.biz/faq/rsync-scp-file-name-with-colon-punctuation-in-it/
|
||||
//
|
||||
// We can't simply check for a filepath separator because container names may
|
||||
// have a separator, e.g., "host0/cname1" if container is in a Docker cluster,
|
||||
// so we have to check for a `/` or `.` prefix. Also, in the case of a Windows
|
||||
// client, a `:` could be part of an absolute Windows path, in which case it
|
||||
// is immediately proceeded by a backslash.
|
||||
func splitCpArg(arg string) (container, path string) {
|
||||
if system.IsAbs(arg) {
|
||||
// Explicit local absolute path, e.g., `C:\foo` or `/foo`.
|
||||
return "", arg
|
||||
}
|
||||
|
||||
parts := strings.SplitN(arg, ":", 2)
|
||||
|
||||
if len(parts) == 1 || strings.HasPrefix(parts[0], ".") {
|
||||
// Either there's no `:` in the arg
|
||||
// OR it's an explicit local relative path like `./file:name.txt`.
|
||||
return "", arg
|
||||
}
|
||||
|
||||
return parts[0], parts[1]
|
||||
}
|
||||
|
||||
func (cli *DockerCli) statContainerPath(ctx context.Context, containerName, path string) (types.ContainerPathStat, error) {
|
||||
return cli.client.ContainerStatPath(ctx, containerName, path)
|
||||
}
|
||||
|
||||
func resolveLocalPath(localPath string) (absPath string, err error) {
|
||||
if absPath, err = filepath.Abs(localPath); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return archive.PreserveTrailingDotOrSeparator(absPath, localPath), nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) copyFromContainer(ctx context.Context, srcContainer, srcPath, dstPath string, cpParam *cpConfig) (err error) {
|
||||
if dstPath != "-" {
|
||||
// Get an absolute destination path.
|
||||
dstPath, err = resolveLocalPath(dstPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// if client requests to follow symbol link, then must decide target file to be copied
|
||||
var rebaseName string
|
||||
if cpParam.followLink {
|
||||
srcStat, err := cli.statContainerPath(ctx, srcContainer, srcPath)
|
||||
|
||||
// If the destination is a symbolic link, we should follow it.
|
||||
if err == nil && srcStat.Mode&os.ModeSymlink != 0 {
|
||||
linkTarget := srcStat.LinkTarget
|
||||
if !system.IsAbs(linkTarget) {
|
||||
// Join with the parent directory.
|
||||
srcParent, _ := archive.SplitPathDirEntry(srcPath)
|
||||
linkTarget = filepath.Join(srcParent, linkTarget)
|
||||
}
|
||||
|
||||
linkTarget, rebaseName = archive.GetRebaseName(srcPath, linkTarget)
|
||||
srcPath = linkTarget
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
content, stat, err := cli.client.CopyFromContainer(ctx, srcContainer, srcPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer content.Close()
|
||||
|
||||
if dstPath == "-" {
|
||||
// Send the response to STDOUT.
|
||||
_, err = io.Copy(os.Stdout, content)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Prepare source copy info.
|
||||
srcInfo := archive.CopyInfo{
|
||||
Path: srcPath,
|
||||
Exists: true,
|
||||
IsDir: stat.Mode.IsDir(),
|
||||
RebaseName: rebaseName,
|
||||
}
|
||||
|
||||
preArchive := content
|
||||
if len(srcInfo.RebaseName) != 0 {
|
||||
_, srcBase := archive.SplitPathDirEntry(srcInfo.Path)
|
||||
preArchive = archive.RebaseArchiveEntries(content, srcBase, srcInfo.RebaseName)
|
||||
}
|
||||
// See comments in the implementation of `archive.CopyTo` for exactly what
|
||||
// goes into deciding how and whether the source archive needs to be
|
||||
// altered for the correct copy behavior.
|
||||
return archive.CopyTo(preArchive, srcInfo, dstPath)
|
||||
}
|
||||
|
||||
func (cli *DockerCli) copyToContainer(ctx context.Context, srcPath, dstContainer, dstPath string, cpParam *cpConfig) (err error) {
|
||||
if srcPath != "-" {
|
||||
// Get an absolute source path.
|
||||
srcPath, err = resolveLocalPath(srcPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// In order to get the copy behavior right, we need to know information
|
||||
// about both the source and destination. The API is a simple tar
|
||||
// archive/extract API but we can use the stat info header about the
|
||||
// destination to be more informed about exactly what the destination is.
|
||||
|
||||
// Prepare destination copy info by stat-ing the container path.
|
||||
dstInfo := archive.CopyInfo{Path: dstPath}
|
||||
dstStat, err := cli.statContainerPath(ctx, dstContainer, dstPath)
|
||||
|
||||
// If the destination is a symbolic link, we should evaluate it.
|
||||
if err == nil && dstStat.Mode&os.ModeSymlink != 0 {
|
||||
linkTarget := dstStat.LinkTarget
|
||||
if !system.IsAbs(linkTarget) {
|
||||
// Join with the parent directory.
|
||||
dstParent, _ := archive.SplitPathDirEntry(dstPath)
|
||||
linkTarget = filepath.Join(dstParent, linkTarget)
|
||||
}
|
||||
|
||||
dstInfo.Path = linkTarget
|
||||
dstStat, err = cli.statContainerPath(ctx, dstContainer, linkTarget)
|
||||
}
|
||||
|
||||
// Ignore any error and assume that the parent directory of the destination
|
||||
// path exists, in which case the copy may still succeed. If there is any
|
||||
// type of conflict (e.g., non-directory overwriting an existing directory
|
||||
// or vice versa) the extraction will fail. If the destination simply did
|
||||
// not exist, but the parent directory does, the extraction will still
|
||||
// succeed.
|
||||
if err == nil {
|
||||
dstInfo.Exists, dstInfo.IsDir = true, dstStat.Mode.IsDir()
|
||||
}
|
||||
|
||||
var (
|
||||
content io.Reader
|
||||
resolvedDstPath string
|
||||
)
|
||||
|
||||
if srcPath == "-" {
|
||||
// Use STDIN.
|
||||
content = os.Stdin
|
||||
resolvedDstPath = dstInfo.Path
|
||||
if !dstInfo.IsDir {
|
||||
return fmt.Errorf("destination %q must be a directory", fmt.Sprintf("%s:%s", dstContainer, dstPath))
|
||||
}
|
||||
} else {
|
||||
// Prepare source copy info.
|
||||
srcInfo, err := archive.CopyInfoSourcePath(srcPath, cpParam.followLink)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
srcArchive, err := archive.TarResource(srcInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcArchive.Close()
|
||||
|
||||
// With the stat info about the local source as well as the
|
||||
// destination, we have enough information to know whether we need to
|
||||
// alter the archive that we upload so that when the server extracts
|
||||
// it to the specified directory in the container we get the desired
|
||||
// copy behavior.
|
||||
|
||||
// See comments in the implementation of `archive.PrepareArchiveCopy`
|
||||
// for exactly what goes into deciding how and whether the source
|
||||
// archive needs to be altered for the correct copy behavior when it is
|
||||
// extracted. This function also infers from the source and destination
|
||||
// info which directory to extract to, which may be the parent of the
|
||||
// destination that the user specified.
|
||||
dstDir, preparedArchive, err := archive.PrepareArchiveCopy(srcArchive, srcInfo, dstInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer preparedArchive.Close()
|
||||
|
||||
resolvedDstPath = dstDir
|
||||
content = preparedArchive
|
||||
}
|
||||
|
||||
options := types.CopyToContainerOptions{
|
||||
AllowOverwriteDirWithFile: false,
|
||||
}
|
||||
|
||||
return cli.client.CopyToContainer(ctx, dstContainer, resolvedDstPath, content, options)
|
||||
}
|
||||
233
vendor/github.com/hyperhq/hypercli/api/client/create.go
generated
vendored
233
vendor/github.com/hyperhq/hypercli/api/client/create.go
generated
vendored
@@ -1,233 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/hyperhq/hyper-api/client"
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hyper-api/types/container"
|
||||
networktypes "github.com/hyperhq/hyper-api/types/network"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/pkg/jsonmessage"
|
||||
"github.com/hyperhq/hypercli/reference"
|
||||
"github.com/hyperhq/hypercli/registry"
|
||||
runconfigopts "github.com/hyperhq/hypercli/runconfig/opts"
|
||||
)
|
||||
|
||||
func (cli *DockerCli) pullImage(ctx context.Context, image string) error {
|
||||
return cli.pullImageCustomOut(ctx, image, cli.out)
|
||||
}
|
||||
|
||||
func (cli *DockerCli) pullImageCustomOut(ctx context.Context, image string, out io.Writer) error {
|
||||
ref, err := reference.ParseNamed(image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Resolve the Repository name from fqn to RepositoryInfo
|
||||
repoInfo, err := registry.ParseRepositoryInfo(ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authConfig := cli.resolveAuthConfig(ctx, cli.configFile.AuthConfigs, repoInfo.Index)
|
||||
encodedAuth, err := encodeAuthToBase64(authConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
options := types.ImageCreateOptions{
|
||||
RegistryAuth: encodedAuth,
|
||||
}
|
||||
|
||||
responseBody, err := cli.client.ImageCreate(ctx, image, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer responseBody.Close()
|
||||
|
||||
return jsonmessage.DisplayJSONMessagesStream(responseBody, out, cli.outFd, cli.isTerminalOut, nil)
|
||||
}
|
||||
|
||||
type cidFile struct {
|
||||
path string
|
||||
file *os.File
|
||||
written bool
|
||||
}
|
||||
|
||||
func newCIDFile(path string) (*cidFile, error) {
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
return nil, fmt.Errorf("Container ID file found, make sure the other container isn't running or delete %s", path)
|
||||
}
|
||||
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to create the container ID file: %s", err)
|
||||
}
|
||||
|
||||
return &cidFile{path: path, file: f}, nil
|
||||
}
|
||||
|
||||
func parseProtoAndLocalBind(bind string) (string, string, bool) {
|
||||
switch {
|
||||
case strings.HasPrefix(bind, "git://"):
|
||||
fallthrough
|
||||
case strings.HasPrefix(bind, "http://"):
|
||||
fallthrough
|
||||
case strings.HasPrefix(bind, "https://"):
|
||||
if strings.Count(bind, ":") < 2 {
|
||||
return "", "", false
|
||||
}
|
||||
case strings.HasPrefix(bind, "/"):
|
||||
if strings.Count(bind, ":") < 1 {
|
||||
return "", "", false
|
||||
}
|
||||
case filepath.VolumeName(bind) != "":
|
||||
// Windows local path
|
||||
default:
|
||||
return "", "", false
|
||||
}
|
||||
|
||||
pos := strings.LastIndex(bind, ":")
|
||||
if pos < 0 || pos >= len(bind)-1 {
|
||||
return "", "", false
|
||||
}
|
||||
|
||||
return bind[:pos], bind[pos+1:], true
|
||||
}
|
||||
|
||||
func (cli *DockerCli) createContainer(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *networktypes.NetworkingConfig, cidfile, name string) (*types.ContainerCreateResponse, error) {
|
||||
var containerIDFile *cidFile
|
||||
var initvols, volumeList []string
|
||||
|
||||
if cidfile != "" {
|
||||
var err error
|
||||
if containerIDFile, err = newCIDFile(cidfile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer containerIDFile.Close()
|
||||
}
|
||||
|
||||
// Check/create protocol and local volume
|
||||
defer func() {
|
||||
for _, vol := range volumeList {
|
||||
cli.client.VolumeRemove(ctx, vol)
|
||||
}
|
||||
}()
|
||||
for idx, bind := range hostConfig.Binds {
|
||||
if source, dest, ok := parseProtoAndLocalBind(bind); ok {
|
||||
volReq := types.VolumeCreateRequest{
|
||||
Driver: "hyper",
|
||||
Labels: map[string]string{
|
||||
"autoremove": "true",
|
||||
}}
|
||||
if vol, err := cli.client.VolumeCreate(ctx, volReq); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
initvols = append(initvols, source+":"+vol.Name)
|
||||
volumeList = append(volumeList, vol.Name)
|
||||
hostConfig.Binds[idx] = vol.Name + ":" + dest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// initialize special volumes
|
||||
if len(initvols) > 0 {
|
||||
err := cli.initVolumes(initvols, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
ref, err := reference.ParseNamed(config.Image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ref = reference.WithDefaultTag(ref)
|
||||
|
||||
var trustedRef reference.Canonical
|
||||
|
||||
if ref, ok := ref.(reference.NamedTagged); ok && isTrusted() {
|
||||
var err error
|
||||
trustedRef, err = cli.trustedReference(ctx, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.Image = trustedRef.String()
|
||||
}
|
||||
|
||||
//create the container
|
||||
response, err := cli.client.ContainerCreate(ctx, config, hostConfig, networkingConfig, name)
|
||||
|
||||
//if image not found try to pull it
|
||||
if err != nil {
|
||||
if client.IsErrImageNotFound(err) {
|
||||
fmt.Fprintf(cli.err, "Unable to find image '%s' in the current region\n", ref.String())
|
||||
|
||||
// we don't want to write to stdout anything apart from container.ID
|
||||
if err = cli.pullImageCustomOut(ctx, config.Image, cli.err); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ref, ok := ref.(reference.NamedTagged); ok && trustedRef != nil {
|
||||
if err := cli.tagTrusted(ctx, trustedRef, ref); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Retry
|
||||
var retryErr error
|
||||
response, retryErr = cli.client.ContainerCreate(ctx, config, hostConfig, networkingConfig, name)
|
||||
if retryErr != nil {
|
||||
return nil, retryErr
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
volumeList = nil
|
||||
|
||||
for _, warning := range response.Warnings {
|
||||
fmt.Fprintf(cli.err, "WARNING: %s\n", warning)
|
||||
}
|
||||
if containerIDFile != nil {
|
||||
if err = containerIDFile.Write(response.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// CmdCreate creates a new container from a given image.
|
||||
//
|
||||
// Usage: docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
|
||||
func (cli *DockerCli) CmdCreate(args ...string) error {
|
||||
cmd := Cli.Subcmd("create", []string{"IMAGE [COMMAND] [ARG...]"}, Cli.DockerCommands["create"].Description, true)
|
||||
addTrustedFlags(cmd, true)
|
||||
|
||||
// These are flags not stored in Config/HostConfig
|
||||
var (
|
||||
flName = cmd.String([]string{"-name"}, "", "Assign a name to the container")
|
||||
)
|
||||
|
||||
config, hostConfig, networkingConfig, cmd, err := runconfigopts.Parse(cmd, args)
|
||||
|
||||
if err != nil {
|
||||
cmd.ReportError(err.Error(), true)
|
||||
os.Exit(1)
|
||||
}
|
||||
if config.Image == "" {
|
||||
cmd.Usage()
|
||||
return nil
|
||||
}
|
||||
response, err := cli.createContainer(context.Background(), config, hostConfig, networkingConfig, hostConfig.ContainerIDFile, *flName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cli.out, "%s\n", response.ID)
|
||||
return nil
|
||||
}
|
||||
398
vendor/github.com/hyperhq/hypercli/api/client/cron.go
generated
vendored
398
vendor/github.com/hyperhq/hypercli/api/client/cron.go
generated
vendored
@@ -1,398 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hyper-api/types/container"
|
||||
"github.com/hyperhq/hyper-api/types/filters"
|
||||
"github.com/hyperhq/hyper-api/types/network"
|
||||
"github.com/hyperhq/hyper-api/types/strslice"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
ropts "github.com/hyperhq/hypercli/opts"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/pkg/signal"
|
||||
"github.com/hyperhq/hypercli/runconfig/opts"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// CmdCron is the parent subcommand for all cron commands
|
||||
//
|
||||
// Usage: hyper cron <COMMAND> [OPTIONS]
|
||||
func (cli *DockerCli) CmdCron(args ...string) error {
|
||||
cmd := Cli.Subcmd("cron", []string{"COMMAND [OPTIONS]"}, cronUsage(), false)
|
||||
cmd.Require(flag.Min, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
// CmdCronCreate creates a new cron with a given name
|
||||
//
|
||||
// Usage: hyper cron create [OPTIONS]
|
||||
func (cli *DockerCli) CmdCronCreate(args ...string) error {
|
||||
cmd := Cli.Subcmd("cron create", []string{"IMAGE"}, "Create a cron job", false)
|
||||
var (
|
||||
flSecurityGroups = ropts.NewListOpts(nil)
|
||||
flEnv = ropts.NewListOpts(opts.ValidateEnv)
|
||||
flLabels = ropts.NewListOpts(opts.ValidateEnv)
|
||||
flEnvFile = ropts.NewListOpts(nil)
|
||||
flVolumes = ropts.NewListOpts(nil)
|
||||
flLinks = ropts.NewListOpts(opts.ValidateLink)
|
||||
flLabelsFile = ropts.NewListOpts(nil)
|
||||
flPublish = ropts.NewListOpts(nil)
|
||||
flExpose = ropts.NewListOpts(nil)
|
||||
|
||||
flName = cmd.String([]string{"-name"}, "", "Cron name")
|
||||
flContainerName = cmd.String([]string{"-container-name"}, "", "Cron container name")
|
||||
flEntrypoint = cmd.String([]string{"-entrypoint"}, "", "Overwrite the default ENTRYPOINT of the image")
|
||||
flNetMode = cmd.String([]string{}, "bridge", "Connect containers to a network, only bridge is supported now")
|
||||
flStopSignal = cmd.String([]string{"-stop-signal"}, signal.DefaultStopSignal, fmt.Sprintf("Signal to stop a container, %v by default", signal.DefaultStopSignal))
|
||||
flContainerSize = cmd.String([]string{"-size"}, "s4", "The size of cron containers (e.g. s1, s2, s3, s4, m1, m2, m3, l1, l2, l3)")
|
||||
flWorkingDir = cmd.String([]string{"w", "-workdir"}, "", "Working directory inside the container")
|
||||
flHostname = cmd.String([]string{"h", "-hostname"}, "", "Container host name")
|
||||
flNoAutoVolume = cmd.Bool([]string{"-noauto-volume"}, false, "Do not create volumes specified in image")
|
||||
flPublishAll = cmd.Bool([]string{"P", "-publish-all"}, false, "Publish all exposed ports to random ports")
|
||||
flRestartPolicy = cmd.String([]string{"-restart"}, "no", "Restart policy to apply when a container exits")
|
||||
flMailTo = cmd.String([]string{"-mailto"}, "", "Mail to while the cron has something")
|
||||
flMailPolicy = cmd.String([]string{"-mail"}, "on-failure", "Mail policy to apply when to send email")
|
||||
flAccessKey = cmd.String([]string{"-access-key"}, "", "Access key to run the cron job")
|
||||
flSecretKey = cmd.String([]string{"-secret-key"}, "", "Secret key to run the cron job")
|
||||
|
||||
flMinute = cmd.String([]string{"-minute"}, "0", "The minutes of cron expression")
|
||||
flHour = cmd.String([]string{"-hour"}, "0", "The hour of cron expression")
|
||||
flDom = cmd.String([]string{"-dom"}, "*", "The day of month of cron expression")
|
||||
flDow = cmd.String([]string{"-week"}, "*", "The day of week of cron expression")
|
||||
flMonth = cmd.String([]string{"-month"}, "*", "The month of cron expression")
|
||||
)
|
||||
cmd.Var(&flLabels, []string{"l", "-label"}, "Set meta data on a container")
|
||||
cmd.Var(&flLabelsFile, []string{"-label-file"}, "Read in a line delimited file of labels")
|
||||
cmd.Var(&flEnv, []string{"e", "-env"}, "Set environment variables")
|
||||
cmd.Var(&flEnvFile, []string{"-env-file"}, "Read in a file of environment variables")
|
||||
cmd.Var(&flSecurityGroups, []string{"-sg"}, "Security group for each container")
|
||||
cmd.Var(&flVolumes, []string{"v", "--volume"}, "Volume for each container")
|
||||
cmd.Var(&flLinks, []string{"-link"}, "Add link to another container")
|
||||
cmd.Var(&flPublish, []string{"p", "-publish"}, "Publish a container's port(s) to the host")
|
||||
cmd.Var(&flExpose, []string{"-expose"}, "Expose a port or a range of ports")
|
||||
|
||||
cmd.Require(flag.Min, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if (*flAccessKey == "" && *flSecretKey != "") || (*flAccessKey != "" && *flSecretKey == "") {
|
||||
return fmt.Errorf("You must specify access key and secret key at the same time")
|
||||
}
|
||||
|
||||
var (
|
||||
parsedArgs = cmd.Args()
|
||||
runCmd strslice.StrSlice
|
||||
entrypoint strslice.StrSlice
|
||||
image = cmd.Arg(0)
|
||||
)
|
||||
if len(parsedArgs) > 1 {
|
||||
runCmd = strslice.StrSlice(parsedArgs[1:])
|
||||
}
|
||||
if *flEntrypoint != "" {
|
||||
entrypoint = strslice.StrSlice{*flEntrypoint}
|
||||
}
|
||||
|
||||
if _, _, err = cli.client.ImageInspectWithRaw(context.Background(), image, false); err != nil && strings.Contains(err.Error(), "No such image") {
|
||||
if err := cli.pullImage(context.Background(), image); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// collect all the environment variables for the container
|
||||
envVariables, err := opts.ReadKVStrings(flEnvFile.GetAll(), flEnv.GetAll())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// collect all the labels for the container
|
||||
labels, err := opts.ReadKVStrings(flLabelsFile.GetAll(), flLabels.GetAll())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
labels = append(labels, fmt.Sprintf("sh_hyper_instancetype=%s", *flContainerSize))
|
||||
for _, sg := range flSecurityGroups.GetAll() {
|
||||
if sg == "" {
|
||||
continue
|
||||
}
|
||||
labels = append(labels, fmt.Sprintf("sh_hyper_sg_%s=yes", sg))
|
||||
}
|
||||
if *flNoAutoVolume {
|
||||
labels = append(labels, "sh_hyper_noauto_volume=true")
|
||||
}
|
||||
|
||||
var (
|
||||
domainname string
|
||||
hostname = *flHostname
|
||||
parts = strings.SplitN(hostname, ".", 2)
|
||||
)
|
||||
if len(parts) > 1 {
|
||||
hostname = parts[0]
|
||||
domainname = parts[1]
|
||||
}
|
||||
ports, portBindings, err := nat.ParsePortSpecs(flPublish.GetAll())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Merge in exposed ports to the map of published ports
|
||||
for _, e := range flExpose.GetAll() {
|
||||
if strings.Contains(e, ":") {
|
||||
return fmt.Errorf("Invalid port format for --expose: %s", e)
|
||||
}
|
||||
//support two formats for expose, original format <portnum>/[<proto>] or <startport-endport>/[<proto>]
|
||||
proto, port := nat.SplitProtoPort(e)
|
||||
//parse the start and end port and create a sequence of ports to expose
|
||||
//if expose a port, the start and end port are the same
|
||||
start, end, err := nat.ParsePortRange(port)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Invalid range format for --expose: %s, error: %s", e, err)
|
||||
}
|
||||
for i := start; i <= end; i++ {
|
||||
p, err := nat.NewPort(proto, strconv.FormatUint(i, 10))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, exists := ports[p]; !exists {
|
||||
ports[p] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
var binds []string
|
||||
// add any bind targets to the list of container volumes
|
||||
for bind := range flVolumes.GetMap() {
|
||||
if arr := opts.VolumeSplitN(bind, 2); len(arr) > 1 {
|
||||
// after creating the bind mount we want to delete it from the flVolumes values because
|
||||
// we do not want bind mounts being committed to image configs
|
||||
binds = append(binds, bind)
|
||||
flVolumes.Delete(bind)
|
||||
}
|
||||
}
|
||||
restartPolicy, err := opts.ParseRestartPolicy(*flRestartPolicy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config := &container.Config{
|
||||
Hostname: hostname,
|
||||
Domainname: domainname,
|
||||
Tty: true,
|
||||
ExposedPorts: ports,
|
||||
Env: envVariables,
|
||||
Cmd: runCmd,
|
||||
Image: image,
|
||||
Volumes: flVolumes.GetMap(),
|
||||
Entrypoint: entrypoint,
|
||||
WorkingDir: *flWorkingDir,
|
||||
Labels: opts.ConvertKVStringsToMap(labels),
|
||||
StopSignal: *flStopSignal,
|
||||
}
|
||||
|
||||
hostConfig := &container.HostConfig{
|
||||
Binds: binds,
|
||||
PortBindings: portBindings,
|
||||
Links: flLinks.GetAll(),
|
||||
PublishAllPorts: *flPublishAll,
|
||||
NetworkMode: container.NetworkMode(*flNetMode),
|
||||
RestartPolicy: restartPolicy,
|
||||
}
|
||||
networkingConfig := &network.NetworkingConfig{
|
||||
EndpointsConfig: make(map[string]*network.EndpointSettings),
|
||||
}
|
||||
|
||||
if hostConfig.NetworkMode.IsUserDefined() && len(hostConfig.Links) > 0 {
|
||||
epConfig := networkingConfig.EndpointsConfig[string(hostConfig.NetworkMode)]
|
||||
if epConfig == nil {
|
||||
epConfig = &network.EndpointSettings{}
|
||||
}
|
||||
epConfig.Links = make([]string, len(hostConfig.Links))
|
||||
copy(epConfig.Links, hostConfig.Links)
|
||||
networkingConfig.EndpointsConfig[string(hostConfig.NetworkMode)] = epConfig
|
||||
}
|
||||
|
||||
if *flMinute == "0" && *flHour == "0" && *flDom == "*" && *flDow == "*" && *flMonth == "*" {
|
||||
return fmt.Errorf("must specify at least one schedule")
|
||||
}
|
||||
|
||||
sv := types.Cron{
|
||||
ContainerName: *flContainerName,
|
||||
Schedule: *flMinute + " " + *flHour + " " + *flDom + " " + *flMonth + " " + *flDow,
|
||||
OwnerEmail: *flMailTo,
|
||||
Config: config,
|
||||
HostConfig: hostConfig,
|
||||
NetConfig: networkingConfig,
|
||||
AccessKey: *flAccessKey,
|
||||
SecretKey: *flSecretKey,
|
||||
MailPolicy: *flMailPolicy,
|
||||
}
|
||||
|
||||
_, err = cli.client.CronCreate(context.Background(), *flName, sv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cli.out, "Cron %s is created.\n", *flName)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdCronDelete deletes one or more crons
|
||||
//
|
||||
// Usage: hyper cron rm cron [cron...]
|
||||
func (cli *DockerCli) CmdCronRm(args ...string) error {
|
||||
cmd := Cli.Subcmd("cron rm", []string{"cron [cron...]"}, "Remove one or more cron job", false)
|
||||
cmd.Require(flag.Min, 1)
|
||||
if err := cmd.ParseFlags(args, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
status := 0
|
||||
for _, sn := range cmd.Args() {
|
||||
if err := cli.client.CronDelete(context.Background(), sn); err != nil {
|
||||
fmt.Fprintf(cli.err, "%s\n", err)
|
||||
status = 1
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(cli.out, "%s\n", sn)
|
||||
}
|
||||
if status != 0 {
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdCronLs lists all the crons
|
||||
//
|
||||
// Usage: hyper cron ls [OPTIONS]
|
||||
func (cli *DockerCli) CmdCronLs(args ...string) error {
|
||||
cmd := Cli.Subcmd("cron ls", nil, "Lists all crons", true)
|
||||
|
||||
flFilter := ropts.NewListOpts(nil)
|
||||
cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided")
|
||||
|
||||
cmd.Require(flag.Exact, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Consolidate all filter flags, and sanity check them early.
|
||||
// They'll get process after get response from server.
|
||||
cronFilterArgs := filters.NewArgs()
|
||||
for _, f := range flFilter.GetAll() {
|
||||
if cronFilterArgs, err = filters.ParseFlag(f, cronFilterArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
options := types.CronListOptions{
|
||||
Filters: cronFilterArgs,
|
||||
}
|
||||
|
||||
crons, err := cli.client.CronList(context.Background(), options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
||||
fmt.Fprintf(w, "Name\tSchedule\tImage\tCommand\n")
|
||||
for _, cron := range crons {
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", cron.Name, cron.Schedule, cron.Config.Image, strings.Join([]string(cron.Config.Cmd), " "))
|
||||
}
|
||||
|
||||
w.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdCronInspect
|
||||
//
|
||||
// Usage: hyper cron inspect [OPTIONS] CRON [CRON...]
|
||||
func (cli *DockerCli) CmdCronInspect(args ...string) error {
|
||||
cmd := Cli.Subcmd("cron inspect", []string{"cron [cron...]"}, "Display detailed information on the given cron", true)
|
||||
tmplStr := cmd.String([]string{"f", "-format"}, "", "Format the output using the given go template")
|
||||
|
||||
cmd.Require(flag.Min, 1)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
inspectSearcher := func(name string) (interface{}, []byte, error) {
|
||||
i, err := cli.client.CronInspect(ctx, name)
|
||||
return i, nil, err
|
||||
}
|
||||
|
||||
return cli.inspectElements(*tmplStr, cmd.Args(), inspectSearcher)
|
||||
}
|
||||
|
||||
// CmdCronHistory
|
||||
//
|
||||
// Usage: hyper cron history [OPTIONS] CRON
|
||||
func (cli *DockerCli) CmdCronHistory(args ...string) error {
|
||||
cmd := Cli.Subcmd("cron history", []string{"cron"}, "Show the execution history (last 100) of a cron job", true)
|
||||
flSince := cmd.String([]string{"-since"}, "", "Show history since timestamp")
|
||||
flTail := cmd.String([]string{"-tail"}, "all", "Number of lines to show from the end of the history")
|
||||
|
||||
cmd.Require(flag.Min, 1)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
name := cmd.Args()[0]
|
||||
cronHistory, err := cli.client.CronHistory(ctx, name, *flSince, *flTail)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
||||
fmt.Fprintf(w, "Container\tStart\tEnd\tStatus\tMessage\n")
|
||||
for _, h := range cronHistory {
|
||||
status := h.Status
|
||||
if status == "success" {
|
||||
status = "done"
|
||||
} else if status == "error" {
|
||||
status = "failed"
|
||||
} else {
|
||||
status = "-"
|
||||
}
|
||||
if h.FinishedAt == 0 {
|
||||
fmt.Fprintf(w, "%s\t%v\t-\t%s\t%s\n", h.Container, time.Unix(h.StartedAt, 0).UTC(), status, h.Message)
|
||||
} else {
|
||||
fmt.Fprintf(w, "%s\t%v\t%v\t%s\t%s\n", h.Container, time.Unix(h.StartedAt, 0).UTC(), time.Unix(h.FinishedAt, 0).UTC(), status, h.Message)
|
||||
}
|
||||
}
|
||||
|
||||
w.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func cronUsage() string {
|
||||
cronCommands := [][]string{
|
||||
{"create", "Create a cron job"},
|
||||
{"inspect", "Display detailed information on the given cron"},
|
||||
{"ls", "List all crons"},
|
||||
{"history", "Show execution history of a cron job"},
|
||||
{"rm", "Remove one or more cron job"},
|
||||
}
|
||||
|
||||
help := "Commands:\n"
|
||||
|
||||
for _, cmd := range cronCommands {
|
||||
help += fmt.Sprintf(" %-25.25s%s\n", cmd[0], cmd[1])
|
||||
}
|
||||
|
||||
help += fmt.Sprintf("\nRun 'hyper cron COMMAND --help' for more information on a command.")
|
||||
return help
|
||||
}
|
||||
49
vendor/github.com/hyperhq/hypercli/api/client/diff.go
generated
vendored
49
vendor/github.com/hyperhq/hypercli/api/client/diff.go
generated
vendored
@@ -1,49 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/pkg/archive"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdDiff shows changes on a container's filesystem.
|
||||
//
|
||||
// Each changed file is printed on a separate line, prefixed with a single
|
||||
// character that indicates the status of the file: C (modified), A (added),
|
||||
// or D (deleted).
|
||||
//
|
||||
// Usage: docker diff CONTAINER
|
||||
func (cli *DockerCli) Diff(args ...string) error {
|
||||
cmd := Cli.Subcmd("diff", []string{"CONTAINER"}, Cli.DockerCommands["diff"].Description, true)
|
||||
cmd.Require(flag.Exact, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
if cmd.Arg(0) == "" {
|
||||
return fmt.Errorf("Container name cannot be empty")
|
||||
}
|
||||
|
||||
changes, err := cli.client.ContainerDiff(context.Background(), cmd.Arg(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, change := range changes {
|
||||
var kind string
|
||||
switch change.Kind {
|
||||
case archive.ChangeModify:
|
||||
kind = "C"
|
||||
case archive.ChangeAdd:
|
||||
kind = "A"
|
||||
case archive.ChangeDelete:
|
||||
kind = "D"
|
||||
}
|
||||
fmt.Fprintf(cli.out, "%s %s\n", kind, change.Path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
102
vendor/github.com/hyperhq/hypercli/api/client/events.go
generated
vendored
102
vendor/github.com/hyperhq/hypercli/api/client/events.go
generated
vendored
@@ -1,102 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/hyperhq/hyper-api/types/events"
|
||||
signutil "github.com/hyperhq/websocket-client/go/util"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Events returns a stream of events in the daemon. It's up to the caller to close the stream
|
||||
// by cancelling the context. Once the stream has been completely read an io.EOF error will
|
||||
// be sent over the error channel. If an error is sent all processing will be stopped. It's up
|
||||
// to the caller to reopen the stream in the event of an error by reinvoking this method.
|
||||
func (cli *DockerCli) Events(ctx context.Context) (<-chan events.Message, <-chan error) {
|
||||
messages := make(chan events.Message)
|
||||
errs := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
hostUrl, err := url.Parse(cli.host)
|
||||
if err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
|
||||
cloudConfig, existed := cli.configFile.CloudConfig[cli.host]
|
||||
if !existed {
|
||||
errs <- errors.New("Please specify 'accessKey' and 'secretKey'!")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: add filter when we have other type event.
|
||||
var u = url.URL{Scheme: "wss", Host: hostUrl.Host, Path: "/events/ws"}
|
||||
|
||||
// add sign to header
|
||||
req, err := http.NewRequest("GET", u.String(), nil)
|
||||
if err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
|
||||
req.URL = &u
|
||||
req = signutil.Sign4(cloudConfig.AccessKey, cloudConfig.SecretKey, req)
|
||||
|
||||
// connect to websocket server
|
||||
config := &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
dialer := websocket.Dialer{
|
||||
TLSClientConfig: config,
|
||||
}
|
||||
|
||||
ws, resp, err := dialer.Dial(u.String(), req.Header)
|
||||
if err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
defer ws.Close()
|
||||
|
||||
if resp.ContentLength > 0 {
|
||||
defer resp.Body.Close()
|
||||
ioutil.ReadAll(resp.Body)
|
||||
}
|
||||
|
||||
// process websocket message
|
||||
for {
|
||||
_, message, err := ws.ReadMessage()
|
||||
if err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
errs <- ctx.Err()
|
||||
return
|
||||
default:
|
||||
var event events.Message
|
||||
err := json.Unmarshal([]byte(message), &event)
|
||||
if err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case messages <- event:
|
||||
case <-ctx.Done():
|
||||
errs <- ctx.Err()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return messages, errs
|
||||
}
|
||||
209
vendor/github.com/hyperhq/hypercli/api/client/exec.go
generated
vendored
209
vendor/github.com/hyperhq/hypercli/api/client/exec.go
generated
vendored
@@ -1,209 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/pkg/promise"
|
||||
)
|
||||
|
||||
// CmdExec runs a command in a running container.
|
||||
//
|
||||
// Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
|
||||
func (cli *DockerCli) CmdExec(args ...string) error {
|
||||
cmd := Cli.Subcmd("exec", []string{"CONTAINER COMMAND [ARG...]"}, Cli.DockerCommands["exec"].Description, true)
|
||||
detachKeys := cmd.String([]string{}, "", "Override the key sequence for detaching a container")
|
||||
|
||||
execConfig, err := ParseExec(cmd, args)
|
||||
container := cmd.Arg(0)
|
||||
// just in case the ParseExec does not exit
|
||||
if container == "" || err != nil {
|
||||
return Cli.StatusError{StatusCode: 1}
|
||||
}
|
||||
|
||||
if *detachKeys != "" {
|
||||
cli.configFile.DetachKeys = *detachKeys
|
||||
}
|
||||
|
||||
// Send client escape keys
|
||||
execConfig.DetachKeys = cli.configFile.DetachKeys
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
response, err := cli.client.ContainerExecCreate(ctx, container, *execConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
execID := response.ID
|
||||
if execID == "" {
|
||||
fmt.Fprintf(cli.out, "exec ID empty")
|
||||
return nil
|
||||
}
|
||||
|
||||
//Temp struct for execStart so that we don't need to transfer all the execConfig
|
||||
if !execConfig.Detach {
|
||||
if err := cli.CheckTtyInput(execConfig.AttachStdin, execConfig.Tty); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
execStartCheck := types.ExecStartCheck{
|
||||
Detach: execConfig.Detach,
|
||||
Tty: execConfig.Tty,
|
||||
}
|
||||
|
||||
if err := cli.client.ContainerExecStart(ctx, execID, execStartCheck); err != nil {
|
||||
return err
|
||||
}
|
||||
// For now don't print this - wait for when we support exec wait()
|
||||
// fmt.Fprintf(cli.out, "%s\n", execID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Interactive exec requested.
|
||||
var (
|
||||
out, stderr io.Writer
|
||||
in io.ReadCloser
|
||||
errCh chan error
|
||||
)
|
||||
|
||||
if execConfig.AttachStdin {
|
||||
in = cli.in
|
||||
}
|
||||
if execConfig.AttachStdout {
|
||||
out = cli.out
|
||||
}
|
||||
if execConfig.AttachStderr {
|
||||
if execConfig.Tty {
|
||||
stderr = cli.out
|
||||
} else {
|
||||
stderr = cli.err
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := cli.client.ContainerExecAttach(ctx, execID, *execConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Close()
|
||||
if in != nil && execConfig.Tty {
|
||||
if err := cli.setRawTerminal(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.restoreTerminal(in)
|
||||
}
|
||||
errCh = promise.Go(func() error {
|
||||
return cli.holdHijackedConnection(execConfig.Tty, in, out, stderr, resp)
|
||||
})
|
||||
|
||||
if execConfig.Tty && cli.isTerminalIn {
|
||||
if err := cli.monitorTtySize(ctx, execID, true); err != nil {
|
||||
fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := <-errCh; err != nil {
|
||||
logrus.Debugf("Error hijack: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
var status int
|
||||
if _, status, err = getExecExitCode(ctx, cli, execID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if status != 0 {
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseExec parses the specified args for the specified command and generates
|
||||
// an ExecConfig from it.
|
||||
// If the minimal number of specified args is not right or if specified args are
|
||||
// not valid, it will return an error.
|
||||
func ParseExec(cmd *flag.FlagSet, args []string) (*types.ExecConfig, error) {
|
||||
var (
|
||||
flStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached")
|
||||
flTty = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY")
|
||||
flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run command in the background")
|
||||
flUser = cmd.String([]string{}, "", "Username or UID (format: <name|uid>[:<group|gid>])")
|
||||
flPrivileged = cmd.Bool([]string{}, false, "Give extended privileges to the command")
|
||||
execCmd []string
|
||||
)
|
||||
cmd.Require(flag.Min, 2)
|
||||
if err := cmd.ParseFlags(args, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parsedArgs := cmd.Args()
|
||||
execCmd = parsedArgs[1:]
|
||||
|
||||
execConfig := &types.ExecConfig{
|
||||
User: *flUser,
|
||||
Privileged: *flPrivileged,
|
||||
Tty: *flTty,
|
||||
Cmd: execCmd,
|
||||
Detach: *flDetach,
|
||||
}
|
||||
|
||||
// If -d is not set, attach to everything by default
|
||||
if !*flDetach {
|
||||
execConfig.AttachStdout = true
|
||||
execConfig.AttachStderr = true
|
||||
if *flStdin {
|
||||
execConfig.AttachStdin = true
|
||||
}
|
||||
}
|
||||
|
||||
return execConfig, nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) ExecCmd(ctx context.Context, user, contID string, cmd []string) (string, error) {
|
||||
execConfig := &types.ExecConfig{
|
||||
User: user,
|
||||
Detach: true,
|
||||
Cmd: cmd,
|
||||
}
|
||||
execCreateResponse, err := cli.client.ContainerExecCreate(ctx, contID, *execConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
execID := execCreateResponse.ID
|
||||
if execID == "" {
|
||||
err = fmt.Errorf("Failed to exec %s: Empty exec ID", strings.Join(cmd, " "))
|
||||
return "", err
|
||||
}
|
||||
execStartCheck := types.ExecStartCheck{Detach: execConfig.Detach}
|
||||
if err := cli.client.ContainerExecStart(ctx, execID, execStartCheck); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return execID, nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) WaitExec(ctx context.Context, execID string) error {
|
||||
for {
|
||||
running, status, err := getExecExitCode(ctx, cli, execID)
|
||||
switch {
|
||||
case err != nil:
|
||||
return err
|
||||
case running:
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
case status != 0:
|
||||
err = fmt.Errorf("Failed to exec cmd: %d", status)
|
||||
return err
|
||||
case status == 0:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
130
vendor/github.com/hyperhq/hypercli/api/client/exec_test.go
generated
vendored
130
vendor/github.com/hyperhq/hypercli/api/client/exec_test.go
generated
vendored
@@ -1,130 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
type arguments struct {
|
||||
args []string
|
||||
}
|
||||
|
||||
func TestParseExec(t *testing.T) {
|
||||
invalids := map[*arguments]error{
|
||||
{[]string{"-unknown"}}: fmt.Errorf("flag provided but not defined: -unknown"),
|
||||
{[]string{"-u"}}: fmt.Errorf("flag needs an argument: -u"),
|
||||
{[]string{"--user"}}: fmt.Errorf("flag needs an argument: --user"),
|
||||
}
|
||||
valids := map[*arguments]*types.ExecConfig{
|
||||
{
|
||||
[]string{"container", "command"},
|
||||
}: {
|
||||
Container: "container",
|
||||
Cmd: []string{"command"},
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
},
|
||||
{
|
||||
[]string{"container", "command1", "command2"},
|
||||
}: {
|
||||
Container: "container",
|
||||
Cmd: []string{"command1", "command2"},
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
},
|
||||
{
|
||||
[]string{"-i", "-t", "-u", "uid", "container", "command"},
|
||||
}: {
|
||||
User: "uid",
|
||||
AttachStdin: true,
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
Tty: true,
|
||||
Container: "container",
|
||||
Cmd: []string{"command"},
|
||||
},
|
||||
{
|
||||
[]string{"-d", "container", "command"},
|
||||
}: {
|
||||
AttachStdin: false,
|
||||
AttachStdout: false,
|
||||
AttachStderr: false,
|
||||
Detach: true,
|
||||
Container: "container",
|
||||
Cmd: []string{"command"},
|
||||
},
|
||||
{
|
||||
[]string{"-t", "-i", "-d", "container", "command"},
|
||||
}: {
|
||||
AttachStdin: false,
|
||||
AttachStdout: false,
|
||||
AttachStderr: false,
|
||||
Detach: true,
|
||||
Tty: true,
|
||||
Container: "container",
|
||||
Cmd: []string{"command"},
|
||||
},
|
||||
}
|
||||
for invalid, expectedError := range invalids {
|
||||
cmd := flag.NewFlagSet("exec", flag.ContinueOnError)
|
||||
cmd.ShortUsage = func() {}
|
||||
cmd.SetOutput(ioutil.Discard)
|
||||
_, err := ParseExec(cmd, invalid.args)
|
||||
if err == nil || err.Error() != expectedError.Error() {
|
||||
t.Fatalf("Expected an error [%v] for %v, got %v", expectedError, invalid, err)
|
||||
}
|
||||
|
||||
}
|
||||
for valid, expectedExecConfig := range valids {
|
||||
cmd := flag.NewFlagSet("exec", flag.ContinueOnError)
|
||||
cmd.ShortUsage = func() {}
|
||||
cmd.SetOutput(ioutil.Discard)
|
||||
execConfig, err := ParseExec(cmd, valid.args)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !compareExecConfig(expectedExecConfig, execConfig) {
|
||||
t.Fatalf("Expected [%v] for %v, got [%v]", expectedExecConfig, valid, execConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func compareExecConfig(config1 *types.ExecConfig, config2 *types.ExecConfig) bool {
|
||||
if config1.AttachStderr != config2.AttachStderr {
|
||||
return false
|
||||
}
|
||||
if config1.AttachStdin != config2.AttachStdin {
|
||||
return false
|
||||
}
|
||||
if config1.AttachStdout != config2.AttachStdout {
|
||||
return false
|
||||
}
|
||||
if config1.Container != config2.Container {
|
||||
return false
|
||||
}
|
||||
if config1.Detach != config2.Detach {
|
||||
return false
|
||||
}
|
||||
if config1.Privileged != config2.Privileged {
|
||||
return false
|
||||
}
|
||||
if config1.Tty != config2.Tty {
|
||||
return false
|
||||
}
|
||||
if config1.User != config2.User {
|
||||
return false
|
||||
}
|
||||
if len(config1.Cmd) != len(config2.Cmd) {
|
||||
return false
|
||||
}
|
||||
for index, value := range config1.Cmd {
|
||||
if value != config2.Cmd[index] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
42
vendor/github.com/hyperhq/hypercli/api/client/export.go
generated
vendored
42
vendor/github.com/hyperhq/hypercli/api/client/export.go
generated
vendored
@@ -1,42 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdExport exports a filesystem as a tar archive.
|
||||
//
|
||||
// The tar archive is streamed to STDOUT by default or written to a file.
|
||||
//
|
||||
// Usage: docker export [OPTIONS] CONTAINER
|
||||
func (cli *DockerCli) Export(args ...string) error {
|
||||
cmd := Cli.Subcmd("export", []string{"CONTAINER"}, Cli.DockerCommands["export"].Description, true)
|
||||
outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT")
|
||||
cmd.Require(flag.Exact, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
if *outfile == "" && cli.isTerminalOut {
|
||||
return errors.New("Cowardly refusing to save to a terminal. Use the -o flag or redirect.")
|
||||
}
|
||||
|
||||
responseBody, err := cli.client.ContainerExport(context.Background(), cmd.Arg(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer responseBody.Close()
|
||||
|
||||
if *outfile == "" {
|
||||
_, err := io.Copy(cli.out, responseBody)
|
||||
return err
|
||||
}
|
||||
|
||||
return copyToFile(*outfile, responseBody)
|
||||
|
||||
}
|
||||
295
vendor/github.com/hyperhq/hypercli/api/client/fip.go
generated
vendored
295
vendor/github.com/hyperhq/hypercli/api/client/fip.go
generated
vendored
@@ -1,295 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hyper-api/types/filters"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/opts"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
var warnMessage = "Please note that Floating IP (FIP) is billed monthly. The billing begins when a new IP is allocated, ends when it is released. Partial month is treated as a entire month. Do you want to continue?"
|
||||
|
||||
// CmdFip is the parent subcommand for all fip commands
|
||||
//
|
||||
// Usage: docker fip <COMMAND> [OPTIONS]
|
||||
func (cli *DockerCli) CmdFip(args ...string) error {
|
||||
cmd := Cli.Subcmd("fip", []string{"COMMAND [OPTIONS]"}, fipUsage(), false)
|
||||
cmd.Require(flag.Min, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
// CmdNetworkCreate creates a new fip with a given name
|
||||
//
|
||||
// Usage: docker fip create [OPTIONS] COUNT
|
||||
func (cli *DockerCli) CmdFipAllocate(args ...string) error {
|
||||
cmd := Cli.Subcmd("fip allocate", []string{"COUNT"}, "Creates some new floating IPs by the user", false)
|
||||
flAvailable := cmd.Bool([]string{"-pick"}, false, "Pick an available floating IP if have")
|
||||
flForce := cmd.Bool([]string{"y", "-yes"}, false, "Agree to allocate floating IP, will not show prompt")
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *flAvailable == true {
|
||||
fipFilterArgs, _ := filters.FromParam("dangling=true")
|
||||
options := types.NetworkListOptions{
|
||||
Filters: fipFilterArgs,
|
||||
}
|
||||
fips, err := cli.client.FipList(context.Background(), options)
|
||||
if err == nil {
|
||||
for _, fip := range fips {
|
||||
if fip["container"] == "" && fip["service"] == "" {
|
||||
fmt.Fprintf(cli.out, "%s\n", fip["fip"])
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if *flForce == false {
|
||||
if askForConfirmation(warnMessage) == false {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
fips, err := cli.client.FipAllocate(context.Background(), cmd.Arg(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, ip := range fips {
|
||||
fmt.Fprintf(cli.out, "%s\n", ip)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdFipRelease deletes one or more fips
|
||||
//
|
||||
// Usage: docker fip release FIP [FIP...]
|
||||
func (cli *DockerCli) CmdFipRelease(args ...string) error {
|
||||
cmd := Cli.Subcmd("fip release", []string{"FIP [FIP...]"}, "Release one or more fips", false)
|
||||
cmd.Require(flag.Min, 1)
|
||||
if err := cmd.ParseFlags(args, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
status := 0
|
||||
for _, ip := range cmd.Args() {
|
||||
if err := cli.client.FipRelease(context.Background(), ip); err != nil {
|
||||
fmt.Fprintf(cli.err, "%s\n", err)
|
||||
status = 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
if status != 0 {
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdFipAttach connects a container to a floating IP
|
||||
//
|
||||
// Usage: docker fip attach [OPTIONS] <FIP> <CONTAINER>
|
||||
func (cli *DockerCli) CmdFipAttach(args ...string) error {
|
||||
cmd := Cli.Subcmd("fip attach", []string{"FIP CONTAINER"}, "Connects a container to a floating IP", false)
|
||||
flForce := cmd.Bool([]string{"f", "-force"}, false, "Deattach that FIP and attach it to this container")
|
||||
cmd.Require(flag.Min, 2)
|
||||
if err := cmd.ParseFlags(args, true); err != nil {
|
||||
return err
|
||||
}
|
||||
if *flForce {
|
||||
filter, _ := filters.FromParam("dangling=false")
|
||||
options := types.NetworkListOptions{
|
||||
Filters: filter,
|
||||
}
|
||||
|
||||
fips, err := cli.client.FipList(context.Background(), options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, fip := range fips {
|
||||
if ip := fip["fip"]; ip == cmd.Arg(0) {
|
||||
if fip["container"] != "" {
|
||||
cli.client.FipDetach(context.Background(), fip["container"])
|
||||
} else if fip["service"] != "" {
|
||||
ip = ""
|
||||
sv := types.ServiceUpdate{
|
||||
FIP: &ip,
|
||||
}
|
||||
cli.client.ServiceUpdate(context.Background(), fip["service"], sv)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return cli.client.FipAttach(context.Background(), cmd.Arg(0), cmd.Arg(1))
|
||||
}
|
||||
|
||||
// CmdFipDetach disconnects a container from a floating IP
|
||||
//
|
||||
// Usage: docker fip detach <CONTAINER>
|
||||
func (cli *DockerCli) CmdFipDetach(args ...string) error {
|
||||
cmd := Cli.Subcmd("fip detach", []string{"CONTAINER"}, "Disconnects container from a floating IP", false)
|
||||
//force := cmd.Bool([]string{"f", "-force"}, false, "Force the container to disconnect from a floating IP")
|
||||
cmd.Require(flag.Exact, 1)
|
||||
if err := cmd.ParseFlags(args, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ip, err := cli.client.FipDetach(context.Background(), cmd.Arg(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cli.out, "%s\n", ip)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdFipLs lists all the fips
|
||||
//
|
||||
// Usage: docker fip ls [OPTIONS]
|
||||
func (cli *DockerCli) CmdFipLs(args ...string) error {
|
||||
cmd := Cli.Subcmd("fip ls", nil, "Lists fips", true)
|
||||
|
||||
flFilter := opts.NewListOpts(nil)
|
||||
cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided")
|
||||
|
||||
cmd.Require(flag.Exact, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Consolidate all filter flags, and sanity check them early.
|
||||
// They'll get process after get response from server.
|
||||
fipFilterArgs := filters.NewArgs()
|
||||
for _, f := range flFilter.GetAll() {
|
||||
if fipFilterArgs, err = filters.ParseFlag(f, fipFilterArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
options := types.NetworkListOptions{
|
||||
Filters: fipFilterArgs,
|
||||
}
|
||||
|
||||
fips, err := cli.client.FipList(context.Background(), options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
||||
fmt.Fprintf(w, "Floating IP\tName\tContainer\tService\n")
|
||||
for _, fip := range fips {
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", fip["fip"], fip["name"], fip["container"], fip["service"])
|
||||
}
|
||||
|
||||
w.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) CmdFipName(args ...string) error {
|
||||
cmd := Cli.Subcmd("fip name", []string{"FIP [NAME]"}, "Set a name for a floating IP", false)
|
||||
//force := cmd.Bool([]string{"f", "-force"}, false, "Force the container to disconnect from a floating IP")
|
||||
cmd.Require(flag.Min, 1)
|
||||
cmd.Require(flag.Max, 2)
|
||||
if err := cmd.ParseFlags(args, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := cli.client.FipName(context.Background(), cmd.Arg(0), cmd.Arg(1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fipUsage() string {
|
||||
fipCommands := [][]string{
|
||||
{"allocate", "Allocate a or some IPs"},
|
||||
{"attach", "Attach floating IP to container"},
|
||||
{"detach", "Detach floating IP from container"},
|
||||
{"ls", "List all floating IPs"},
|
||||
{"release", "Release a floating IP"},
|
||||
{"name", "Name a floating IP"},
|
||||
}
|
||||
|
||||
help := "Commands:\n"
|
||||
|
||||
for _, cmd := range fipCommands {
|
||||
help += fmt.Sprintf(" %-25.25s%s\n", cmd[0], cmd[1])
|
||||
}
|
||||
|
||||
help += fmt.Sprintf("\nRun 'hyper fip COMMAND --help' for more information on a command.")
|
||||
return help
|
||||
}
|
||||
|
||||
// Allocate and attach a fip
|
||||
func (cli *DockerCli) associateNewFip(ctx context.Context, contID string) (string, error) {
|
||||
fips, err := cli.client.FipAllocate(ctx, "1")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, ip := range fips {
|
||||
err = cli.client.FipAttach(ctx, ip, contID)
|
||||
if err != nil {
|
||||
go func() {
|
||||
cli.client.FipRelease(ctx, ip)
|
||||
}()
|
||||
return "", err
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("Server failed to create new fip")
|
||||
}
|
||||
|
||||
// Release a fip
|
||||
func (cli *DockerCli) releaseFip(ctx context.Context, ip string) error {
|
||||
return cli.client.FipRelease(ctx, ip)
|
||||
}
|
||||
|
||||
// Detach and release a fip
|
||||
func (cli *DockerCli) releaseContainerFip(ctx context.Context, contID string) error {
|
||||
ip, err := cli.client.FipDetach(ctx, contID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return cli.client.FipRelease(ctx, ip)
|
||||
}
|
||||
|
||||
// askForConfirmation asks the user for confirmation. A user must type in "yes" or "no" and
|
||||
// then press enter. It has fuzzy matching, so "y", "Y", "yes", "YES", and "Yes" all count as
|
||||
// confirmations. If the input is not recognized, it will ask again. The function does not return
|
||||
// until it gets a valid response from the user.
|
||||
func askForConfirmation(s string) bool {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
for {
|
||||
fmt.Printf("%s [y/n]: ", s)
|
||||
|
||||
response, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
response = strings.ToLower(strings.TrimSpace(response))
|
||||
|
||||
if response == "y" || response == "yes" {
|
||||
return true
|
||||
} else if response == "n" || response == "no" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
264
vendor/github.com/hyperhq/hypercli/api/client/formatter/custom.go
generated
vendored
264
vendor/github.com/hyperhq/hypercli/api/client/formatter/custom.go
generated
vendored
@@ -1,264 +0,0 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hypercli/api"
|
||||
"github.com/hyperhq/hypercli/pkg/stringid"
|
||||
"github.com/hyperhq/hypercli/pkg/stringutils"
|
||||
)
|
||||
|
||||
const (
|
||||
tableKey = "table"
|
||||
fipLabel = "sh.hyper.fip"
|
||||
|
||||
containerIDHeader = "CONTAINER ID"
|
||||
imageHeader = "IMAGE"
|
||||
namesHeader = "NAMES"
|
||||
commandHeader = "COMMAND"
|
||||
createdSinceHeader = "CREATED"
|
||||
createdAtHeader = "CREATED AT"
|
||||
runningForHeader = "CREATED"
|
||||
statusHeader = "STATUS"
|
||||
portsHeader = "PORTS"
|
||||
sizeHeader = "SIZE"
|
||||
labelsHeader = "LABELS"
|
||||
imageIDHeader = "IMAGE ID"
|
||||
repositoryHeader = "REPOSITORY"
|
||||
tagHeader = "TAG"
|
||||
digestHeader = "DIGEST"
|
||||
fipHeader = "PUBLIC IP"
|
||||
volumeNameHeader = "NAME"
|
||||
volumeSizeHeader = "SIZE"
|
||||
volumeDriverHeader = "DRIVER"
|
||||
volumeContainerHeader = "CONTAINER"
|
||||
)
|
||||
|
||||
type containerContext struct {
|
||||
baseSubContext
|
||||
trunc bool
|
||||
c types.Container
|
||||
}
|
||||
|
||||
func (c *containerContext) ID() string {
|
||||
c.addHeader(containerIDHeader)
|
||||
if c.trunc {
|
||||
return stringid.TruncateID(c.c.ID)
|
||||
}
|
||||
return c.c.ID
|
||||
}
|
||||
|
||||
func (c *containerContext) Names() string {
|
||||
c.addHeader(namesHeader)
|
||||
names := stripNamePrefix(c.c.Names)
|
||||
if c.trunc {
|
||||
for _, name := range names {
|
||||
if len(strings.Split(name, "/")) == 1 {
|
||||
names = []string{name}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings.Join(names, ",")
|
||||
}
|
||||
|
||||
func (c *containerContext) Image() string {
|
||||
c.addHeader(imageHeader)
|
||||
if c.c.Image == "" {
|
||||
return "<no image>"
|
||||
}
|
||||
if c.trunc {
|
||||
if trunc := stringid.TruncateID(c.c.ImageID); trunc == stringid.TruncateID(c.c.Image) {
|
||||
return trunc
|
||||
}
|
||||
}
|
||||
return c.c.Image
|
||||
}
|
||||
|
||||
func (c *containerContext) Command() string {
|
||||
c.addHeader(commandHeader)
|
||||
command := c.c.Command
|
||||
if c.trunc {
|
||||
command = stringutils.Truncate(command, 20)
|
||||
}
|
||||
return strconv.Quote(command)
|
||||
}
|
||||
|
||||
func (c *containerContext) CreatedAt() string {
|
||||
c.addHeader(createdAtHeader)
|
||||
return time.Unix(int64(c.c.Created), 0).String()
|
||||
}
|
||||
|
||||
func (c *containerContext) RunningFor() string {
|
||||
c.addHeader(runningForHeader)
|
||||
createdAt := time.Unix(int64(c.c.Created), 0)
|
||||
return units.HumanDuration(time.Now().UTC().Sub(createdAt))
|
||||
}
|
||||
|
||||
func (c *containerContext) Ports() string {
|
||||
c.addHeader(portsHeader)
|
||||
return api.DisplayablePorts(c.c.Ports)
|
||||
}
|
||||
|
||||
func (c *containerContext) Status() string {
|
||||
c.addHeader(statusHeader)
|
||||
return c.c.Status
|
||||
}
|
||||
|
||||
func (c *containerContext) Size() string {
|
||||
c.addHeader(sizeHeader)
|
||||
srw := units.HumanSize(float64(c.c.SizeRw))
|
||||
sv := units.HumanSize(float64(c.c.SizeRootFs))
|
||||
|
||||
sf := srw
|
||||
if c.c.SizeRootFs > 0 {
|
||||
sf = fmt.Sprintf("%s (virtual %s)", srw, sv)
|
||||
}
|
||||
return sf
|
||||
}
|
||||
|
||||
func (c *containerContext) Labels() string {
|
||||
c.addHeader(labelsHeader)
|
||||
if c.c.Labels == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var joinLabels []string
|
||||
for k, v := range c.c.Labels {
|
||||
joinLabels = append(joinLabels, fmt.Sprintf("%s=%s", k, v))
|
||||
}
|
||||
return strings.Join(joinLabels, ",")
|
||||
}
|
||||
|
||||
func (c *containerContext) Label(name string) string {
|
||||
n := strings.Split(name, ".")
|
||||
r := strings.NewReplacer("-", " ", "_", " ")
|
||||
h := r.Replace(n[len(n)-1])
|
||||
|
||||
c.addHeader(h)
|
||||
|
||||
if c.c.Labels == nil {
|
||||
return ""
|
||||
}
|
||||
return c.c.Labels[name]
|
||||
}
|
||||
|
||||
func (c *containerContext) PublicIP() string {
|
||||
c.addHeader(fipHeader)
|
||||
|
||||
if c.c.Labels == nil {
|
||||
return ""
|
||||
}
|
||||
return c.c.Labels[fipLabel]
|
||||
}
|
||||
|
||||
type imageContext struct {
|
||||
baseSubContext
|
||||
trunc bool
|
||||
i types.Image
|
||||
repo string
|
||||
tag string
|
||||
digest string
|
||||
}
|
||||
|
||||
func (c *imageContext) ID() string {
|
||||
c.addHeader(imageIDHeader)
|
||||
if c.trunc {
|
||||
return stringid.TruncateID(c.i.ID)
|
||||
}
|
||||
return c.i.ID
|
||||
}
|
||||
|
||||
func (c *imageContext) Repository() string {
|
||||
c.addHeader(repositoryHeader)
|
||||
return c.repo
|
||||
}
|
||||
|
||||
func (c *imageContext) Tag() string {
|
||||
c.addHeader(tagHeader)
|
||||
return c.tag
|
||||
}
|
||||
|
||||
func (c *imageContext) Digest() string {
|
||||
c.addHeader(digestHeader)
|
||||
return c.digest
|
||||
}
|
||||
|
||||
func (c *imageContext) CreatedSince() string {
|
||||
c.addHeader(createdSinceHeader)
|
||||
createdAt := time.Unix(int64(c.i.Created), 0)
|
||||
return units.HumanDuration(time.Now().UTC().Sub(createdAt))
|
||||
}
|
||||
|
||||
func (c *imageContext) CreatedAt() string {
|
||||
c.addHeader(createdAtHeader)
|
||||
return time.Unix(int64(c.i.Created), 0).String()
|
||||
}
|
||||
|
||||
func (c *imageContext) Size() string {
|
||||
c.addHeader(sizeHeader)
|
||||
return units.HumanSize(float64(c.i.Size))
|
||||
}
|
||||
|
||||
type volumeContext struct {
|
||||
baseSubContext
|
||||
i types.Volume
|
||||
}
|
||||
|
||||
func (c *volumeContext) Name() string {
|
||||
c.addHeader(volumeNameHeader)
|
||||
return c.i.Name
|
||||
}
|
||||
|
||||
func (c *volumeContext) Size() string {
|
||||
c.addHeader(volumeSizeHeader)
|
||||
size := c.i.Labels["size"]
|
||||
return size + " GB"
|
||||
}
|
||||
|
||||
func (c *volumeContext) Driver() string {
|
||||
c.addHeader(volumeDriverHeader)
|
||||
return c.i.Driver
|
||||
}
|
||||
|
||||
func (c *volumeContext) Container() string {
|
||||
c.addHeader(volumeContainerHeader)
|
||||
container := c.i.Labels["container"]
|
||||
return container
|
||||
}
|
||||
|
||||
type subContext interface {
|
||||
fullHeader() string
|
||||
addHeader(header string)
|
||||
}
|
||||
|
||||
type baseSubContext struct {
|
||||
header []string
|
||||
}
|
||||
|
||||
func (c *baseSubContext) fullHeader() string {
|
||||
if c.header == nil {
|
||||
return ""
|
||||
}
|
||||
return strings.Join(c.header, "\t")
|
||||
}
|
||||
|
||||
func (c *baseSubContext) addHeader(header string) {
|
||||
if c.header == nil {
|
||||
c.header = []string{}
|
||||
}
|
||||
c.header = append(c.header, strings.ToUpper(header))
|
||||
}
|
||||
|
||||
func stripNamePrefix(ss []string) []string {
|
||||
for i, s := range ss {
|
||||
ss[i] = s[1:]
|
||||
}
|
||||
|
||||
return ss
|
||||
}
|
||||
192
vendor/github.com/hyperhq/hypercli/api/client/formatter/custom_test.go
generated
vendored
192
vendor/github.com/hyperhq/hypercli/api/client/formatter/custom_test.go
generated
vendored
@@ -1,192 +0,0 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hypercli/pkg/stringid"
|
||||
)
|
||||
|
||||
func TestContainerPsContext(t *testing.T) {
|
||||
containerID := stringid.GenerateRandomID()
|
||||
unix := time.Now().Unix()
|
||||
|
||||
var ctx containerContext
|
||||
cases := []struct {
|
||||
container types.Container
|
||||
trunc bool
|
||||
expValue string
|
||||
expHeader string
|
||||
call func() string
|
||||
}{
|
||||
{types.Container{ID: containerID}, true, stringid.TruncateID(containerID), containerIDHeader, ctx.ID},
|
||||
{types.Container{ID: containerID}, false, containerID, containerIDHeader, ctx.ID},
|
||||
{types.Container{Names: []string{"/foobar_baz"}}, true, "foobar_baz", namesHeader, ctx.Names},
|
||||
{types.Container{Image: "ubuntu"}, true, "ubuntu", imageHeader, ctx.Image},
|
||||
{types.Container{Image: "verylongimagename"}, true, "verylongimagename", imageHeader, ctx.Image},
|
||||
{types.Container{Image: "verylongimagename"}, false, "verylongimagename", imageHeader, ctx.Image},
|
||||
{types.Container{
|
||||
Image: "a5a665ff33eced1e0803148700880edab4",
|
||||
ImageID: "a5a665ff33eced1e0803148700880edab4269067ed77e27737a708d0d293fbf5",
|
||||
},
|
||||
true,
|
||||
"a5a665ff33ec",
|
||||
imageHeader,
|
||||
ctx.Image,
|
||||
},
|
||||
{types.Container{
|
||||
Image: "a5a665ff33eced1e0803148700880edab4",
|
||||
ImageID: "a5a665ff33eced1e0803148700880edab4269067ed77e27737a708d0d293fbf5",
|
||||
},
|
||||
false,
|
||||
"a5a665ff33eced1e0803148700880edab4",
|
||||
imageHeader,
|
||||
ctx.Image,
|
||||
},
|
||||
{types.Container{Image: ""}, true, "<no image>", imageHeader, ctx.Image},
|
||||
{types.Container{Command: "sh -c 'ls -la'"}, true, `"sh -c 'ls -la'"`, commandHeader, ctx.Command},
|
||||
{types.Container{Created: unix}, true, time.Unix(unix, 0).String(), createdAtHeader, ctx.CreatedAt},
|
||||
{types.Container{Ports: []types.Port{{PrivatePort: 8080, PublicPort: 8080, Type: "tcp"}}}, true, "8080/tcp", portsHeader, ctx.Ports},
|
||||
{types.Container{Status: "RUNNING"}, true, "RUNNING", statusHeader, ctx.Status},
|
||||
{types.Container{SizeRw: 10}, true, "10 B", sizeHeader, ctx.Size},
|
||||
{types.Container{SizeRw: 10, SizeRootFs: 20}, true, "10 B (virtual 20 B)", sizeHeader, ctx.Size},
|
||||
{types.Container{}, true, "", labelsHeader, ctx.Labels},
|
||||
{types.Container{Labels: map[string]string{"cpu": "6", "storage": "ssd"}}, true, "cpu=6,storage=ssd", labelsHeader, ctx.Labels},
|
||||
{types.Container{Created: unix}, true, "Less than a second", runningForHeader, ctx.RunningFor},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
ctx = containerContext{c: c.container, trunc: c.trunc}
|
||||
v := c.call()
|
||||
if strings.Contains(v, ",") {
|
||||
compareMultipleValues(t, v, c.expValue)
|
||||
} else if v != c.expValue {
|
||||
t.Fatalf("Expected %s, was %s\n", c.expValue, v)
|
||||
}
|
||||
|
||||
h := ctx.fullHeader()
|
||||
if h != c.expHeader {
|
||||
t.Fatalf("Expected %s, was %s\n", c.expHeader, h)
|
||||
}
|
||||
}
|
||||
|
||||
c1 := types.Container{Labels: map[string]string{"com.docker.swarm.swarm-id": "33", "com.docker.swarm.node_name": "ubuntu"}}
|
||||
ctx = containerContext{c: c1, trunc: true}
|
||||
|
||||
sid := ctx.Label("com.docker.swarm.swarm-id")
|
||||
node := ctx.Label("com.docker.swarm.node_name")
|
||||
if sid != "33" {
|
||||
t.Fatalf("Expected 33, was %s\n", sid)
|
||||
}
|
||||
|
||||
if node != "ubuntu" {
|
||||
t.Fatalf("Expected ubuntu, was %s\n", node)
|
||||
}
|
||||
|
||||
h := ctx.fullHeader()
|
||||
if h != "SWARM ID\tNODE NAME" {
|
||||
t.Fatalf("Expected %s, was %s\n", "SWARM ID\tNODE NAME", h)
|
||||
|
||||
}
|
||||
|
||||
c2 := types.Container{}
|
||||
ctx = containerContext{c: c2, trunc: true}
|
||||
|
||||
label := ctx.Label("anything.really")
|
||||
if label != "" {
|
||||
t.Fatalf("Expected an empty string, was %s", label)
|
||||
}
|
||||
|
||||
ctx = containerContext{c: c2, trunc: true}
|
||||
fullHeader := ctx.fullHeader()
|
||||
if fullHeader != "" {
|
||||
t.Fatalf("Expected fullHeader to be empty, was %s", fullHeader)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestImagesContext(t *testing.T) {
|
||||
imageID := stringid.GenerateRandomID()
|
||||
unix := time.Now().Unix()
|
||||
|
||||
var ctx imageContext
|
||||
cases := []struct {
|
||||
imageCtx imageContext
|
||||
expValue string
|
||||
expHeader string
|
||||
call func() string
|
||||
}{
|
||||
{imageContext{
|
||||
i: types.Image{ID: imageID},
|
||||
trunc: true,
|
||||
}, stringid.TruncateID(imageID), imageIDHeader, ctx.ID},
|
||||
{imageContext{
|
||||
i: types.Image{ID: imageID},
|
||||
trunc: false,
|
||||
}, imageID, imageIDHeader, ctx.ID},
|
||||
{imageContext{
|
||||
i: types.Image{Size: 10},
|
||||
trunc: true,
|
||||
}, "10 B", sizeHeader, ctx.Size},
|
||||
{imageContext{
|
||||
i: types.Image{Created: unix},
|
||||
trunc: true,
|
||||
}, time.Unix(unix, 0).String(), createdAtHeader, ctx.CreatedAt},
|
||||
// FIXME
|
||||
// {imageContext{
|
||||
// i: types.Image{Created: unix},
|
||||
// trunc: true,
|
||||
// }, units.HumanDuration(time.Unix(unix, 0)), createdSinceHeader, ctx.CreatedSince},
|
||||
{imageContext{
|
||||
i: types.Image{},
|
||||
repo: "busybox",
|
||||
}, "busybox", repositoryHeader, ctx.Repository},
|
||||
{imageContext{
|
||||
i: types.Image{},
|
||||
tag: "latest",
|
||||
}, "latest", tagHeader, ctx.Tag},
|
||||
{imageContext{
|
||||
i: types.Image{},
|
||||
digest: "sha256:d149ab53f8718e987c3a3024bb8aa0e2caadf6c0328f1d9d850b2a2a67f2819a",
|
||||
}, "sha256:d149ab53f8718e987c3a3024bb8aa0e2caadf6c0328f1d9d850b2a2a67f2819a", digestHeader, ctx.Digest},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
ctx = c.imageCtx
|
||||
v := c.call()
|
||||
if strings.Contains(v, ",") {
|
||||
compareMultipleValues(t, v, c.expValue)
|
||||
} else if v != c.expValue {
|
||||
t.Fatalf("Expected %s, was %s\n", c.expValue, v)
|
||||
}
|
||||
|
||||
h := ctx.fullHeader()
|
||||
if h != c.expHeader {
|
||||
t.Fatalf("Expected %s, was %s\n", c.expHeader, h)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func compareMultipleValues(t *testing.T, value, expected string) {
|
||||
// comma-separated values means probably a map input, which won't
|
||||
// be guaranteed to have the same order as our expected value
|
||||
// We'll create maps and use reflect.DeepEquals to check instead:
|
||||
entriesMap := make(map[string]string)
|
||||
expMap := make(map[string]string)
|
||||
entries := strings.Split(value, ",")
|
||||
expectedEntries := strings.Split(expected, ",")
|
||||
for _, entry := range entries {
|
||||
keyval := strings.Split(entry, "=")
|
||||
entriesMap[keyval[0]] = keyval[1]
|
||||
}
|
||||
for _, expected := range expectedEntries {
|
||||
keyval := strings.Split(expected, "=")
|
||||
expMap[keyval[0]] = keyval[1]
|
||||
}
|
||||
if !reflect.DeepEqual(expMap, entriesMap) {
|
||||
t.Fatalf("Expected entries: %v, got: %v", expected, value)
|
||||
}
|
||||
}
|
||||
302
vendor/github.com/hyperhq/hypercli/api/client/formatter/formatter.go
generated
vendored
302
vendor/github.com/hyperhq/hypercli/api/client/formatter/formatter.go
generated
vendored
@@ -1,302 +0,0 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hypercli/reference"
|
||||
)
|
||||
|
||||
const (
|
||||
tableFormatKey = "table"
|
||||
rawFormatKey = "raw"
|
||||
|
||||
defaultContainerTableFormat = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.RunningFor}} ago\t{{.Status}}\t{{.Ports}}\t{{.Names}}\t{{.PublicIP}}"
|
||||
defaultImageTableFormat = "table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.CreatedSince}} ago\t{{.Size}}"
|
||||
defaultImageTableFormatWithDigest = "table {{.Repository}}\t{{.Tag}}\t{{.Digest}}\t{{.ID}}\t{{.CreatedSince}} ago\t{{.Size}}"
|
||||
defaultVolumeTableFormat = "table {{.Driver}}\t{{.Name}}\t{{.Size}}\t{{.Container}}"
|
||||
defaultQuietFormat = "{{.ID}}"
|
||||
)
|
||||
|
||||
// Context contains information required by the formatter to print the output as desired.
|
||||
type Context struct {
|
||||
// Output is the output stream to which the formatted string is written.
|
||||
Output io.Writer
|
||||
// Format is used to choose raw, table or custom format for the output.
|
||||
Format string
|
||||
// Quiet when set to true will simply print minimal information.
|
||||
Quiet bool
|
||||
// Trunc when set to true will truncate the output of certain fields such as Container ID.
|
||||
Trunc bool
|
||||
|
||||
// internal element
|
||||
table bool
|
||||
finalFormat string
|
||||
header string
|
||||
buffer *bytes.Buffer
|
||||
}
|
||||
|
||||
func (c *Context) preformat() {
|
||||
c.finalFormat = c.Format
|
||||
|
||||
if strings.HasPrefix(c.Format, tableKey) {
|
||||
c.table = true
|
||||
c.finalFormat = c.finalFormat[len(tableKey):]
|
||||
}
|
||||
|
||||
c.finalFormat = strings.Trim(c.finalFormat, " ")
|
||||
r := strings.NewReplacer(`\t`, "\t", `\n`, "\n")
|
||||
c.finalFormat = r.Replace(c.finalFormat)
|
||||
}
|
||||
|
||||
func (c *Context) parseFormat() (*template.Template, error) {
|
||||
tmpl, err := template.New("").Parse(c.finalFormat)
|
||||
if err != nil {
|
||||
c.buffer.WriteString(fmt.Sprintf("Template parsing error: %v\n", err))
|
||||
c.buffer.WriteTo(c.Output)
|
||||
}
|
||||
return tmpl, err
|
||||
}
|
||||
|
||||
func (c *Context) postformat(tmpl *template.Template, subContext subContext) {
|
||||
if c.table {
|
||||
if len(c.header) == 0 {
|
||||
// if we still don't have a header, we didn't have any containers so we need to fake it to get the right headers from the template
|
||||
tmpl.Execute(bytes.NewBufferString(""), subContext)
|
||||
c.header = subContext.fullHeader()
|
||||
}
|
||||
|
||||
t := tabwriter.NewWriter(c.Output, 20, 1, 3, ' ', 0)
|
||||
t.Write([]byte(c.header))
|
||||
t.Write([]byte("\n"))
|
||||
c.buffer.WriteTo(t)
|
||||
t.Flush()
|
||||
} else {
|
||||
c.buffer.WriteTo(c.Output)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) contextFormat(tmpl *template.Template, subContext subContext) error {
|
||||
if err := tmpl.Execute(c.buffer, subContext); err != nil {
|
||||
c.buffer = bytes.NewBufferString(fmt.Sprintf("Template parsing error: %v\n", err))
|
||||
c.buffer.WriteTo(c.Output)
|
||||
return err
|
||||
}
|
||||
if c.table && len(c.header) == 0 {
|
||||
c.header = subContext.fullHeader()
|
||||
}
|
||||
c.buffer.WriteString("\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContainerContext contains container specific information required by the formater, encapsulate a Context struct.
|
||||
type ContainerContext struct {
|
||||
Context
|
||||
// Size when set to true will display the size of the output.
|
||||
Size bool
|
||||
// Containers
|
||||
Containers []types.Container
|
||||
}
|
||||
|
||||
// ImageContext contains image specific information required by the formater, encapsulate a Context struct.
|
||||
type ImageContext struct {
|
||||
Context
|
||||
Digest bool
|
||||
// Images
|
||||
Images []types.Image
|
||||
}
|
||||
|
||||
type VolumeContext struct {
|
||||
Context
|
||||
// Volumes
|
||||
Volumes []*types.Volume
|
||||
}
|
||||
|
||||
func (ctx ContainerContext) Write() {
|
||||
switch ctx.Format {
|
||||
case tableFormatKey:
|
||||
ctx.Format = defaultContainerTableFormat
|
||||
if ctx.Quiet {
|
||||
ctx.Format = defaultQuietFormat
|
||||
}
|
||||
case rawFormatKey:
|
||||
if ctx.Quiet {
|
||||
ctx.Format = `container_id: {{.ID}}`
|
||||
} else {
|
||||
ctx.Format = `container_id: {{.ID}}
|
||||
image: {{.Image}}
|
||||
command: {{.Command}}
|
||||
created_at: {{.CreatedAt}}
|
||||
status: {{.Status}}
|
||||
names: {{.Names}}
|
||||
public_ip: {{.PublicIP}}
|
||||
labels: {{.Labels}}
|
||||
ports: {{.Ports}}
|
||||
`
|
||||
if ctx.Size {
|
||||
ctx.Format += `size: {{.Size}}
|
||||
`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.buffer = bytes.NewBufferString("")
|
||||
ctx.preformat()
|
||||
if ctx.table && ctx.Size {
|
||||
ctx.finalFormat += "\t{{.Size}}"
|
||||
}
|
||||
|
||||
tmpl, err := ctx.parseFormat()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, container := range ctx.Containers {
|
||||
containerCtx := &containerContext{
|
||||
trunc: ctx.Trunc,
|
||||
c: container,
|
||||
}
|
||||
err = ctx.contextFormat(tmpl, containerCtx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ctx.postformat(tmpl, &containerContext{})
|
||||
}
|
||||
|
||||
func (ctx ImageContext) Write() {
|
||||
switch ctx.Format {
|
||||
case tableFormatKey:
|
||||
ctx.Format = defaultImageTableFormat
|
||||
if ctx.Digest {
|
||||
ctx.Format = defaultImageTableFormatWithDigest
|
||||
}
|
||||
if ctx.Quiet {
|
||||
ctx.Format = defaultQuietFormat
|
||||
}
|
||||
case rawFormatKey:
|
||||
if ctx.Quiet {
|
||||
ctx.Format = `image_id: {{.ID}}`
|
||||
} else {
|
||||
if ctx.Digest {
|
||||
ctx.Format = `repository: {{ .Repository }}
|
||||
tag: {{.Tag}}
|
||||
digest: {{.Digest}}
|
||||
image_id: {{.ID}}
|
||||
created_at: {{.CreatedAt}}
|
||||
virtual_size: {{.Size}}
|
||||
`
|
||||
} else {
|
||||
ctx.Format = `repository: {{ .Repository }}
|
||||
tag: {{.Tag}}
|
||||
image_id: {{.ID}}
|
||||
created_at: {{.CreatedAt}}
|
||||
virtual_size: {{.Size}}
|
||||
`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.buffer = bytes.NewBufferString("")
|
||||
ctx.preformat()
|
||||
if ctx.table && ctx.Digest && !strings.Contains(ctx.Format, "{{.Digest}}") {
|
||||
ctx.finalFormat += "\t{{.Digest}}"
|
||||
}
|
||||
|
||||
tmpl, err := ctx.parseFormat()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, image := range ctx.Images {
|
||||
|
||||
repoTags := image.RepoTags
|
||||
repoDigests := image.RepoDigests
|
||||
|
||||
if len(repoTags) == 1 && repoTags[0] == "<none>:<none>" && len(repoDigests) == 1 && repoDigests[0] == "<none>@<none>" {
|
||||
// dangling image - clear out either repoTags or repoDigests so we only show it once below
|
||||
repoDigests = []string{}
|
||||
}
|
||||
// combine the tags and digests lists
|
||||
tagsAndDigests := append(repoTags, repoDigests...)
|
||||
for _, repoAndRef := range tagsAndDigests {
|
||||
repo := "<none>"
|
||||
tag := "<none>"
|
||||
digest := "<none>"
|
||||
|
||||
if !strings.HasPrefix(repoAndRef, "<none>") {
|
||||
ref, err := reference.ParseNamed(repoAndRef)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
repo = ref.Name()
|
||||
|
||||
switch x := ref.(type) {
|
||||
case reference.Canonical:
|
||||
digest = x.Digest().String()
|
||||
case reference.NamedTagged:
|
||||
tag = x.Tag()
|
||||
}
|
||||
}
|
||||
imageCtx := &imageContext{
|
||||
trunc: ctx.Trunc,
|
||||
i: image,
|
||||
repo: repo,
|
||||
tag: tag,
|
||||
digest: digest,
|
||||
}
|
||||
err = ctx.contextFormat(tmpl, imageCtx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.postformat(tmpl, &imageContext{})
|
||||
}
|
||||
|
||||
func (ctx VolumeContext) Write() {
|
||||
switch ctx.Format {
|
||||
case tableFormatKey:
|
||||
ctx.Format = defaultVolumeTableFormat
|
||||
if ctx.Quiet {
|
||||
ctx.Format = "{{.Name}}"
|
||||
}
|
||||
case rawFormatKey:
|
||||
if ctx.Quiet {
|
||||
ctx.Format = `name: {{.Name}}`
|
||||
} else {
|
||||
ctx.Format = `name: {{.Name}}
|
||||
driver: {{.Driver}}
|
||||
size: {{.Size}}
|
||||
container: {{.Container}}
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
ctx.buffer = bytes.NewBufferString("")
|
||||
ctx.preformat()
|
||||
|
||||
tmpl, err := ctx.parseFormat()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, vol := range ctx.Volumes {
|
||||
volCtx := &volumeContext{
|
||||
i: *vol,
|
||||
}
|
||||
err = ctx.contextFormat(tmpl, volCtx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ctx.postformat(tmpl, &volumeContext{})
|
||||
}
|
||||
535
vendor/github.com/hyperhq/hypercli/api/client/formatter/formatter_test.go
generated
vendored
535
vendor/github.com/hyperhq/hypercli/api/client/formatter/formatter_test.go
generated
vendored
@@ -1,535 +0,0 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
)
|
||||
|
||||
func TestContainerContextWrite(t *testing.T) {
|
||||
unixTime := time.Now().AddDate(0, 0, -1).Unix()
|
||||
expectedTime := time.Unix(unixTime, 0).String()
|
||||
|
||||
contexts := []struct {
|
||||
context ContainerContext
|
||||
expected string
|
||||
}{
|
||||
// Errors
|
||||
{
|
||||
ContainerContext{
|
||||
Context: Context{
|
||||
Format: "{{InvalidFunction}}",
|
||||
},
|
||||
},
|
||||
`Template parsing error: template: :1: function "InvalidFunction" not defined
|
||||
`,
|
||||
},
|
||||
{
|
||||
ContainerContext{
|
||||
Context: Context{
|
||||
Format: "{{nil}}",
|
||||
},
|
||||
},
|
||||
`Template parsing error: template: :1:2: executing "" at <nil>: nil is not a command
|
||||
`,
|
||||
},
|
||||
// Table Format
|
||||
{
|
||||
ContainerContext{
|
||||
Context: Context{
|
||||
Format: "table",
|
||||
},
|
||||
},
|
||||
`CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
containerID1 ubuntu "" 24 hours ago foobar_baz
|
||||
containerID2 ubuntu "" 24 hours ago foobar_bar
|
||||
`,
|
||||
},
|
||||
{
|
||||
ContainerContext{
|
||||
Context: Context{
|
||||
Format: "table {{.Image}}",
|
||||
},
|
||||
},
|
||||
"IMAGE\nubuntu\nubuntu\n",
|
||||
},
|
||||
{
|
||||
ContainerContext{
|
||||
Context: Context{
|
||||
Format: "table {{.Image}}",
|
||||
},
|
||||
Size: true,
|
||||
},
|
||||
"IMAGE SIZE\nubuntu 0 B\nubuntu 0 B\n",
|
||||
},
|
||||
{
|
||||
ContainerContext{
|
||||
Context: Context{
|
||||
Format: "table {{.Image}}",
|
||||
Quiet: true,
|
||||
},
|
||||
},
|
||||
"IMAGE\nubuntu\nubuntu\n",
|
||||
},
|
||||
{
|
||||
ContainerContext{
|
||||
Context: Context{
|
||||
Format: "table",
|
||||
Quiet: true,
|
||||
},
|
||||
},
|
||||
"containerID1\ncontainerID2\n",
|
||||
},
|
||||
// Raw Format
|
||||
{
|
||||
ContainerContext{
|
||||
Context: Context{
|
||||
Format: "raw",
|
||||
},
|
||||
},
|
||||
fmt.Sprintf(`container_id: containerID1
|
||||
image: ubuntu
|
||||
command: ""
|
||||
created_at: %s
|
||||
status:
|
||||
names: foobar_baz
|
||||
labels:
|
||||
ports:
|
||||
|
||||
container_id: containerID2
|
||||
image: ubuntu
|
||||
command: ""
|
||||
created_at: %s
|
||||
status:
|
||||
names: foobar_bar
|
||||
labels:
|
||||
ports:
|
||||
|
||||
`, expectedTime, expectedTime),
|
||||
},
|
||||
{
|
||||
ContainerContext{
|
||||
Context: Context{
|
||||
Format: "raw",
|
||||
},
|
||||
Size: true,
|
||||
},
|
||||
fmt.Sprintf(`container_id: containerID1
|
||||
image: ubuntu
|
||||
command: ""
|
||||
created_at: %s
|
||||
status:
|
||||
names: foobar_baz
|
||||
labels:
|
||||
ports:
|
||||
size: 0 B
|
||||
|
||||
container_id: containerID2
|
||||
image: ubuntu
|
||||
command: ""
|
||||
created_at: %s
|
||||
status:
|
||||
names: foobar_bar
|
||||
labels:
|
||||
ports:
|
||||
size: 0 B
|
||||
|
||||
`, expectedTime, expectedTime),
|
||||
},
|
||||
{
|
||||
ContainerContext{
|
||||
Context: Context{
|
||||
Format: "raw",
|
||||
Quiet: true,
|
||||
},
|
||||
},
|
||||
"container_id: containerID1\ncontainer_id: containerID2\n",
|
||||
},
|
||||
// Custom Format
|
||||
{
|
||||
ContainerContext{
|
||||
Context: Context{
|
||||
Format: "{{.Image}}",
|
||||
},
|
||||
},
|
||||
"ubuntu\nubuntu\n",
|
||||
},
|
||||
{
|
||||
ContainerContext{
|
||||
Context: Context{
|
||||
Format: "{{.Image}}",
|
||||
},
|
||||
Size: true,
|
||||
},
|
||||
"ubuntu\nubuntu\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, context := range contexts {
|
||||
containers := []types.Container{
|
||||
{ID: "containerID1", Names: []string{"/foobar_baz"}, Image: "ubuntu", Created: unixTime},
|
||||
{ID: "containerID2", Names: []string{"/foobar_bar"}, Image: "ubuntu", Created: unixTime},
|
||||
}
|
||||
out := bytes.NewBufferString("")
|
||||
context.context.Output = out
|
||||
context.context.Containers = containers
|
||||
context.context.Write()
|
||||
actual := out.String()
|
||||
if actual != context.expected {
|
||||
t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
|
||||
}
|
||||
// Clean buffer
|
||||
out.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestContainerContextWriteWithNoContainers(t *testing.T) {
|
||||
out := bytes.NewBufferString("")
|
||||
containers := []types.Container{}
|
||||
|
||||
contexts := []struct {
|
||||
context ContainerContext
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
ContainerContext{
|
||||
Context: Context{
|
||||
Format: "{{.Image}}",
|
||||
Output: out,
|
||||
},
|
||||
},
|
||||
"",
|
||||
},
|
||||
{
|
||||
ContainerContext{
|
||||
Context: Context{
|
||||
Format: "table {{.Image}}",
|
||||
Output: out,
|
||||
},
|
||||
},
|
||||
"IMAGE\n",
|
||||
},
|
||||
{
|
||||
ContainerContext{
|
||||
Context: Context{
|
||||
Format: "{{.Image}}",
|
||||
Output: out,
|
||||
},
|
||||
Size: true,
|
||||
},
|
||||
"",
|
||||
},
|
||||
{
|
||||
ContainerContext{
|
||||
Context: Context{
|
||||
Format: "table {{.Image}}",
|
||||
Output: out,
|
||||
},
|
||||
Size: true,
|
||||
},
|
||||
"IMAGE SIZE\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, context := range contexts {
|
||||
context.context.Containers = containers
|
||||
context.context.Write()
|
||||
actual := out.String()
|
||||
if actual != context.expected {
|
||||
t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
|
||||
}
|
||||
// Clean buffer
|
||||
out.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageContextWrite(t *testing.T) {
|
||||
unixTime := time.Now().AddDate(0, 0, -1).Unix()
|
||||
expectedTime := time.Unix(unixTime, 0).String()
|
||||
|
||||
contexts := []struct {
|
||||
context ImageContext
|
||||
expected string
|
||||
}{
|
||||
// Errors
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "{{InvalidFunction}}",
|
||||
},
|
||||
},
|
||||
`Template parsing error: template: :1: function "InvalidFunction" not defined
|
||||
`,
|
||||
},
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "{{nil}}",
|
||||
},
|
||||
},
|
||||
`Template parsing error: template: :1:2: executing "" at <nil>: nil is not a command
|
||||
`,
|
||||
},
|
||||
// Table Format
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "table",
|
||||
},
|
||||
},
|
||||
`REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
image tag1 imageID1 24 hours ago 0 B
|
||||
image <none> imageID1 24 hours ago 0 B
|
||||
image tag2 imageID2 24 hours ago 0 B
|
||||
<none> <none> imageID3 24 hours ago 0 B
|
||||
`,
|
||||
},
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "table {{.Repository}}",
|
||||
},
|
||||
},
|
||||
"REPOSITORY\nimage\nimage\nimage\n<none>\n",
|
||||
},
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "table {{.Repository}}",
|
||||
},
|
||||
Digest: true,
|
||||
},
|
||||
`REPOSITORY DIGEST
|
||||
image <none>
|
||||
image sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf
|
||||
image <none>
|
||||
<none> <none>
|
||||
`,
|
||||
},
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "table {{.Repository}}",
|
||||
Quiet: true,
|
||||
},
|
||||
},
|
||||
"REPOSITORY\nimage\nimage\nimage\n<none>\n",
|
||||
},
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "table",
|
||||
Quiet: true,
|
||||
},
|
||||
},
|
||||
"imageID1\nimageID1\nimageID2\nimageID3\n",
|
||||
},
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "table",
|
||||
Quiet: false,
|
||||
},
|
||||
Digest: true,
|
||||
},
|
||||
`REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
|
||||
image tag1 <none> imageID1 24 hours ago 0 B
|
||||
image <none> sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf imageID1 24 hours ago 0 B
|
||||
image tag2 <none> imageID2 24 hours ago 0 B
|
||||
<none> <none> <none> imageID3 24 hours ago 0 B
|
||||
`,
|
||||
},
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "table",
|
||||
Quiet: true,
|
||||
},
|
||||
Digest: true,
|
||||
},
|
||||
"imageID1\nimageID1\nimageID2\nimageID3\n",
|
||||
},
|
||||
// Raw Format
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "raw",
|
||||
},
|
||||
},
|
||||
fmt.Sprintf(`repository: image
|
||||
tag: tag1
|
||||
image_id: imageID1
|
||||
created_at: %s
|
||||
virtual_size: 0 B
|
||||
|
||||
repository: image
|
||||
tag: <none>
|
||||
image_id: imageID1
|
||||
created_at: %s
|
||||
virtual_size: 0 B
|
||||
|
||||
repository: image
|
||||
tag: tag2
|
||||
image_id: imageID2
|
||||
created_at: %s
|
||||
virtual_size: 0 B
|
||||
|
||||
repository: <none>
|
||||
tag: <none>
|
||||
image_id: imageID3
|
||||
created_at: %s
|
||||
virtual_size: 0 B
|
||||
|
||||
`, expectedTime, expectedTime, expectedTime, expectedTime),
|
||||
},
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "raw",
|
||||
},
|
||||
Digest: true,
|
||||
},
|
||||
fmt.Sprintf(`repository: image
|
||||
tag: tag1
|
||||
digest: <none>
|
||||
image_id: imageID1
|
||||
created_at: %s
|
||||
virtual_size: 0 B
|
||||
|
||||
repository: image
|
||||
tag: <none>
|
||||
digest: sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf
|
||||
image_id: imageID1
|
||||
created_at: %s
|
||||
virtual_size: 0 B
|
||||
|
||||
repository: image
|
||||
tag: tag2
|
||||
digest: <none>
|
||||
image_id: imageID2
|
||||
created_at: %s
|
||||
virtual_size: 0 B
|
||||
|
||||
repository: <none>
|
||||
tag: <none>
|
||||
digest: <none>
|
||||
image_id: imageID3
|
||||
created_at: %s
|
||||
virtual_size: 0 B
|
||||
|
||||
`, expectedTime, expectedTime, expectedTime, expectedTime),
|
||||
},
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "raw",
|
||||
Quiet: true,
|
||||
},
|
||||
},
|
||||
`image_id: imageID1
|
||||
image_id: imageID1
|
||||
image_id: imageID2
|
||||
image_id: imageID3
|
||||
`,
|
||||
},
|
||||
// Custom Format
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "{{.Repository}}",
|
||||
},
|
||||
},
|
||||
"image\nimage\nimage\n<none>\n",
|
||||
},
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "{{.Repository}}",
|
||||
},
|
||||
Digest: true,
|
||||
},
|
||||
"image\nimage\nimage\n<none>\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, context := range contexts {
|
||||
images := []types.Image{
|
||||
{ID: "imageID1", RepoTags: []string{"image:tag1"}, RepoDigests: []string{"image@sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf"}, Created: unixTime},
|
||||
{ID: "imageID2", RepoTags: []string{"image:tag2"}, Created: unixTime},
|
||||
{ID: "imageID3", RepoTags: []string{"<none>:<none>"}, RepoDigests: []string{"<none>@<none>"}, Created: unixTime},
|
||||
}
|
||||
out := bytes.NewBufferString("")
|
||||
context.context.Output = out
|
||||
context.context.Images = images
|
||||
context.context.Write()
|
||||
actual := out.String()
|
||||
if actual != context.expected {
|
||||
t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
|
||||
}
|
||||
// Clean buffer
|
||||
out.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageContextWriteWithNoImage(t *testing.T) {
|
||||
out := bytes.NewBufferString("")
|
||||
images := []types.Image{}
|
||||
|
||||
contexts := []struct {
|
||||
context ImageContext
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "{{.Repository}}",
|
||||
Output: out,
|
||||
},
|
||||
},
|
||||
"",
|
||||
},
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "table {{.Repository}}",
|
||||
Output: out,
|
||||
},
|
||||
},
|
||||
"REPOSITORY\n",
|
||||
},
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "{{.Repository}}",
|
||||
Output: out,
|
||||
},
|
||||
Digest: true,
|
||||
},
|
||||
"",
|
||||
},
|
||||
{
|
||||
ImageContext{
|
||||
Context: Context{
|
||||
Format: "table {{.Repository}}",
|
||||
Output: out,
|
||||
},
|
||||
Digest: true,
|
||||
},
|
||||
"REPOSITORY DIGEST\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, context := range contexts {
|
||||
context.context.Images = images
|
||||
context.context.Write()
|
||||
actual := out.String()
|
||||
if actual != context.expected {
|
||||
t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
|
||||
}
|
||||
// Clean buffer
|
||||
out.Reset()
|
||||
}
|
||||
}
|
||||
533
vendor/github.com/hyperhq/hypercli/api/client/func.go
generated
vendored
533
vendor/github.com/hyperhq/hypercli/api/client/func.go
generated
vendored
@@ -1,533 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/docker/go-connections/nat"
|
||||
units "github.com/docker/go-units"
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hyper-api/types/container"
|
||||
"github.com/hyperhq/hyper-api/types/filters"
|
||||
"github.com/hyperhq/hyper-api/types/network"
|
||||
"github.com/hyperhq/hyper-api/types/strslice"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
ropts "github.com/hyperhq/hypercli/opts"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/pkg/signal"
|
||||
"github.com/hyperhq/hypercli/runconfig/opts"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// CmdFunc is the parent subcommand for all func commands
|
||||
//
|
||||
// Usage: docker func <COMMAND> [OPTIONS]
|
||||
func (cli *DockerCli) CmdFunc(args ...string) error {
|
||||
cmd := Cli.Subcmd("func", []string{"COMMAND [OPTIONS]"}, funcUsage(), false)
|
||||
cmd.Require(flag.Min, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
func funcUsage() string {
|
||||
funcCommands := [][]string{
|
||||
{"create", "Create a new function"},
|
||||
{"update", "Update a function"},
|
||||
{"ls", "Lists all functions"},
|
||||
{"rm", "Remove one or more function"},
|
||||
{"inspect", "Display detailed information on the given function"},
|
||||
{"call", "Call a function"},
|
||||
{"get", "Get the return of a function call"},
|
||||
{"logs", "Retrieve the logs of a function"},
|
||||
{"status", "Retrieve the status of a function"},
|
||||
}
|
||||
|
||||
help := "Commands:\n"
|
||||
|
||||
for _, cmd := range funcCommands {
|
||||
help += fmt.Sprintf(" %-25.25s%s\n", cmd[0], cmd[1])
|
||||
}
|
||||
|
||||
help += fmt.Sprintf("\nRun 'hyper func COMMAND --help' for more information on a command.")
|
||||
return help
|
||||
}
|
||||
|
||||
// CmdFuncCreate creates a new func with a given name
|
||||
//
|
||||
// Usage: hyper func create [OPTIONS] IMAGE [COMMAND]
|
||||
func (cli *DockerCli) CmdFuncCreate(args ...string) error {
|
||||
cmd := Cli.Subcmd("func create", []string{"IMAGE [COMMAND] [ARG...]"}, "Create a new function", false)
|
||||
var (
|
||||
flName = cmd.String([]string{"-name"}, "", "Function name")
|
||||
flContainerSize = cmd.String([]string{"-size"}, "s4", "The size of function containers to run the function (e.g. s1, s2, s3, s4, m1, m2, m3, l1, l2, l3)")
|
||||
flTimeout = cmd.Int([]string{"-timeout"}, 300, "The maximum execution duration of function call")
|
||||
|
||||
flEnv = ropts.NewListOpts(opts.ValidateEnv)
|
||||
flEnvFile = ropts.NewListOpts(nil)
|
||||
|
||||
flLabels = ropts.NewListOpts(opts.ValidateEnv)
|
||||
flLabelsFile = ropts.NewListOpts(nil)
|
||||
|
||||
flVolumesFrom = ropts.NewListOpts(nil)
|
||||
flNoAutoVolume = cmd.Bool([]string{"-noauto-volume"}, false, "Do not create volumes specified in image")
|
||||
|
||||
flPublish = ropts.NewListOpts(nil)
|
||||
flExpose = ropts.NewListOpts(nil)
|
||||
flPublishAll = cmd.Bool([]string{"P", "-publish-all"}, false, "Publish all exposed ports to random ports")
|
||||
|
||||
flEntrypoint = cmd.String([]string{"-entrypoint"}, "", "Overwrite the default ENTRYPOINT of the image")
|
||||
flWorkingDir = cmd.String([]string{"w", "-workdir"}, "", "Working directory inside the container")
|
||||
|
||||
flTty = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY")
|
||||
flLinks = ropts.NewListOpts(opts.ValidateLink)
|
||||
flSecurityGroups = ropts.NewListOpts(nil)
|
||||
flStopSignal = cmd.String([]string{"-stop-signal"}, signal.DefaultStopSignal, fmt.Sprintf("Signal to stop a container, %v by default", signal.DefaultStopSignal))
|
||||
flNetMode = cmd.String([]string{}, "bridge", "Connect containers to a network, only bridge is supported now")
|
||||
)
|
||||
cmd.Var(&flLabels, []string{"l", "-label"}, "Set meta data on a container")
|
||||
cmd.Var(&flLabelsFile, []string{"-label-file"}, "Read in a line delimited file of labels")
|
||||
cmd.Var(&flEnv, []string{"e", "-env"}, "Set environment variables")
|
||||
cmd.Var(&flEnvFile, []string{"-env-file"}, "Read in a file of environment variables")
|
||||
cmd.Var(&flSecurityGroups, []string{"-sg"}, "Security group for each container")
|
||||
cmd.Var(&flLinks, []string{"-link"}, "Add link to another container")
|
||||
cmd.Var(&flPublish, []string{"p", "-publish"}, "Publish a container's port(s) to the host")
|
||||
cmd.Var(&flExpose, []string{"-expose"}, "Expose a port or a range of ports")
|
||||
cmd.Var(&flVolumesFrom, []string{"-volumes-from"}, "Mount shared volumes from the specified container(s)")
|
||||
|
||||
cmd.Require(flag.Min, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
parsedArgs = cmd.Args()
|
||||
runCmd strslice.StrSlice
|
||||
entrypoint strslice.StrSlice
|
||||
image = cmd.Arg(0)
|
||||
)
|
||||
if len(parsedArgs) > 1 {
|
||||
runCmd = strslice.StrSlice(parsedArgs[1:])
|
||||
}
|
||||
if *flEntrypoint != "" {
|
||||
entrypoint = strslice.StrSlice{*flEntrypoint}
|
||||
}
|
||||
|
||||
// collect all the environment variables for the container
|
||||
envVariables, err := opts.ReadKVStrings(flEnvFile.GetAll(), flEnv.GetAll())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// collect all the labels for the container
|
||||
labels, err := opts.ReadKVStrings(flLabelsFile.GetAll(), flLabels.GetAll())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, sg := range flSecurityGroups.GetAll() {
|
||||
if sg == "" {
|
||||
continue
|
||||
}
|
||||
labels = append(labels, fmt.Sprintf("sh_hyper_sg_%s=yes", sg))
|
||||
}
|
||||
if *flNoAutoVolume {
|
||||
labels = append(labels, "sh_hyper_noauto_volume=true")
|
||||
}
|
||||
|
||||
ports, portBindings, err := nat.ParsePortSpecs(flPublish.GetAll())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Merge in exposed ports to the map of published ports
|
||||
for _, e := range flExpose.GetAll() {
|
||||
if strings.Contains(e, ":") {
|
||||
return fmt.Errorf("Invalid port format for --expose: %s", e)
|
||||
}
|
||||
//support two formats for expose, original format <portnum>/[<proto>] or <startport-endport>/[<proto>]
|
||||
proto, port := nat.SplitProtoPort(e)
|
||||
//parse the start and end port and create a sequence of ports to expose
|
||||
//if expose a port, the start and end port are the same
|
||||
start, end, err := nat.ParsePortRange(port)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Invalid range format for --expose: %s, error: %s", e, err)
|
||||
}
|
||||
for i := start; i <= end; i++ {
|
||||
p, err := nat.NewPort(proto, strconv.FormatUint(i, 10))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, exists := ports[p]; !exists {
|
||||
ports[p] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config := types.FuncConfig{
|
||||
Tty: *flTty,
|
||||
ExposedPorts: ports,
|
||||
Env: &envVariables,
|
||||
Cmd: runCmd,
|
||||
Image: image,
|
||||
Entrypoint: entrypoint,
|
||||
WorkingDir: *flWorkingDir,
|
||||
Labels: opts.ConvertKVStringsToMap(labels),
|
||||
StopSignal: *flStopSignal,
|
||||
}
|
||||
|
||||
hostConfig := types.FuncHostConfig{
|
||||
VolumesFrom: flVolumesFrom.GetAll(),
|
||||
PortBindings: portBindings,
|
||||
Links: flLinks.GetAll(),
|
||||
PublishAllPorts: *flPublishAll,
|
||||
NetworkMode: container.NetworkMode(*flNetMode),
|
||||
}
|
||||
networkingConfig := network.NetworkingConfig{
|
||||
EndpointsConfig: make(map[string]*network.EndpointSettings),
|
||||
}
|
||||
|
||||
if hostConfig.NetworkMode.IsUserDefined() && len(hostConfig.Links) > 0 {
|
||||
epConfig := networkingConfig.EndpointsConfig[string(hostConfig.NetworkMode)]
|
||||
if epConfig == nil {
|
||||
epConfig = &network.EndpointSettings{}
|
||||
}
|
||||
epConfig.Links = make([]string, len(hostConfig.Links))
|
||||
copy(epConfig.Links, hostConfig.Links)
|
||||
networkingConfig.EndpointsConfig[string(hostConfig.NetworkMode)] = epConfig
|
||||
}
|
||||
|
||||
fnOpts := types.Func{
|
||||
Name: *flName,
|
||||
ContainerSize: *flContainerSize,
|
||||
Timeout: *flTimeout,
|
||||
|
||||
Config: config,
|
||||
HostConfig: hostConfig,
|
||||
NetworkingConfig: networkingConfig,
|
||||
}
|
||||
|
||||
fn, err := cli.client.FuncCreate(context.Background(), fnOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cli.out, "%s is created with the address of https://%s.hyperfunc.io/call/%s/%s\n", fn.Name, cli.region, fn.Name, fn.UUID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdFuncUpdate updates a func with a given name
|
||||
//
|
||||
// Usage: hyper func update [OPTIONS] NAME
|
||||
func (cli *DockerCli) CmdFuncUpdate(args ...string) error {
|
||||
cmd := Cli.Subcmd("func update", []string{"NAME"}, "Update a function", false)
|
||||
var (
|
||||
flContainerSize = cmd.String([]string{"-size"}, "", "The size of function containers to run the funciton (e.g. s1, s2, s3, s4, m1, m2, m3, l1, l2, l3)")
|
||||
flEnv = ropts.NewListOpts(opts.ValidateEnv)
|
||||
flEnvFile = ropts.NewListOpts(nil)
|
||||
flRefresh = cmd.Bool([]string{"-refresh"}, false, "Whether to regenerate the uuid of function")
|
||||
flTimeout = cmd.String([]string{"-timeout"}, "", "The maximum execution duration of function call")
|
||||
)
|
||||
cmd.Var(&flEnv, []string{"e", "-env"}, "Set environment variables")
|
||||
cmd.Var(&flEnvFile, []string{"-env-file"}, "Read in a file of environment variables")
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := cmd.Arg(0)
|
||||
name = strings.Replace(name, "/", "", -1)
|
||||
|
||||
// collect all the environment variables for the container
|
||||
envVariables, err := opts.ReadKVStrings(flEnvFile.GetAll(), flEnv.GetAll())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, env := range envVariables {
|
||||
if env == "" {
|
||||
envVariables = []string{}
|
||||
break
|
||||
}
|
||||
}
|
||||
env := &envVariables
|
||||
if !cmd.IsSet("-env") && !cmd.IsSet("e") && !cmd.IsSet("-env-file") {
|
||||
env = nil
|
||||
}
|
||||
|
||||
timeout, _ := strconv.Atoi(*flTimeout)
|
||||
|
||||
fnOpts := types.Func{
|
||||
Name: name,
|
||||
ContainerSize: *flContainerSize,
|
||||
Refresh: *flRefresh,
|
||||
Timeout: timeout,
|
||||
Config: types.FuncConfig{
|
||||
Env: env,
|
||||
},
|
||||
}
|
||||
|
||||
fn, err := cli.client.FuncUpdate(context.Background(), name, fnOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cli.out, "%s\n", fn.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdFuncDelete deletes one or more funcs
|
||||
//
|
||||
// Usage: hyper func rm NAME [NAME...]
|
||||
func (cli *DockerCli) CmdFuncRm(args ...string) error {
|
||||
cmd := Cli.Subcmd("func rm", []string{"NAME [NAME...]"}, "Remove one or more function", false)
|
||||
cmd.Require(flag.Min, 1)
|
||||
if err := cmd.ParseFlags(args, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
status := 0
|
||||
for _, name := range cmd.Args() {
|
||||
name = strings.Replace(name, "/", "", -1)
|
||||
if err := cli.client.FuncDelete(context.Background(), name); err != nil {
|
||||
fmt.Fprintf(cli.err, "%s\n", err)
|
||||
status = 1
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(cli.out, "%s\n", name)
|
||||
}
|
||||
if status != 0 {
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdFuncLs lists all the funcs
|
||||
//
|
||||
// Usage: hyper func ls [OPTIONS]
|
||||
func (cli *DockerCli) CmdFuncLs(args ...string) error {
|
||||
cmd := Cli.Subcmd("func ls", nil, "Lists all functions", true)
|
||||
|
||||
flFilter := ropts.NewListOpts(nil)
|
||||
cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided")
|
||||
|
||||
cmd.Require(flag.Exact, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Consolidate all filter flags, and sanity check them early.
|
||||
// They'll get process after get response from server.
|
||||
funcFilterArgs := filters.NewArgs()
|
||||
for _, f := range flFilter.GetAll() {
|
||||
if funcFilterArgs, err = filters.ParseFlag(f, funcFilterArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
options := types.FuncListOptions{
|
||||
Filters: funcFilterArgs,
|
||||
}
|
||||
|
||||
fns, err := cli.client.FuncList(context.Background(), options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
||||
fmt.Fprintf(w, "NAME\tSIZE\tIMAGE\tCOMMAND\tCREATED\tUUID\n")
|
||||
for _, fn := range fns {
|
||||
created := units.HumanDuration(time.Now().UTC().Sub(fn.Created)) + " ago"
|
||||
command := strings.Join([]string(fn.Config.Cmd), " ")
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\n", fn.Name, fn.ContainerSize, fn.Config.Image, command, created, fn.UUID)
|
||||
}
|
||||
w.Flush()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdFuncInspect
|
||||
//
|
||||
// Usage: docker func inspect [OPTIONS] NAME [NAME...]
|
||||
func (cli *DockerCli) CmdFuncInspect(args ...string) error {
|
||||
cmd := Cli.Subcmd("func inspect", []string{"NAME [NAME...]"}, "Display detailed information on the given function", true)
|
||||
tmplStr := cmd.String([]string{"f", "-format"}, "", "Format the output using the given go template")
|
||||
|
||||
cmd.Require(flag.Min, 1)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
inspectSearcher := func(name string) (interface{}, []byte, error) {
|
||||
name = strings.Replace(name, "/", "", -1)
|
||||
i, err := cli.client.FuncInspect(ctx, name)
|
||||
return i, nil, err
|
||||
}
|
||||
|
||||
return cli.inspectElements(*tmplStr, cmd.Args(), inspectSearcher)
|
||||
}
|
||||
|
||||
// CmdFuncCall call a func
|
||||
//
|
||||
// Usage: hyper func call NAME
|
||||
func (cli *DockerCli) CmdFuncCall(args ...string) error {
|
||||
cmd := Cli.Subcmd("func call", []string{"NAME"}, "Call a function", false)
|
||||
sync := cmd.Bool([]string{"-sync"}, false, "Block until the call is completed")
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
if err := cmd.ParseFlags(args, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := cmd.Arg(0)
|
||||
name = strings.Replace(name, "/", "", -1)
|
||||
|
||||
var stdin io.Reader
|
||||
if fi, err := os.Stdin.Stat(); err == nil {
|
||||
if fi.Mode()&os.ModeNamedPipe != 0 {
|
||||
stdin = bufio.NewReader(os.Stdin)
|
||||
}
|
||||
}
|
||||
|
||||
body, err := cli.client.FuncCall(context.Background(), cli.region, name, stdin, *sync)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer body.Close()
|
||||
|
||||
if *sync {
|
||||
_, err = io.Copy(cli.out, body)
|
||||
return err
|
||||
}
|
||||
|
||||
var ret types.FuncCallResponse
|
||||
err = json.NewDecoder(body).Decode(&ret)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cli.out, "CallId: %s\n", ret.CallId)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdFuncGet Get the return of a func call
|
||||
//
|
||||
// Usage: hyper func get [OPTIONS] CALL_ID
|
||||
func (cli *DockerCli) CmdFuncGet(args ...string) error {
|
||||
cmd := Cli.Subcmd("func get", []string{"CALL_ID"}, "Get the return of a function call", false)
|
||||
wait := cmd.Bool([]string{"-wait"}, false, "Block until the call is completed")
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
if err := cmd.ParseFlags(args, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
callId := cmd.Arg(0)
|
||||
|
||||
body, err := cli.client.FuncGet(context.Background(), cli.region, callId, *wait)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer body.Close()
|
||||
|
||||
_, err = io.Copy(cli.out, body)
|
||||
return err
|
||||
}
|
||||
|
||||
// CmdFuncLogs Get the return of a func call
|
||||
//
|
||||
// Usage: hyper func get [OPTIONS] NAME
|
||||
func (cli *DockerCli) CmdFuncLogs(args ...string) error {
|
||||
cmd := Cli.Subcmd("func logs", []string{"NAME"}, "Retrieve the logs of a function", false)
|
||||
|
||||
follow := cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
|
||||
tail := cmd.String([]string{"-tail"}, "all", "Number of lines to show from the end of the logs")
|
||||
callId := cmd.String([]string{"-callid"}, "", "Only retrieve specific logs of CallId")
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
if err := cmd.ParseFlags(args, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := cmd.Arg(0)
|
||||
name = strings.Replace(name, "/", "", -1)
|
||||
|
||||
reader, err := cli.client.FuncLogs(context.Background(), cli.region, name, *callId, *follow, *tail)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer reader.Close()
|
||||
dec := json.NewDecoder(reader)
|
||||
for {
|
||||
var log types.FuncLogsResponse
|
||||
err := dec.Decode(&log)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
if log.Event != "" {
|
||||
logTime := log.Time.Local().Format("2006-01-02T15:04:05Z")
|
||||
if log.Event == "CALL" {
|
||||
fmt.Fprintf(
|
||||
cli.out, "%s [%s] CallId: %s, ShortStdin: %s\n",
|
||||
logTime, log.Event, log.CallId, log.ShortStdin,
|
||||
)
|
||||
} else if log.Event == "FINISHED" {
|
||||
fmt.Fprintf(
|
||||
cli.out, "%s [%s] CallId: %s, ShortStdout: %s, ShortStderr: %s\n",
|
||||
logTime, log.Event, log.CallId, log.ShortStdout, log.ShortStderr,
|
||||
)
|
||||
} else if log.Event == "FAILED" {
|
||||
fmt.Fprintf(
|
||||
cli.out, "%s [%s] CallId: %s, Message: %s\n",
|
||||
logTime, log.Event, log.CallId, log.Message,
|
||||
)
|
||||
} else {
|
||||
fmt.Fprintf(
|
||||
cli.out, "%s [%s] CallId: %s\n",
|
||||
logTime, log.Event, log.CallId,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CmdFuncStatus Status the return of a func call
|
||||
//
|
||||
// Usage: hyper func status [OPTIONS] NAME
|
||||
func (cli *DockerCli) CmdFuncStatus(args ...string) error {
|
||||
cmd := Cli.Subcmd("func status", []string{"NAME"}, "Retrieve the status of a function", false)
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
if err := cmd.ParseFlags(args, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := cmd.Arg(0)
|
||||
name = strings.Replace(name, "/", "", -1)
|
||||
|
||||
status, err := cli.client.FuncStatus(context.Background(), cli.region, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
||||
fmt.Fprintf(w, "TOTAL\tPENDING\tRUNNING\tFINISHED\tFAILED\n")
|
||||
fmt.Fprintf(w, "%d\t%d\t%d\t%d\t%d\n", status.Total, status.Pending, status.Running, status.Finished, status.Failed)
|
||||
w.Flush()
|
||||
|
||||
return nil
|
||||
}
|
||||
56
vendor/github.com/hyperhq/hypercli/api/client/hijack.go
generated
vendored
56
vendor/github.com/hyperhq/hypercli/api/client/hijack.go
generated
vendored
@@ -1,56 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hypercli/pkg/stdcopy"
|
||||
)
|
||||
|
||||
func (cli *DockerCli) holdHijackedConnection(tty bool, inputStream io.ReadCloser, outputStream, errorStream io.Writer, resp types.HijackedResponse) error {
|
||||
var err error
|
||||
receiveStdout := make(chan error, 1)
|
||||
if outputStream != nil || errorStream != nil {
|
||||
go func() {
|
||||
// When TTY is ON, use regular copy
|
||||
if tty && outputStream != nil {
|
||||
_, err = io.Copy(outputStream, resp.Reader)
|
||||
} else {
|
||||
_, err = stdcopy.StdCopy(outputStream, errorStream, resp.Reader)
|
||||
}
|
||||
logrus.Debugf("[hijack] End of stdout")
|
||||
receiveStdout <- err
|
||||
}()
|
||||
}
|
||||
|
||||
stdinDone := make(chan struct{})
|
||||
go func() {
|
||||
if inputStream != nil {
|
||||
io.Copy(resp.Conn, inputStream)
|
||||
logrus.Debugf("[hijack] End of stdin")
|
||||
}
|
||||
|
||||
if err := resp.CloseWrite(); err != nil {
|
||||
logrus.Debugf("Couldn't send EOF: %s", err)
|
||||
}
|
||||
close(stdinDone)
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-receiveStdout:
|
||||
if err != nil {
|
||||
logrus.Debugf("Error receiveStdout: %s", err)
|
||||
return err
|
||||
}
|
||||
case <-stdinDone:
|
||||
if outputStream != nil || errorStream != nil {
|
||||
if err := <-receiveStdout; err != nil {
|
||||
logrus.Debugf("Error receiveStdout: %s", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
76
vendor/github.com/hyperhq/hypercli/api/client/history.go
generated
vendored
76
vendor/github.com/hyperhq/hypercli/api/client/history.go
generated
vendored
@@ -1,76 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/pkg/stringid"
|
||||
"github.com/hyperhq/hypercli/pkg/stringutils"
|
||||
)
|
||||
|
||||
// CmdHistory shows the history of an image.
|
||||
//
|
||||
// Usage: docker history [OPTIONS] IMAGE
|
||||
func (cli *DockerCli) CmdHistory(args ...string) error {
|
||||
cmd := Cli.Subcmd("history", []string{"IMAGE"}, Cli.DockerCommands["history"].Description, true)
|
||||
human := cmd.Bool([]string{"H", "-human"}, true, "Print sizes and dates in human readable format")
|
||||
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
|
||||
noTrunc := cmd.Bool([]string{"-no-trunc"}, false, "Don't truncate output")
|
||||
cmd.Require(flag.Exact, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
history, err := cli.client.ImageHistory(context.Background(), cmd.Arg(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
||||
|
||||
if *quiet {
|
||||
for _, entry := range history {
|
||||
if *noTrunc {
|
||||
fmt.Fprintf(w, "%s\n", entry.ID)
|
||||
} else {
|
||||
fmt.Fprintf(w, "%s\n", stringid.TruncateID(entry.ID))
|
||||
}
|
||||
}
|
||||
w.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
var imageID string
|
||||
var createdBy string
|
||||
var created string
|
||||
var size string
|
||||
|
||||
fmt.Fprintln(w, "IMAGE\tCREATED\tCREATED BY\tSIZE\tCOMMENT")
|
||||
for _, entry := range history {
|
||||
imageID = entry.ID
|
||||
createdBy = strings.Replace(entry.CreatedBy, "\t", " ", -1)
|
||||
if *noTrunc == false {
|
||||
createdBy = stringutils.Truncate(createdBy, 45)
|
||||
imageID = stringid.TruncateID(entry.ID)
|
||||
}
|
||||
|
||||
if *human {
|
||||
created = units.HumanDuration(time.Now().UTC().Sub(time.Unix(entry.Created, 0))) + " ago"
|
||||
size = units.HumanSize(float64(entry.Size))
|
||||
} else {
|
||||
created = time.Unix(entry.Created, 0).Format(time.RFC3339)
|
||||
size = strconv.FormatInt(entry.Size, 10)
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", imageID, created, createdBy, size, entry.Comment)
|
||||
}
|
||||
w.Flush()
|
||||
return nil
|
||||
}
|
||||
80
vendor/github.com/hyperhq/hypercli/api/client/images.go
generated
vendored
80
vendor/github.com/hyperhq/hypercli/api/client/images.go
generated
vendored
@@ -1,80 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hyper-api/types/filters"
|
||||
"github.com/hyperhq/hypercli/api/client/formatter"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/opts"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// CmdImages lists the images in a specified repository, or all top-level images if no repository is specified.
|
||||
//
|
||||
// Usage: docker images [OPTIONS] [REPOSITORY]
|
||||
func (cli *DockerCli) CmdImages(args ...string) error {
|
||||
cmd := Cli.Subcmd("images", []string{"[REPOSITORY[:TAG]]"}, Cli.DockerCommands["images"].Description, true)
|
||||
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only show numeric IDs")
|
||||
all := cmd.Bool([]string{"a", "-all"}, false, "Show all images (default hides intermediate images)")
|
||||
noTrunc := cmd.Bool([]string{"-no-trunc"}, false, "Don't truncate output")
|
||||
showDigests := cmd.Bool([]string{"-digests"}, false, "Show digests")
|
||||
format := cmd.String([]string{"-format"}, "", "Pretty-print images using a Go template")
|
||||
|
||||
flFilter := opts.NewListOpts(nil)
|
||||
cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided")
|
||||
cmd.Require(flag.Max, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
// Consolidate all filter flags, and sanity check them early.
|
||||
// They'll get process in the daemon/server.
|
||||
imageFilterArgs := filters.NewArgs()
|
||||
for _, f := range flFilter.GetAll() {
|
||||
var err error
|
||||
imageFilterArgs, err = filters.ParseFlag(f, imageFilterArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var matchName string
|
||||
if cmd.NArg() == 1 {
|
||||
matchName = cmd.Arg(0)
|
||||
}
|
||||
|
||||
options := types.ImageListOptions{
|
||||
MatchName: matchName,
|
||||
All: *all,
|
||||
Filters: imageFilterArgs,
|
||||
}
|
||||
|
||||
images, err := cli.client.ImageList(context.Background(), options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f := *format
|
||||
if len(f) == 0 {
|
||||
if len(cli.ImagesFormat()) > 0 && !*quiet {
|
||||
f = cli.ImagesFormat()
|
||||
} else {
|
||||
f = "table"
|
||||
}
|
||||
}
|
||||
|
||||
imagesCtx := formatter.ImageContext{
|
||||
Context: formatter.Context{
|
||||
Output: cli.out,
|
||||
Format: f,
|
||||
Quiet: *quiet,
|
||||
Trunc: !*noTrunc,
|
||||
},
|
||||
Digest: *showDigests,
|
||||
Images: images,
|
||||
}
|
||||
|
||||
imagesCtx.Write()
|
||||
|
||||
return nil
|
||||
}
|
||||
75
vendor/github.com/hyperhq/hypercli/api/client/import.go
generated
vendored
75
vendor/github.com/hyperhq/hypercli/api/client/import.go
generated
vendored
@@ -1,75 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/opts"
|
||||
"github.com/hyperhq/hypercli/pkg/jsonmessage"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/pkg/urlutil"
|
||||
)
|
||||
|
||||
// CmdImport creates an empty filesystem image, imports the contents of the tarball into the image, and optionally tags the image.
|
||||
//
|
||||
// The URL argument is the address of a tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) file or a path to local file relative to docker client. If the URL is '-', then the tar file is read from STDIN.
|
||||
//
|
||||
// Usage: docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
|
||||
func (cli *DockerCli) Import(args ...string) error {
|
||||
cmd := Cli.Subcmd("import", []string{"file|URL|- [REPOSITORY[:TAG]]"}, Cli.DockerCommands["import"].Description, true)
|
||||
flChanges := opts.NewListOpts(nil)
|
||||
cmd.Var(&flChanges, []string{"c", "-change"}, "Apply Dockerfile instruction to the created image")
|
||||
message := cmd.String([]string{"m", "-message"}, "", "Set commit message for imported image")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
var (
|
||||
in io.Reader
|
||||
tag string
|
||||
src = cmd.Arg(0)
|
||||
srcName = src
|
||||
ref = cmd.Arg(1)
|
||||
changes = flChanges.GetAll()
|
||||
)
|
||||
|
||||
if cmd.NArg() == 3 {
|
||||
fmt.Fprintf(cli.err, "[DEPRECATED] The format 'file|URL|- [REPOSITORY [TAG]]' has been deprecated. Please use file|URL|- [REPOSITORY[:TAG]]\n")
|
||||
tag = cmd.Arg(2)
|
||||
}
|
||||
|
||||
if src == "-" {
|
||||
in = cli.in
|
||||
} else if !urlutil.IsURL(src) {
|
||||
srcName = "-"
|
||||
file, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
in = file
|
||||
}
|
||||
source := types.ImageImportSource{
|
||||
Source: in,
|
||||
SourceName: srcName,
|
||||
}
|
||||
|
||||
options := types.ImageImportOptions{
|
||||
Message: *message,
|
||||
Tag: tag,
|
||||
Changes: changes,
|
||||
}
|
||||
|
||||
responseBody, err := cli.client.ImageImport(context.Background(), source, ref, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer responseBody.Close()
|
||||
|
||||
return jsonmessage.DisplayJSONMessagesStream(responseBody, cli.out, cli.outFd, cli.isTerminalOut, nil)
|
||||
}
|
||||
153
vendor/github.com/hyperhq/hypercli/api/client/info.go
generated
vendored
153
vendor/github.com/hyperhq/hypercli/api/client/info.go
generated
vendored
@@ -1,153 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/pkg/ioutils"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/utils"
|
||||
)
|
||||
|
||||
// CmdInfo displays system-wide information.
|
||||
//
|
||||
// Usage: docker info
|
||||
func (cli *DockerCli) CmdInfo(args ...string) error {
|
||||
cmd := Cli.Subcmd("info", nil, Cli.DockerCommands["info"].Description, true)
|
||||
cmd.Require(flag.Exact, 0)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
info, err := cli.client.Info(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(cli.out, "Containers: %d\n", info.Containers)
|
||||
fmt.Fprintf(cli.out, " Running: %d\n", info.ContainersRunning)
|
||||
fmt.Fprintf(cli.out, " Paused: %d\n", info.ContainersPaused)
|
||||
fmt.Fprintf(cli.out, " Stopped: %d\n", info.ContainersStopped)
|
||||
fmt.Fprintf(cli.out, "Images: %d\n", info.Images)
|
||||
ioutils.FprintfIfNotEmpty(cli.out, "Server Version: %s\n", info.ServerVersion)
|
||||
ioutils.FprintfIfNotEmpty(cli.out, "Storage Driver: %s\n", info.Driver)
|
||||
if info.DriverStatus != nil {
|
||||
for _, pair := range info.DriverStatus {
|
||||
fmt.Fprintf(cli.out, " %s: %s\n", pair[0], pair[1])
|
||||
|
||||
// print a warning if devicemapper is using a loopback file
|
||||
if pair[0] == "Data loop file" {
|
||||
fmt.Fprintln(cli.err, " WARNING: Usage of loopback devices is strongly discouraged for production use. Either use `--storage-opt dm.thinpooldev` or use `--storage-opt dm.no_warn_on_loop_devices=true` to suppress this warning.")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if info.SystemStatus != nil {
|
||||
for _, pair := range info.SystemStatus {
|
||||
fmt.Fprintf(cli.out, "%s: %s\n", pair[0], pair[1])
|
||||
}
|
||||
}
|
||||
ioutils.FprintfIfNotEmpty(cli.out, "Execution Driver: %s\n", info.ExecutionDriver)
|
||||
ioutils.FprintfIfNotEmpty(cli.out, "Logging Driver: %s\n", info.LoggingDriver)
|
||||
|
||||
fmt.Fprintf(cli.out, "Plugins: \n")
|
||||
fmt.Fprintf(cli.out, " Volume:")
|
||||
fmt.Fprintf(cli.out, " %s", strings.Join(info.Plugins.Volume, " "))
|
||||
fmt.Fprintf(cli.out, "\n")
|
||||
fmt.Fprintf(cli.out, " Network:")
|
||||
fmt.Fprintf(cli.out, " %s", strings.Join(info.Plugins.Network, " "))
|
||||
fmt.Fprintf(cli.out, "\n")
|
||||
|
||||
if len(info.Plugins.Authorization) != 0 {
|
||||
fmt.Fprintf(cli.out, " Authorization:")
|
||||
fmt.Fprintf(cli.out, " %s", strings.Join(info.Plugins.Authorization, " "))
|
||||
fmt.Fprintf(cli.out, "\n")
|
||||
}
|
||||
|
||||
ioutils.FprintfIfNotEmpty(cli.out, "Kernel Version: %s\n", info.KernelVersion)
|
||||
ioutils.FprintfIfNotEmpty(cli.out, "Operating System: %s\n", info.OperatingSystem)
|
||||
ioutils.FprintfIfNotEmpty(cli.out, "OSType: %s\n", info.OSType)
|
||||
ioutils.FprintfIfNotEmpty(cli.out, "Architecture: %s\n", info.Architecture)
|
||||
fmt.Fprintf(cli.out, "CPUs: %d\n", info.NCPU)
|
||||
fmt.Fprintf(cli.out, "Total Memory: %s\n", units.BytesSize(float64(info.MemTotal)))
|
||||
ioutils.FprintfIfNotEmpty(cli.out, "Name: %s\n", info.Name)
|
||||
ioutils.FprintfIfNotEmpty(cli.out, "ID: %s\n", info.ID)
|
||||
|
||||
fmt.Fprintf(cli.out, "Debug mode (client): %v\n", utils.IsDebugEnabled())
|
||||
fmt.Fprintf(cli.out, "Debug mode (server): %v\n", info.Debug)
|
||||
|
||||
if info.Debug {
|
||||
fmt.Fprintf(cli.out, " File Descriptors: %d\n", info.NFd)
|
||||
fmt.Fprintf(cli.out, " Goroutines: %d\n", info.NGoroutines)
|
||||
fmt.Fprintf(cli.out, " System Time: %s\n", info.SystemTime)
|
||||
fmt.Fprintf(cli.out, " EventsListeners: %d\n", info.NEventsListener)
|
||||
fmt.Fprintf(cli.out, " Docker Root Dir: %s\n", info.DockerRootDir)
|
||||
}
|
||||
|
||||
ioutils.FprintfIfNotEmpty(cli.out, "Http Proxy: %s\n", info.HTTPProxy)
|
||||
ioutils.FprintfIfNotEmpty(cli.out, "Https Proxy: %s\n", info.HTTPSProxy)
|
||||
ioutils.FprintfIfNotEmpty(cli.out, "No Proxy: %s\n", info.NoProxy)
|
||||
|
||||
if info.IndexServerAddress != "" {
|
||||
u := cli.configFile.AuthConfigs[info.IndexServerAddress].Username
|
||||
if len(u) > 0 {
|
||||
fmt.Fprintf(cli.out, "Username: %v\n", u)
|
||||
fmt.Fprintf(cli.out, "Registry: %v\n", info.IndexServerAddress)
|
||||
}
|
||||
}
|
||||
|
||||
// Only output these warnings if the server does not support these features
|
||||
// and the client is in debug mode
|
||||
if utils.IsDebugEnabled() && info.OSType != "windows" {
|
||||
if !info.MemoryLimit {
|
||||
fmt.Fprintln(cli.err, "WARNING: No memory limit support")
|
||||
}
|
||||
if !info.SwapLimit {
|
||||
fmt.Fprintln(cli.err, "WARNING: No swap limit support")
|
||||
}
|
||||
if !info.OomKillDisable {
|
||||
fmt.Fprintln(cli.err, "WARNING: No oom kill disable support")
|
||||
}
|
||||
if !info.CPUCfsQuota {
|
||||
fmt.Fprintln(cli.err, "WARNING: No cpu cfs quota support")
|
||||
}
|
||||
if !info.CPUCfsPeriod {
|
||||
fmt.Fprintln(cli.err, "WARNING: No cpu cfs period support")
|
||||
}
|
||||
if !info.CPUShares {
|
||||
fmt.Fprintln(cli.err, "WARNING: No cpu shares support")
|
||||
}
|
||||
if !info.CPUSet {
|
||||
fmt.Fprintln(cli.err, "WARNING: No cpuset support")
|
||||
}
|
||||
if !info.IPv4Forwarding {
|
||||
fmt.Fprintln(cli.err, "WARNING: IPv4 forwarding is disabled")
|
||||
}
|
||||
if !info.BridgeNfIptables {
|
||||
fmt.Fprintln(cli.err, "WARNING: bridge-nf-call-iptables is disabled")
|
||||
}
|
||||
if !info.BridgeNfIP6tables {
|
||||
fmt.Fprintln(cli.err, "WARNING: bridge-nf-call-ip6tables is disabled")
|
||||
}
|
||||
}
|
||||
|
||||
if info.Labels != nil {
|
||||
fmt.Fprintln(cli.out, "Labels:")
|
||||
for _, attribute := range info.Labels {
|
||||
fmt.Fprintf(cli.out, " %s\n", attribute)
|
||||
}
|
||||
}
|
||||
|
||||
ioutils.FprintfIfTrue(cli.out, "Experimental: %v\n", info.ExperimentalBuild)
|
||||
if info.ClusterStore != "" {
|
||||
fmt.Fprintf(cli.out, "Cluster store: %s\n", info.ClusterStore)
|
||||
}
|
||||
|
||||
if info.ClusterAdvertise != "" {
|
||||
fmt.Fprintf(cli.out, "Cluster advertise: %s\n", info.ClusterAdvertise)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
137
vendor/github.com/hyperhq/hypercli/api/client/inspect.go
generated
vendored
137
vendor/github.com/hyperhq/hypercli/api/client/inspect.go
generated
vendored
@@ -1,137 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"text/template"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/hyperhq/hyper-api/client"
|
||||
"github.com/hyperhq/hypercli/api/client/inspect"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
var funcMap = template.FuncMap{
|
||||
"json": func(v interface{}) string {
|
||||
a, _ := json.Marshal(v)
|
||||
return string(a)
|
||||
},
|
||||
}
|
||||
|
||||
// CmdInspect displays low-level information on one or more containers or images.
|
||||
//
|
||||
// Usage: docker inspect [OPTIONS] CONTAINER|IMAGE [CONTAINER|IMAGE...]
|
||||
func (cli *DockerCli) CmdInspect(args ...string) error {
|
||||
cmd := Cli.Subcmd("inspect", []string{"CONTAINER|IMAGE [CONTAINER|IMAGE...]"}, Cli.DockerCommands["inspect"].Description, true)
|
||||
tmplStr := cmd.String([]string{"f", "-format"}, "", "Format the output using the given go template")
|
||||
inspectType := cmd.String([]string{"-type"}, "", "Return JSON for specified type, (e.g image or container)")
|
||||
size := cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes if the type is container")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
if *inspectType != "" && *inspectType != "container" && *inspectType != "image" {
|
||||
return fmt.Errorf("%q is not a valid value for --type", *inspectType)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
var elementSearcher inspectSearcher
|
||||
switch *inspectType {
|
||||
case "container":
|
||||
elementSearcher = cli.inspectContainers(ctx, *size)
|
||||
case "image":
|
||||
elementSearcher = cli.inspectImages(ctx, *size)
|
||||
default:
|
||||
elementSearcher = cli.inspectAll(ctx, *size)
|
||||
}
|
||||
|
||||
return cli.inspectElements(*tmplStr, cmd.Args(), elementSearcher)
|
||||
}
|
||||
|
||||
func (cli *DockerCli) inspectContainers(ctx context.Context, getSize bool) inspectSearcher {
|
||||
return func(ref string) (interface{}, []byte, error) {
|
||||
return cli.client.ContainerInspectWithRaw(ctx, ref, getSize)
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *DockerCli) inspectImages(ctx context.Context, getSize bool) inspectSearcher {
|
||||
return func(ref string) (interface{}, []byte, error) {
|
||||
return cli.client.ImageInspectWithRaw(ctx, ref, getSize)
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *DockerCli) inspectAll(ctx context.Context, getSize bool) inspectSearcher {
|
||||
return func(ref string) (interface{}, []byte, error) {
|
||||
c, rawContainer, err := cli.client.ContainerInspectWithRaw(ctx, ref, getSize)
|
||||
if err != nil {
|
||||
// Search for image with that id if a container doesn't exist.
|
||||
if client.IsErrContainerNotFound(err) {
|
||||
i, rawImage, err := cli.client.ImageInspectWithRaw(ctx, ref, getSize)
|
||||
if err != nil {
|
||||
if client.IsErrImageNotFound(err) {
|
||||
return nil, nil, fmt.Errorf("Error: No such image or container: %s", ref)
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
return i, rawImage, err
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
return c, rawContainer, err
|
||||
}
|
||||
}
|
||||
|
||||
type inspectSearcher func(ref string) (interface{}, []byte, error)
|
||||
|
||||
func (cli *DockerCli) inspectElements(tmplStr string, references []string, searchByReference inspectSearcher) error {
|
||||
elementInspector, err := cli.newInspectorWithTemplate(tmplStr)
|
||||
if err != nil {
|
||||
return Cli.StatusError{StatusCode: 64, Status: err.Error()}
|
||||
}
|
||||
|
||||
var inspectErr error
|
||||
for _, ref := range references {
|
||||
element, raw, err := searchByReference(ref)
|
||||
if err != nil {
|
||||
inspectErr = err
|
||||
break
|
||||
}
|
||||
|
||||
if err := elementInspector.Inspect(element, raw); err != nil {
|
||||
inspectErr = err
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err := elementInspector.Flush(); err != nil {
|
||||
cli.inspectErrorStatus(err)
|
||||
}
|
||||
|
||||
if status := cli.inspectErrorStatus(inspectErr); status != 0 {
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) inspectErrorStatus(err error) (status int) {
|
||||
if err != nil {
|
||||
fmt.Fprintf(cli.err, "%s\n", err)
|
||||
status = 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *DockerCli) newInspectorWithTemplate(tmplStr string) (inspect.Inspector, error) {
|
||||
elementInspector := inspect.NewIndentedInspector(cli.out)
|
||||
if tmplStr != "" {
|
||||
tmpl, err := template.New("").Funcs(funcMap).Parse(tmplStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Template parsing error: %s", err)
|
||||
}
|
||||
elementInspector = inspect.NewTemplateInspector(cli.out, tmpl)
|
||||
}
|
||||
return elementInspector, nil
|
||||
}
|
||||
119
vendor/github.com/hyperhq/hypercli/api/client/inspect/inspector.go
generated
vendored
119
vendor/github.com/hyperhq/hypercli/api/client/inspect/inspector.go
generated
vendored
@@ -1,119 +0,0 @@
|
||||
package inspect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// Inspector defines an interface to implement to process elements
|
||||
type Inspector interface {
|
||||
Inspect(typedElement interface{}, rawElement []byte) error
|
||||
Flush() error
|
||||
}
|
||||
|
||||
// TemplateInspector uses a text template to inspect elements.
|
||||
type TemplateInspector struct {
|
||||
outputStream io.Writer
|
||||
buffer *bytes.Buffer
|
||||
tmpl *template.Template
|
||||
}
|
||||
|
||||
// NewTemplateInspector creates a new inspector with a template.
|
||||
func NewTemplateInspector(outputStream io.Writer, tmpl *template.Template) Inspector {
|
||||
return &TemplateInspector{
|
||||
outputStream: outputStream,
|
||||
buffer: new(bytes.Buffer),
|
||||
tmpl: tmpl,
|
||||
}
|
||||
}
|
||||
|
||||
// Inspect executes the inspect template.
|
||||
// It decodes the raw element into a map if the initial execution fails.
|
||||
// This allows docker cli to parse inspect structs injected with Swarm fields.
|
||||
func (i *TemplateInspector) Inspect(typedElement interface{}, rawElement []byte) error {
|
||||
buffer := new(bytes.Buffer)
|
||||
if err := i.tmpl.Execute(buffer, typedElement); err != nil {
|
||||
if rawElement == nil {
|
||||
return fmt.Errorf("Template parsing error: %v", err)
|
||||
}
|
||||
return i.tryRawInspectFallback(rawElement, err)
|
||||
}
|
||||
i.buffer.Write(buffer.Bytes())
|
||||
i.buffer.WriteByte('\n')
|
||||
return nil
|
||||
}
|
||||
|
||||
// Flush write the result of inspecting all elements into the output stream.
|
||||
func (i *TemplateInspector) Flush() error {
|
||||
if i.buffer.Len() == 0 {
|
||||
_, err := io.WriteString(i.outputStream, "\n")
|
||||
return err
|
||||
}
|
||||
_, err := io.Copy(i.outputStream, i.buffer)
|
||||
return err
|
||||
}
|
||||
|
||||
// IndentedInspector uses a buffer to stop the indented representation of an element.
|
||||
type IndentedInspector struct {
|
||||
outputStream io.Writer
|
||||
elements []interface{}
|
||||
rawElements [][]byte
|
||||
}
|
||||
|
||||
// NewIndentedInspector generates a new IndentedInspector.
|
||||
func NewIndentedInspector(outputStream io.Writer) Inspector {
|
||||
return &IndentedInspector{
|
||||
outputStream: outputStream,
|
||||
}
|
||||
}
|
||||
|
||||
// Inspect writes the raw element with an indented json format.
|
||||
func (i *IndentedInspector) Inspect(typedElement interface{}, rawElement []byte) error {
|
||||
if rawElement != nil {
|
||||
i.rawElements = append(i.rawElements, rawElement)
|
||||
} else {
|
||||
i.elements = append(i.elements, typedElement)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Flush write the result of inspecting all elements into the output stream.
|
||||
func (i *IndentedInspector) Flush() error {
|
||||
if len(i.elements) == 0 && len(i.rawElements) == 0 {
|
||||
_, err := io.WriteString(i.outputStream, "[]\n")
|
||||
return err
|
||||
}
|
||||
|
||||
var buffer io.Reader
|
||||
if len(i.rawElements) > 0 {
|
||||
bytesBuffer := new(bytes.Buffer)
|
||||
bytesBuffer.WriteString("[")
|
||||
for idx, r := range i.rawElements {
|
||||
bytesBuffer.Write(r)
|
||||
if idx < len(i.rawElements)-1 {
|
||||
bytesBuffer.WriteString(",")
|
||||
}
|
||||
}
|
||||
bytesBuffer.WriteString("]")
|
||||
indented := new(bytes.Buffer)
|
||||
if err := json.Indent(indented, bytesBuffer.Bytes(), "", " "); err != nil {
|
||||
return err
|
||||
}
|
||||
buffer = indented
|
||||
} else {
|
||||
b, err := json.MarshalIndent(i.elements, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buffer = bytes.NewReader(b)
|
||||
}
|
||||
|
||||
if _, err := io.Copy(i.outputStream, buffer); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := io.WriteString(i.outputStream, "\n")
|
||||
return err
|
||||
}
|
||||
40
vendor/github.com/hyperhq/hypercli/api/client/inspect/inspector_go14.go
generated
vendored
40
vendor/github.com/hyperhq/hypercli/api/client/inspect/inspector_go14.go
generated
vendored
@@ -1,40 +0,0 @@
|
||||
// +build !go1.5
|
||||
|
||||
package inspect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// tryeRawInspectFallback executes the inspect template with a raw interface.
|
||||
// This allows docker cli to parse inspect structs injected with Swarm fields.
|
||||
// Unfortunately, go 1.4 doesn't fail executing invalid templates when the input is an interface.
|
||||
// It doesn't allow to modify this behavior either, sending <no value> messages to the output.
|
||||
// We assume that the template is invalid when there is a <no value>, if the template was valid
|
||||
// we'd get <nil> or "" values. In that case we fail with the original error raised executing the
|
||||
// template with the typed input.
|
||||
func (i *TemplateInspector) tryRawInspectFallback(rawElement []byte, originalErr error) error {
|
||||
var raw interface{}
|
||||
buffer := new(bytes.Buffer)
|
||||
rdr := bytes.NewReader(rawElement)
|
||||
dec := json.NewDecoder(rdr)
|
||||
|
||||
if rawErr := dec.Decode(&raw); rawErr != nil {
|
||||
return fmt.Errorf("unable to read inspect data: %v", rawErr)
|
||||
}
|
||||
|
||||
if rawErr := i.tmpl.Execute(buffer, raw); rawErr != nil {
|
||||
return fmt.Errorf("Template parsing error: %v", rawErr)
|
||||
}
|
||||
|
||||
if strings.Contains(buffer.String(), "<no value>") {
|
||||
return fmt.Errorf("Template parsing error: %v", originalErr)
|
||||
}
|
||||
|
||||
i.buffer.Write(buffer.Bytes())
|
||||
i.buffer.WriteByte('\n')
|
||||
return nil
|
||||
}
|
||||
29
vendor/github.com/hyperhq/hypercli/api/client/inspect/inspector_go15.go
generated
vendored
29
vendor/github.com/hyperhq/hypercli/api/client/inspect/inspector_go15.go
generated
vendored
@@ -1,29 +0,0 @@
|
||||
// +build go1.5
|
||||
|
||||
package inspect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (i *TemplateInspector) tryRawInspectFallback(rawElement []byte, _ error) error {
|
||||
var raw interface{}
|
||||
buffer := new(bytes.Buffer)
|
||||
rdr := bytes.NewReader(rawElement)
|
||||
dec := json.NewDecoder(rdr)
|
||||
|
||||
if rawErr := dec.Decode(&raw); rawErr != nil {
|
||||
return fmt.Errorf("unable to read inspect data: %v", rawErr)
|
||||
}
|
||||
|
||||
tmplMissingKey := i.tmpl.Option("missingkey=error")
|
||||
if rawErr := tmplMissingKey.Execute(buffer, raw); rawErr != nil {
|
||||
return fmt.Errorf("Template parsing error: %v", rawErr)
|
||||
}
|
||||
|
||||
i.buffer.Write(buffer.Bytes())
|
||||
i.buffer.WriteByte('\n')
|
||||
return nil
|
||||
}
|
||||
220
vendor/github.com/hyperhq/hypercli/api/client/inspect/inspector_test.go
generated
vendored
220
vendor/github.com/hyperhq/hypercli/api/client/inspect/inspector_test.go
generated
vendored
@@ -1,220 +0,0 @@
|
||||
package inspect
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type testElement struct {
|
||||
DNS string `json:"Dns"`
|
||||
}
|
||||
|
||||
func TestTemplateInspectorDefault(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
tmpl, err := template.New("test").Parse("{{.DNS}}")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
i := NewTemplateInspector(b, tmpl)
|
||||
if err := i.Inspect(testElement{"0.0.0.0"}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := i.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if b.String() != "0.0.0.0\n" {
|
||||
t.Fatalf("Expected `0.0.0.0\\n`, got `%s`", b.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateInspectorEmpty(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
tmpl, err := template.New("test").Parse("{{.DNS}}")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
i := NewTemplateInspector(b, tmpl)
|
||||
|
||||
if err := i.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if b.String() != "\n" {
|
||||
t.Fatalf("Expected `\\n`, got `%s`", b.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateInspectorTemplateError(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
tmpl, err := template.New("test").Parse("{{.Foo}}")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
i := NewTemplateInspector(b, tmpl)
|
||||
|
||||
err = i.Inspect(testElement{"0.0.0.0"}, nil)
|
||||
if err == nil {
|
||||
t.Fatal("Expected error got nil")
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(err.Error(), "Template parsing error") {
|
||||
t.Fatalf("Expected template error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateInspectorRawFallback(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
tmpl, err := template.New("test").Parse("{{.Dns}}")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
i := NewTemplateInspector(b, tmpl)
|
||||
if err := i.Inspect(testElement{"0.0.0.0"}, []byte(`{"Dns": "0.0.0.0"}`)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := i.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if b.String() != "0.0.0.0\n" {
|
||||
t.Fatalf("Expected `0.0.0.0\\n`, got `%s`", b.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateInspectorRawFallbackError(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
tmpl, err := template.New("test").Parse("{{.Dns}}")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
i := NewTemplateInspector(b, tmpl)
|
||||
err = i.Inspect(testElement{"0.0.0.0"}, []byte(`{"Foo": "0.0.0.0"}`))
|
||||
if err == nil {
|
||||
t.Fatal("Expected error got nil")
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(err.Error(), "Template parsing error") {
|
||||
t.Fatalf("Expected template error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateInspectorMultiple(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
tmpl, err := template.New("test").Parse("{{.DNS}}")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
i := NewTemplateInspector(b, tmpl)
|
||||
|
||||
if err := i.Inspect(testElement{"0.0.0.0"}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := i.Inspect(testElement{"1.1.1.1"}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := i.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if b.String() != "0.0.0.0\n1.1.1.1\n" {
|
||||
t.Fatalf("Expected `0.0.0.0\\n1.1.1.1\\n`, got `%s`", b.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestIndentedInspectorDefault(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
i := NewIndentedInspector(b)
|
||||
if err := i.Inspect(testElement{"0.0.0.0"}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := i.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := `[
|
||||
{
|
||||
"Dns": "0.0.0.0"
|
||||
}
|
||||
]
|
||||
`
|
||||
if b.String() != expected {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expected, b.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestIndentedInspectorMultiple(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
i := NewIndentedInspector(b)
|
||||
if err := i.Inspect(testElement{"0.0.0.0"}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := i.Inspect(testElement{"1.1.1.1"}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := i.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := `[
|
||||
{
|
||||
"Dns": "0.0.0.0"
|
||||
},
|
||||
{
|
||||
"Dns": "1.1.1.1"
|
||||
}
|
||||
]
|
||||
`
|
||||
if b.String() != expected {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expected, b.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestIndentedInspectorEmpty(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
i := NewIndentedInspector(b)
|
||||
|
||||
if err := i.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := "[]\n"
|
||||
if b.String() != expected {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expected, b.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestIndentedInspectorRawElements(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
i := NewIndentedInspector(b)
|
||||
if err := i.Inspect(testElement{"0.0.0.0"}, []byte(`{"Dns": "0.0.0.0", "Node": "0"}`)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := i.Inspect(testElement{"1.1.1.1"}, []byte(`{"Dns": "1.1.1.1", "Node": "1"}`)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := i.Flush(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := `[
|
||||
{
|
||||
"Dns": "0.0.0.0",
|
||||
"Node": "0"
|
||||
},
|
||||
{
|
||||
"Dns": "1.1.1.1",
|
||||
"Node": "1"
|
||||
}
|
||||
]
|
||||
`
|
||||
if b.String() != expected {
|
||||
t.Fatalf("Expected `%s`, got `%s`", expected, b.String())
|
||||
}
|
||||
}
|
||||
35
vendor/github.com/hyperhq/hypercli/api/client/kill.go
generated
vendored
35
vendor/github.com/hyperhq/hypercli/api/client/kill.go
generated
vendored
@@ -1,35 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdKill kills one or more running container using SIGKILL or a specified signal.
|
||||
//
|
||||
// Usage: docker kill [OPTIONS] CONTAINER [CONTAINER...]
|
||||
func (cli *DockerCli) CmdKill(args ...string) error {
|
||||
cmd := Cli.Subcmd("kill", []string{"CONTAINER [CONTAINER...]"}, Cli.DockerCommands["kill"].Description, true)
|
||||
signal := cmd.String([]string{"s", "-signal"}, "KILL", "Signal to send to the container")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
var errs []string
|
||||
for _, name := range cmd.Args() {
|
||||
if err := cli.client.ContainerKill(context.Background(), name, *signal); err != nil {
|
||||
errs = append(errs, err.Error())
|
||||
} else {
|
||||
fmt.Fprintf(cli.out, "%s\n", name)
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("%s", strings.Join(errs, "\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
323
vendor/github.com/hyperhq/hypercli/api/client/load.go
generated
vendored
323
vendor/github.com/hyperhq/hypercli/api/client/load.go
generated
vendored
@@ -1,323 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/image"
|
||||
"github.com/hyperhq/hypercli/pkg/archive"
|
||||
"github.com/hyperhq/hypercli/pkg/jsonmessage"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/pkg/progress"
|
||||
"github.com/hyperhq/hypercli/pkg/streamformatter"
|
||||
"github.com/hyperhq/hypercli/pkg/symlink"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
const (
|
||||
unsupported = "Unsupported image version"
|
||||
)
|
||||
|
||||
type manifestItem struct {
|
||||
Config string
|
||||
RepoTags []string
|
||||
Layers []string
|
||||
}
|
||||
|
||||
type readCloser struct {
|
||||
io.Reader
|
||||
NeedClose io.ReadCloser
|
||||
}
|
||||
|
||||
func (rc readCloser) Close() error {
|
||||
return rc.NeedClose.Close()
|
||||
}
|
||||
|
||||
func safePath(base, path string) (string, error) {
|
||||
return symlink.FollowSymlinkInScope(filepath.Join(base, path), base)
|
||||
}
|
||||
|
||||
func removeExistLayers(tmpDir string, existLayers []string, layerPaths []string) error {
|
||||
keepLayerPaths := make(map[string]bool)
|
||||
for _, _layerPath := range layerPaths[len(existLayers):] {
|
||||
layerPath := filepath.Join(tmpDir, _layerPath)
|
||||
info, err := os.Lstat(layerPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||
if _realPath, err := filepath.EvalSymlinks(layerPath); err == nil {
|
||||
realPath := filepath.Join(filepath.Base(filepath.Dir(_realPath)), "layer.tar")
|
||||
keepLayerPaths[realPath] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
for idx := range existLayers {
|
||||
layerPath := layerPaths[idx]
|
||||
if _, ok := keepLayerPaths[layerPath]; !ok {
|
||||
if err := os.Remove(filepath.Join(tmpDir, layerPath)); err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) getExistLayers(ctx context.Context, tmpDir string) ([]string, []string, error) {
|
||||
manifestPath, err := safePath(tmpDir, "manifest.json")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
manifestFile, err := os.Open(manifestPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer manifestFile.Close()
|
||||
|
||||
var manifest []manifestItem
|
||||
if err := json.NewDecoder(manifestFile).Decode(&manifest); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
allLayers := make([][]string, 0)
|
||||
repoTags := make([][]string, 0)
|
||||
layerPaths := make([]string, 0)
|
||||
for _, m := range manifest {
|
||||
configPath, err := safePath(tmpDir, m.Config)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
config, err := ioutil.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
img, err := image.NewFromJSON(config)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if expected, actual := len(m.Layers), len(img.RootFS.DiffIDs); expected != actual {
|
||||
return nil, nil, errors.New(unsupported)
|
||||
}
|
||||
|
||||
layerPaths = append(layerPaths, m.Layers...)
|
||||
|
||||
layers := make([]string, 0)
|
||||
|
||||
for _, diffID := range img.RootFS.DiffIDs {
|
||||
layers = append(layers, string(diffID))
|
||||
}
|
||||
|
||||
allLayers = append(allLayers, layers)
|
||||
repoTags = append(repoTags, m.RepoTags)
|
||||
}
|
||||
diffRet, err := cli.client.ImageDiff(ctx, allLayers, repoTags)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return diffRet.ExistLayers, layerPaths, nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) ImageLoadFromTar(ctx context.Context, tr io.Reader, quiet bool) (*types.ImageLoadResponse, error) {
|
||||
tmpDir, err := ioutil.TempDir("", "hyper-pull-local-")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
if err := archive.Untar(tr, tmpDir, &archive.TarOptions{NoLchown: true}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !quiet {
|
||||
fmt.Fprintln(cli.out, "Diffing local image with remote image...")
|
||||
}
|
||||
|
||||
existLayers, layerPaths, err := cli.getExistLayers(ctx, tmpDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := removeExistLayers(tmpDir, existLayers, layerPaths); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fs, err := archive.Tar(tmpDir, archive.Gzip)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fs.Close()
|
||||
|
||||
hasNewLayers := len(existLayers) != len(layerPaths)
|
||||
if hasNewLayers {
|
||||
if !quiet {
|
||||
fmt.Fprintln(cli.out, "Preparing to upload image...")
|
||||
}
|
||||
}
|
||||
|
||||
tarTmpDir, err := ioutil.TempDir("", "hyper-pull-local-")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer os.RemoveAll(tarTmpDir)
|
||||
|
||||
tarPath := filepath.Join(tarTmpDir, "image.tar")
|
||||
|
||||
tf, err := os.Create(tarPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer tf.Close()
|
||||
|
||||
_, err = io.Copy(tf, fs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
os.RemoveAll(tmpDir)
|
||||
|
||||
info, err := tf.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tf, err = os.Open(tarPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := cli.client.ImageLoadLocal(ctx, quiet, info.Size())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !hasNewLayers || quiet {
|
||||
go func() {
|
||||
_, err := io.Copy(resp.Conn, tf)
|
||||
if err != nil {
|
||||
fmt.Fprintln(cli.out, err.Error())
|
||||
resp.Conn.Close()
|
||||
return
|
||||
}
|
||||
tf.Close()
|
||||
}()
|
||||
return &types.ImageLoadResponse{
|
||||
Body: resp.Conn,
|
||||
JSON: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
pr, pw := io.Pipe()
|
||||
progressOutput := streamformatter.NewJSONStreamFormatter().NewProgressOutput(pw, false)
|
||||
progressReader := progress.NewProgressReader(tf, progressOutput, info.Size(), "", "Uploading image")
|
||||
|
||||
go func() {
|
||||
_, err := io.Copy(resp.Conn, progressReader)
|
||||
if err != nil {
|
||||
fmt.Fprintln(cli.out, err.Error())
|
||||
resp.Conn.Close()
|
||||
return
|
||||
}
|
||||
pw.CloseWithError(io.EOF)
|
||||
}()
|
||||
|
||||
return &types.ImageLoadResponse{
|
||||
Body: readCloser{io.MultiReader(pr, resp.Conn), resp.Conn},
|
||||
JSON: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ImageDiff diff an image layers with local and imaged
|
||||
func (cli *DockerCli) ImageLoadFromDaemon(ctx context.Context, name string, quiet bool) (*types.ImageLoadResponse, error) {
|
||||
if !quiet {
|
||||
fmt.Fprintln(cli.out, "Loading image from local docker daemon...")
|
||||
}
|
||||
|
||||
tr, err := cli.client.ImageSaveTarFromDaemon(ctx, []string{name})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer tr.Close()
|
||||
|
||||
return cli.ImageLoadFromTar(ctx, tr, quiet)
|
||||
}
|
||||
|
||||
// CmdLoad load a local image or a tar file
|
||||
//
|
||||
// The tar archive is read from STDIN by default, or from a tar archive file.
|
||||
//
|
||||
// Usage: docker load [OPTIONS]
|
||||
func (cli *DockerCli) CmdLoad(args ...string) error {
|
||||
cmd := Cli.Subcmd("load", nil, "Load a local image or a tar file", true)
|
||||
local := cmd.String([]string{"l", "-local"}, "", "Read from a local image")
|
||||
infile := cmd.String([]string{"i", "-input"}, "", "Read from a local or remote archive file compressed with gzip, bzip, or xz, instead of STDIN")
|
||||
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Do not show load process")
|
||||
cmd.Require(flag.Exact, 0)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
*infile = strings.TrimSpace(*infile)
|
||||
*local = strings.TrimSpace(*local)
|
||||
|
||||
var stdin io.Reader = cli.in
|
||||
|
||||
if *infile == "" && *local == "" && stdin == nil {
|
||||
return errors.New("source image must be specified via --input, --local or STDIN")
|
||||
}
|
||||
|
||||
var response *types.ImageLoadResponse
|
||||
var err error
|
||||
|
||||
if *local != "" {
|
||||
// Load from local docker daemon
|
||||
response, err = cli.ImageLoadFromDaemon(context.Background(), *local, *quiet)
|
||||
} else if *infile != "" {
|
||||
if strings.HasPrefix(*infile, "http://") ||
|
||||
strings.HasPrefix(*infile, "https://") ||
|
||||
strings.HasPrefix(*infile, "ftp://") {
|
||||
var input struct {
|
||||
FromSrc string `json:"fromSrc"`
|
||||
Quiet bool `json:"quiet"`
|
||||
}
|
||||
input.FromSrc = *infile
|
||||
input.Quiet = *quiet
|
||||
// Load from remote URL
|
||||
response, err = cli.client.ImageLoad(context.Background(), input)
|
||||
} else {
|
||||
// Load from local tar
|
||||
var af *os.File
|
||||
af, err = os.Open(*infile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer af.Close()
|
||||
response, err = cli.ImageLoadFromTar(context.Background(), af, *quiet)
|
||||
}
|
||||
} else if stdin != nil {
|
||||
// Load from STDIN
|
||||
response, err = cli.ImageLoadFromTar(context.Background(), stdin, *quiet)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if response == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.JSON {
|
||||
return jsonmessage.DisplayJSONMessagesStream(response.Body, cli.out, cli.outFd, cli.isTerminalOut, nil)
|
||||
}
|
||||
|
||||
_, err = io.Copy(cli.out, response.Body)
|
||||
return err
|
||||
}
|
||||
156
vendor/github.com/hyperhq/hypercli/api/client/login.go
generated
vendored
156
vendor/github.com/hyperhq/hypercli/api/client/login.go
generated
vendored
@@ -1,156 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/hyperhq/hyper-api/client"
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/pkg/term"
|
||||
)
|
||||
|
||||
// CmdLogin logs in or registers a user to a Docker registry service.
|
||||
//
|
||||
// If no server is specified, the user will be logged into or registered to the registry's index server.
|
||||
//
|
||||
// Usage: docker login SERVER
|
||||
func (cli *DockerCli) CmdLogin(args ...string) error {
|
||||
cmd := Cli.Subcmd("login", []string{"[SERVER]"}, Cli.DockerCommands["login"].Description+".\nIf no server is specified, the default is defined by the daemon.", true)
|
||||
cmd.Require(flag.Max, 1)
|
||||
|
||||
flUser := cmd.String([]string{"u", "-username"}, "", "Username")
|
||||
flPassword := cmd.String([]string{"p", "-password"}, "", "Password")
|
||||
flEmail := cmd.String([]string{"e", "-email"}, "", "Email")
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
// On Windows, force the use of the regular OS stdin stream. Fixes #14336/#14210
|
||||
if runtime.GOOS == "windows" {
|
||||
cli.in = os.Stdin
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
var serverAddress string
|
||||
if len(cmd.Args()) > 0 {
|
||||
serverAddress = cmd.Arg(0)
|
||||
} else {
|
||||
serverAddress = cli.electAuthServer(ctx)
|
||||
}
|
||||
|
||||
authConfig, err := cli.configureAuth(*flUser, *flPassword, *flEmail, serverAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
response, err := cli.client.RegistryLogin(ctx, authConfig)
|
||||
if err != nil {
|
||||
if client.IsErrUnauthorized(err) {
|
||||
delete(cli.configFile.AuthConfigs, serverAddress)
|
||||
if err2 := cli.configFile.Save(); err2 != nil {
|
||||
fmt.Fprintf(cli.out, "WARNING: could not save config file: %v\n", err2)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cli.configFile.Save(); err != nil {
|
||||
return fmt.Errorf("Error saving config file: %v", err)
|
||||
}
|
||||
fmt.Fprintf(cli.out, "WARNING: login credentials saved in %s\n", cli.configFile.Filename())
|
||||
|
||||
if response.Status != "" {
|
||||
fmt.Fprintf(cli.out, "%s\n", response.Status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) promptWithDefault(prompt string, configDefault string) {
|
||||
if configDefault == "" {
|
||||
fmt.Fprintf(cli.out, "%s: ", prompt)
|
||||
} else {
|
||||
fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault)
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *DockerCli) configureAuth(flUser, flPassword, flEmail, serverAddress string) (types.AuthConfig, error) {
|
||||
authconfig, ok := cli.configFile.AuthConfigs[serverAddress]
|
||||
if !ok {
|
||||
authconfig = types.AuthConfig{}
|
||||
}
|
||||
authconfig.Username = strings.TrimSpace(authconfig.Username)
|
||||
|
||||
if flUser = strings.TrimSpace(flUser); flUser == "" {
|
||||
cli.promptWithDefault("Username", authconfig.Username)
|
||||
flUser = readInput(cli.in, cli.out)
|
||||
flUser = strings.TrimSpace(flUser)
|
||||
if flUser == "" {
|
||||
flUser = authconfig.Username
|
||||
}
|
||||
}
|
||||
|
||||
if flUser == "" {
|
||||
return authconfig, fmt.Errorf("Error: Non-null Username Required")
|
||||
}
|
||||
|
||||
if flPassword == "" {
|
||||
oldState, err := term.SaveState(cli.inFd)
|
||||
if err != nil {
|
||||
return authconfig, err
|
||||
}
|
||||
fmt.Fprintf(cli.out, "Password: ")
|
||||
term.DisableEcho(cli.inFd, oldState)
|
||||
|
||||
flPassword = readInput(cli.in, cli.out)
|
||||
fmt.Fprint(cli.out, "\n")
|
||||
|
||||
term.RestoreTerminal(cli.inFd, oldState)
|
||||
if flPassword == "" {
|
||||
return authconfig, fmt.Errorf("Error: Password Required")
|
||||
}
|
||||
}
|
||||
|
||||
// Assume that a different username means they may not want to use
|
||||
// the email from the config file, so prompt it
|
||||
if flUser != authconfig.Username {
|
||||
if flEmail == "" {
|
||||
cli.promptWithDefault("Email", authconfig.Email)
|
||||
flEmail = readInput(cli.in, cli.out)
|
||||
if flEmail == "" {
|
||||
flEmail = authconfig.Email
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// However, if they don't override the username use the
|
||||
// email from the cmd line if specified. IOW, allow
|
||||
// then to change/override them. And if not specified, just
|
||||
// use what's in the config file
|
||||
if flEmail == "" {
|
||||
flEmail = authconfig.Email
|
||||
}
|
||||
}
|
||||
authconfig.Username = flUser
|
||||
authconfig.Password = flPassword
|
||||
authconfig.Email = flEmail
|
||||
authconfig.ServerAddress = serverAddress
|
||||
cli.configFile.AuthConfigs[serverAddress] = authconfig
|
||||
return authconfig, nil
|
||||
}
|
||||
|
||||
func readInput(in io.Reader, out io.Writer) string {
|
||||
reader := bufio.NewReader(in)
|
||||
line, _, err := reader.ReadLine()
|
||||
if err != nil {
|
||||
fmt.Fprintln(out, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
return string(line)
|
||||
}
|
||||
42
vendor/github.com/hyperhq/hypercli/api/client/logout.go
generated
vendored
42
vendor/github.com/hyperhq/hypercli/api/client/logout.go
generated
vendored
@@ -1,42 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdLogout logs a user out from a Docker registry.
|
||||
//
|
||||
// If no server is specified, the user will be logged out from the registry's index server.
|
||||
//
|
||||
// Usage: docker logout [SERVER]
|
||||
func (cli *DockerCli) CmdLogout(args ...string) error {
|
||||
cmd := Cli.Subcmd("logout", []string{"[SERVER]"}, Cli.DockerCommands["logout"].Description+".\nIf no server is specified, the default is defined by the daemon.", true)
|
||||
cmd.Require(flag.Max, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
var serverAddress string
|
||||
if len(cmd.Args()) > 0 {
|
||||
serverAddress = cmd.Arg(0)
|
||||
} else {
|
||||
serverAddress = cli.electAuthServer(context.Background())
|
||||
}
|
||||
|
||||
if _, ok := cli.configFile.AuthConfigs[serverAddress]; !ok {
|
||||
fmt.Fprintf(cli.out, "Not logged in to %s\n", serverAddress)
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Fprintf(cli.out, "Remove login credentials for %s\n", serverAddress)
|
||||
delete(cli.configFile.AuthConfigs, serverAddress)
|
||||
if err := cli.configFile.Save(); err != nil {
|
||||
return fmt.Errorf("Failed to save docker config: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
65
vendor/github.com/hyperhq/hypercli/api/client/logs.go
generated
vendored
65
vendor/github.com/hyperhq/hypercli/api/client/logs.go
generated
vendored
@@ -1,65 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/pkg/stdcopy"
|
||||
)
|
||||
|
||||
var validDrivers = map[string]bool{
|
||||
"json-file": true,
|
||||
"journald": true,
|
||||
}
|
||||
|
||||
// CmdLogs fetches the logs of a given container.
|
||||
//
|
||||
// docker logs [OPTIONS] CONTAINER
|
||||
func (cli *DockerCli) CmdLogs(args ...string) error {
|
||||
cmd := Cli.Subcmd("logs", []string{"CONTAINER"}, Cli.DockerCommands["logs"].Description, true)
|
||||
follow := cmd.Bool([]string{"f", "-follow"}, false, "Follow log output")
|
||||
since := cmd.String([]string{"-since"}, "", "Show logs since timestamp")
|
||||
times := cmd.Bool([]string{"t", "-timestamps"}, false, "Show timestamps")
|
||||
tail := cmd.String([]string{"-tail"}, "all", "Number of lines to show from the end of the logs")
|
||||
cmd.Require(flag.Exact, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
name := cmd.Arg(0)
|
||||
|
||||
ctx := context.Background()
|
||||
c, err := cli.client.ContainerInspect(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !validDrivers[c.HostConfig.LogConfig.Type] {
|
||||
return fmt.Errorf("\"logs\" command is supported only for \"json-file\" and \"journald\" logging drivers (got: %s)", c.HostConfig.LogConfig.Type)
|
||||
}
|
||||
|
||||
options := types.ContainerLogsOptions{
|
||||
ShowStdout: true,
|
||||
ShowStderr: true,
|
||||
Since: *since,
|
||||
Timestamps: *times,
|
||||
Follow: *follow,
|
||||
Tail: *tail,
|
||||
}
|
||||
responseBody, err := cli.client.ContainerLogs(ctx, name, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer responseBody.Close()
|
||||
|
||||
if c.Config.Tty {
|
||||
_, err = io.Copy(cli.out, responseBody)
|
||||
} else {
|
||||
_, err = stdcopy.StdCopy(cli.out, cli.err, responseBody)
|
||||
}
|
||||
return err
|
||||
}
|
||||
379
vendor/github.com/hyperhq/hypercli/api/client/network.go
generated
vendored
379
vendor/github.com/hyperhq/hypercli/api/client/network.go
generated
vendored
@@ -1,379 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hyper-api/types/filters"
|
||||
"github.com/hyperhq/hyper-api/types/network"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/opts"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/pkg/stringid"
|
||||
runconfigopts "github.com/hyperhq/hypercli/runconfig/opts"
|
||||
)
|
||||
|
||||
// CmdNetwork is the parent subcommand for all network commands
|
||||
//
|
||||
// Usage: docker network <COMMAND> [OPTIONS]
|
||||
func (cli *DockerCli) Network(args ...string) error {
|
||||
cmd := Cli.Subcmd("network", []string{"COMMAND [OPTIONS]"}, networkUsage(), false)
|
||||
cmd.Require(flag.Min, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
// CmdNetworkCreate creates a new network with a given name
|
||||
//
|
||||
// Usage: docker network create [OPTIONS] <NETWORK-NAME>
|
||||
func (cli *DockerCli) NetworkCreate(args ...string) error {
|
||||
cmd := Cli.Subcmd("network create", []string{"NETWORK-NAME"}, "Creates a new network with a name specified by the user", false)
|
||||
flDriver := cmd.String([]string{"d", "-driver"}, "bridge", "Driver to manage the Network")
|
||||
flOpts := opts.NewMapOpts(nil, nil)
|
||||
|
||||
flIpamDriver := cmd.String([]string{"-ipam-driver"}, "default", "IP Address Management Driver")
|
||||
flIpamSubnet := opts.NewListOpts(nil)
|
||||
flIpamIPRange := opts.NewListOpts(nil)
|
||||
flIpamGateway := opts.NewListOpts(nil)
|
||||
flIpamAux := opts.NewMapOpts(nil, nil)
|
||||
flIpamOpt := opts.NewMapOpts(nil, nil)
|
||||
|
||||
cmd.Var(&flIpamSubnet, []string{"-subnet"}, "subnet in CIDR format that represents a network segment")
|
||||
cmd.Var(&flIpamIPRange, []string{"-ip-range"}, "allocate container ip from a sub-range")
|
||||
cmd.Var(&flIpamGateway, []string{"-gateway"}, "ipv4 or ipv6 Gateway for the master subnet")
|
||||
cmd.Var(flIpamAux, []string{"-aux-address"}, "auxiliary ipv4 or ipv6 addresses used by Network driver")
|
||||
cmd.Var(flOpts, []string{"o", "-opt"}, "set driver specific options")
|
||||
cmd.Var(flIpamOpt, []string{"-ipam-opt"}, "set IPAM driver specific options")
|
||||
|
||||
flInternal := cmd.Bool([]string{"-internal"}, false, "restricts external access to the network")
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set the default driver to "" if the user didn't set the value.
|
||||
// That way we can know whether it was user input or not.
|
||||
driver := *flDriver
|
||||
if !cmd.IsSet("-driver") && !cmd.IsSet("d") {
|
||||
driver = ""
|
||||
}
|
||||
|
||||
ipamCfg, err := consolidateIpam(flIpamSubnet.GetAll(), flIpamIPRange.GetAll(), flIpamGateway.GetAll(), flIpamAux.GetAll())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Construct network create request body
|
||||
nc := types.NetworkCreate{
|
||||
Driver: driver,
|
||||
IPAM: network.IPAM{Driver: *flIpamDriver, Config: ipamCfg, Options: flIpamOpt.GetAll()},
|
||||
Options: flOpts.GetAll(),
|
||||
CheckDuplicate: true,
|
||||
Internal: *flInternal,
|
||||
}
|
||||
|
||||
resp, err := cli.client.NetworkCreate(context.Background(), cmd.Arg(0), nc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cli.out, "%s\n", resp.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdNetworkRm deletes one or more networks
|
||||
//
|
||||
// Usage: docker network rm NETWORK-NAME|NETWORK-ID [NETWORK-NAME|NETWORK-ID...]
|
||||
func (cli *DockerCli) NetworkRm(args ...string) error {
|
||||
cmd := Cli.Subcmd("network rm", []string{"NETWORK [NETWORK...]"}, "Deletes one or more networks", false)
|
||||
cmd.Require(flag.Min, 1)
|
||||
if err := cmd.ParseFlags(args, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
status := 0
|
||||
for _, net := range cmd.Args() {
|
||||
if err := cli.client.NetworkRemove(context.Background(), net); err != nil {
|
||||
fmt.Fprintf(cli.err, "%s\n", err)
|
||||
status = 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
if status != 0 {
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdNetworkConnect connects a container to a network
|
||||
//
|
||||
// Usage: docker network connect [OPTIONS] <NETWORK> <CONTAINER>
|
||||
func (cli *DockerCli) NetworkConnect(args ...string) error {
|
||||
cmd := Cli.Subcmd("network connect", []string{"NETWORK CONTAINER"}, "Connects a container to a network", false)
|
||||
flIPAddress := cmd.String([]string{"-ip"}, "", "IP Address")
|
||||
flIPv6Address := cmd.String([]string{"-ip6"}, "", "IPv6 Address")
|
||||
flLinks := opts.NewListOpts(runconfigopts.ValidateLink)
|
||||
cmd.Var(&flLinks, []string{"-link"}, "Add link to another container")
|
||||
flAliases := opts.NewListOpts(nil)
|
||||
cmd.Var(&flAliases, []string{"-alias"}, "Add network-scoped alias for the container")
|
||||
cmd.Require(flag.Min, 2)
|
||||
if err := cmd.ParseFlags(args, true); err != nil {
|
||||
return err
|
||||
}
|
||||
epConfig := &network.EndpointSettings{
|
||||
IPAMConfig: &network.EndpointIPAMConfig{
|
||||
IPv4Address: *flIPAddress,
|
||||
IPv6Address: *flIPv6Address,
|
||||
},
|
||||
Links: flLinks.GetAll(),
|
||||
Aliases: flAliases.GetAll(),
|
||||
}
|
||||
return cli.client.NetworkConnect(context.Background(), cmd.Arg(0), cmd.Arg(1), epConfig)
|
||||
}
|
||||
|
||||
// CmdNetworkDisconnect disconnects a container from a network
|
||||
//
|
||||
// Usage: docker network disconnect <NETWORK> <CONTAINER>
|
||||
func (cli *DockerCli) NetworkDisconnect(args ...string) error {
|
||||
cmd := Cli.Subcmd("network disconnect", []string{"NETWORK CONTAINER"}, "Disconnects container from a network", false)
|
||||
force := cmd.Bool([]string{"f", "-force"}, false, "Force the container to disconnect from a network")
|
||||
cmd.Require(flag.Exact, 2)
|
||||
if err := cmd.ParseFlags(args, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return cli.client.NetworkDisconnect(context.Background(), cmd.Arg(0), cmd.Arg(1), *force)
|
||||
}
|
||||
|
||||
// CmdNetworkLs lists all the networks managed by docker daemon
|
||||
//
|
||||
// Usage: docker network ls [OPTIONS]
|
||||
func (cli *DockerCli) NetworkLs(args ...string) error {
|
||||
cmd := Cli.Subcmd("network ls", nil, "Lists networks", true)
|
||||
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
|
||||
noTrunc := cmd.Bool([]string{"-no-trunc"}, false, "Do not truncate the output")
|
||||
|
||||
flFilter := opts.NewListOpts(nil)
|
||||
cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided")
|
||||
|
||||
cmd.Require(flag.Exact, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Consolidate all filter flags, and sanity check them early.
|
||||
// They'll get process after get response from server.
|
||||
netFilterArgs := filters.NewArgs()
|
||||
for _, f := range flFilter.GetAll() {
|
||||
if netFilterArgs, err = filters.ParseFlag(f, netFilterArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
options := types.NetworkListOptions{
|
||||
Filters: netFilterArgs,
|
||||
}
|
||||
|
||||
networkResources, err := cli.client.NetworkList(context.Background(), options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wr := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
||||
|
||||
// unless quiet (-q) is specified, print field titles
|
||||
if !*quiet {
|
||||
fmt.Fprintln(wr, "NETWORK ID\tNAME\tDRIVER")
|
||||
}
|
||||
|
||||
for _, networkResource := range networkResources {
|
||||
ID := networkResource.ID
|
||||
netName := networkResource.Name
|
||||
if !*noTrunc {
|
||||
ID = stringid.TruncateID(ID)
|
||||
}
|
||||
if *quiet {
|
||||
fmt.Fprintln(wr, ID)
|
||||
continue
|
||||
}
|
||||
driver := networkResource.Driver
|
||||
fmt.Fprintf(wr, "%s\t%s\t%s\t",
|
||||
ID,
|
||||
netName,
|
||||
driver)
|
||||
fmt.Fprint(wr, "\n")
|
||||
}
|
||||
wr.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdNetworkInspect inspects the network object for more details
|
||||
//
|
||||
// Usage: docker network inspect [OPTIONS] <NETWORK> [NETWORK...]
|
||||
func (cli *DockerCli) NetworkInspect(args ...string) error {
|
||||
cmd := Cli.Subcmd("network inspect", []string{"NETWORK [NETWORK...]"}, "Displays detailed information on one or more networks", false)
|
||||
tmplStr := cmd.String([]string{"f", "-format"}, "", "Format the output using the given go template")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
if err := cmd.ParseFlags(args, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
inspectSearcher := func(name string) (interface{}, []byte, error) {
|
||||
i, err := cli.client.NetworkInspect(context.Background(), name)
|
||||
return i, nil, err
|
||||
}
|
||||
|
||||
return cli.inspectElements(*tmplStr, cmd.Args(), inspectSearcher)
|
||||
}
|
||||
|
||||
// Consolidates the ipam configuration as a group from different related configurations
|
||||
// user can configure network with multiple non-overlapping subnets and hence it is
|
||||
// possible to correlate the various related parameters and consolidate them.
|
||||
// consoidateIpam consolidates subnets, ip-ranges, gateways and auxiliary addresses into
|
||||
// structured ipam data.
|
||||
func consolidateIpam(subnets, ranges, gateways []string, auxaddrs map[string]string) ([]network.IPAMConfig, error) {
|
||||
if len(subnets) < len(ranges) || len(subnets) < len(gateways) {
|
||||
return nil, fmt.Errorf("every ip-range or gateway must have a corresponding subnet")
|
||||
}
|
||||
iData := map[string]*network.IPAMConfig{}
|
||||
|
||||
// Populate non-overlapping subnets into consolidation map
|
||||
for _, s := range subnets {
|
||||
for k := range iData {
|
||||
ok1, err := subnetMatches(s, k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ok2, err := subnetMatches(k, s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ok1 || ok2 {
|
||||
return nil, fmt.Errorf("multiple overlapping subnet configuration is not supported")
|
||||
}
|
||||
}
|
||||
iData[s] = &network.IPAMConfig{Subnet: s, AuxAddress: map[string]string{}}
|
||||
}
|
||||
|
||||
// Validate and add valid ip ranges
|
||||
for _, r := range ranges {
|
||||
match := false
|
||||
for _, s := range subnets {
|
||||
ok, err := subnetMatches(s, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if iData[s].IPRange != "" {
|
||||
return nil, fmt.Errorf("cannot configure multiple ranges (%s, %s) on the same subnet (%s)", r, iData[s].IPRange, s)
|
||||
}
|
||||
d := iData[s]
|
||||
d.IPRange = r
|
||||
match = true
|
||||
}
|
||||
if !match {
|
||||
return nil, fmt.Errorf("no matching subnet for range %s", r)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate and add valid gateways
|
||||
for _, g := range gateways {
|
||||
match := false
|
||||
for _, s := range subnets {
|
||||
ok, err := subnetMatches(s, g)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if iData[s].Gateway != "" {
|
||||
return nil, fmt.Errorf("cannot configure multiple gateways (%s, %s) for the same subnet (%s)", g, iData[s].Gateway, s)
|
||||
}
|
||||
d := iData[s]
|
||||
d.Gateway = g
|
||||
match = true
|
||||
}
|
||||
if !match {
|
||||
return nil, fmt.Errorf("no matching subnet for gateway %s", g)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate and add aux-addresses
|
||||
for key, aa := range auxaddrs {
|
||||
match := false
|
||||
for _, s := range subnets {
|
||||
ok, err := subnetMatches(s, aa)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
iData[s].AuxAddress[key] = aa
|
||||
match = true
|
||||
}
|
||||
if !match {
|
||||
return nil, fmt.Errorf("no matching subnet for aux-address %s", aa)
|
||||
}
|
||||
}
|
||||
|
||||
idl := []network.IPAMConfig{}
|
||||
for _, v := range iData {
|
||||
idl = append(idl, *v)
|
||||
}
|
||||
return idl, nil
|
||||
}
|
||||
|
||||
func subnetMatches(subnet, data string) (bool, error) {
|
||||
var (
|
||||
ip net.IP
|
||||
)
|
||||
|
||||
_, s, err := net.ParseCIDR(subnet)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Invalid subnet %s : %v", s, err)
|
||||
}
|
||||
|
||||
if strings.Contains(data, "/") {
|
||||
ip, _, err = net.ParseCIDR(data)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Invalid cidr %s : %v", data, err)
|
||||
}
|
||||
} else {
|
||||
ip = net.ParseIP(data)
|
||||
}
|
||||
|
||||
return s.Contains(ip), nil
|
||||
}
|
||||
|
||||
func networkUsage() string {
|
||||
networkCommands := map[string]string{
|
||||
"create": "Create a network",
|
||||
"connect": "Connect container to a network",
|
||||
"disconnect": "Disconnect container from a network",
|
||||
"inspect": "Display detailed network information",
|
||||
"ls": "List all networks",
|
||||
"rm": "Remove a network",
|
||||
}
|
||||
|
||||
help := "Commands:\n"
|
||||
|
||||
for cmd, description := range networkCommands {
|
||||
help += fmt.Sprintf(" %-25.25s%s\n", cmd, description)
|
||||
}
|
||||
|
||||
help += fmt.Sprintf("\nRun 'hyper network COMMAND --help' for more information on a command.")
|
||||
return help
|
||||
}
|
||||
36
vendor/github.com/hyperhq/hypercli/api/client/pause.go
generated
vendored
36
vendor/github.com/hyperhq/hypercli/api/client/pause.go
generated
vendored
@@ -1,36 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdPause pauses all processes within one or more containers.
|
||||
//
|
||||
// Usage: docker pause CONTAINER [CONTAINER...]
|
||||
func (cli *DockerCli) Pause(args ...string) error {
|
||||
cmd := Cli.Subcmd("pause", []string{"CONTAINER [CONTAINER...]"}, Cli.DockerCommands["pause"].Description, true)
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
var errs []string
|
||||
for _, name := range cmd.Args() {
|
||||
if err := cli.client.ContainerPause(ctx, name); err != nil {
|
||||
errs = append(errs, err.Error())
|
||||
} else {
|
||||
fmt.Fprintf(cli.out, "%s\n", name)
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("%s", strings.Join(errs, "\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
63
vendor/github.com/hyperhq/hypercli/api/client/port.go
generated
vendored
63
vendor/github.com/hyperhq/hypercli/api/client/port.go
generated
vendored
@@ -1,63 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/docker/go-connections/nat"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdPort lists port mappings for a container.
|
||||
// If a private port is specified, it also shows the public-facing port that is NATed to the private port.
|
||||
//
|
||||
// Usage: docker port CONTAINER [PRIVATE_PORT[/PROTO]]
|
||||
func (cli *DockerCli) CmdPort(args ...string) error {
|
||||
cmd := Cli.Subcmd("port", []string{"CONTAINER [PRIVATE_PORT[/PROTO]]"}, Cli.DockerCommands["port"].Description, true)
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
c, err := cli.client.ContainerInspect(ctx, cmd.Arg(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cmd.NArg() == 2 {
|
||||
var (
|
||||
port = cmd.Arg(1)
|
||||
proto = "tcp"
|
||||
parts = strings.SplitN(port, "/", 2)
|
||||
)
|
||||
|
||||
if len(parts) == 2 && len(parts[1]) != 0 {
|
||||
port = parts[0]
|
||||
proto = parts[1]
|
||||
}
|
||||
natPort := port + "/" + proto
|
||||
newP, err := nat.NewPort(proto, port)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if frontends, exists := c.NetworkSettings.Ports[newP]; exists && frontends != nil {
|
||||
for _, frontend := range frontends {
|
||||
fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIP, frontend.HostPort)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Error: No public port '%s' published for %s", natPort, cmd.Arg(0))
|
||||
}
|
||||
|
||||
for from, frontends := range c.NetworkSettings.Ports {
|
||||
for _, frontend := range frontends {
|
||||
fmt.Fprintf(cli.out, "%s -> %s:%s\n", from, frontend.HostIP, frontend.HostPort)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
88
vendor/github.com/hyperhq/hypercli/api/client/ps.go
generated
vendored
88
vendor/github.com/hyperhq/hypercli/api/client/ps.go
generated
vendored
@@ -1,88 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hyper-api/types/filters"
|
||||
"github.com/hyperhq/hypercli/api/client/formatter"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/opts"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// CmdPs outputs a list of Docker containers.
|
||||
//
|
||||
// Usage: docker ps [OPTIONS]
|
||||
func (cli *DockerCli) CmdPs(args ...string) error {
|
||||
var (
|
||||
err error
|
||||
|
||||
psFilterArgs = filters.NewArgs()
|
||||
|
||||
cmd = Cli.Subcmd("ps", nil, Cli.DockerCommands["ps"].Description, true)
|
||||
quiet = cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
|
||||
size = cmd.Bool([]string{"s", "-size"}, false, "Display total file sizes")
|
||||
all = cmd.Bool([]string{"a", "-all"}, false, "Show all containers (default shows just running)")
|
||||
noTrunc = cmd.Bool([]string{"-no-trunc"}, false, "Don't truncate output")
|
||||
nLatest = cmd.Bool([]string{"l", "-latest"}, false, "Show the latest created container (includes all states)")
|
||||
since = cmd.String([]string{"#-since"}, "", "Show containers created since Id or Name (includes all states)")
|
||||
before = cmd.String([]string{"#-before"}, "", "Only show containers created before Id or Name")
|
||||
last = cmd.Int([]string{"n"}, -1, "Show n last created containers (includes all states)")
|
||||
format = cmd.String([]string{"-format"}, "", "Pretty-print containers using a Go template")
|
||||
flFilter = opts.NewListOpts(nil)
|
||||
)
|
||||
cmd.Require(flag.Exact, 0)
|
||||
|
||||
cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided")
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
if *last == -1 && *nLatest {
|
||||
*last = 1
|
||||
}
|
||||
|
||||
// Consolidate all filter flags, and sanity check them.
|
||||
// They'll get processed in the daemon/server.
|
||||
for _, f := range flFilter.GetAll() {
|
||||
if psFilterArgs, err = filters.ParseFlag(f, psFilterArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
options := types.ContainerListOptions{
|
||||
All: *all,
|
||||
Limit: *last,
|
||||
Since: *since,
|
||||
Before: *before,
|
||||
Size: *size,
|
||||
Filter: psFilterArgs,
|
||||
}
|
||||
|
||||
containers, err := cli.client.ContainerList(context.Background(), options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f := *format
|
||||
if len(f) == 0 {
|
||||
if len(cli.PsFormat()) > 0 && !*quiet {
|
||||
f = cli.PsFormat()
|
||||
} else {
|
||||
f = "table"
|
||||
}
|
||||
}
|
||||
|
||||
psCtx := formatter.ContainerContext{
|
||||
Context: formatter.Context{
|
||||
Output: cli.out,
|
||||
Format: f,
|
||||
Quiet: *quiet,
|
||||
Trunc: !*noTrunc,
|
||||
},
|
||||
Size: *size,
|
||||
Containers: containers,
|
||||
}
|
||||
|
||||
psCtx.Write()
|
||||
|
||||
return nil
|
||||
}
|
||||
94
vendor/github.com/hyperhq/hypercli/api/client/pull.go
generated
vendored
94
vendor/github.com/hyperhq/hypercli/api/client/pull.go
generated
vendored
@@ -1,94 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/pkg/jsonmessage"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/reference"
|
||||
"github.com/hyperhq/hypercli/registry"
|
||||
)
|
||||
|
||||
// CmdPull pulls an image or a repository from the registry.
|
||||
//
|
||||
// Usage: docker pull [OPTIONS] IMAGENAME[:TAG|@DIGEST]
|
||||
func (cli *DockerCli) CmdPull(args ...string) error {
|
||||
cmd := Cli.Subcmd("pull", []string{"NAME[:TAG|@DIGEST]"}, Cli.DockerCommands["pull"].Description, true)
|
||||
allTags := cmd.Bool([]string{}, false, "Download all tagged images in the repository")
|
||||
addTrustedFlags(cmd, true)
|
||||
cmd.Require(flag.Exact, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
remote := cmd.Arg(0)
|
||||
|
||||
distributionRef, err := reference.ParseNamed(remote)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *allTags && !reference.IsNameOnly(distributionRef) {
|
||||
return errors.New("tag can't be used with --all-tags/-a")
|
||||
}
|
||||
|
||||
if err = cli.checkCloudConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !*allTags && reference.IsNameOnly(distributionRef) {
|
||||
distributionRef = reference.WithDefaultTag(distributionRef)
|
||||
fmt.Fprintf(cli.out, "Using default tag: %s\n", reference.DefaultTag)
|
||||
}
|
||||
|
||||
var tag string
|
||||
switch x := distributionRef.(type) {
|
||||
case reference.Canonical:
|
||||
tag = x.Digest().String()
|
||||
case reference.NamedTagged:
|
||||
tag = x.Tag()
|
||||
}
|
||||
|
||||
ref := registry.ParseReference(tag)
|
||||
|
||||
// Resolve the Repository name from fqn to RepositoryInfo
|
||||
repoInfo, err := registry.ParseRepositoryInfo(distributionRef)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
authConfig := cli.resolveAuthConfig(ctx, cli.configFile.AuthConfigs, repoInfo.Index)
|
||||
requestPrivilege := cli.registryAuthenticationPrivilegedFunc(repoInfo.Index, "pull")
|
||||
|
||||
if isTrusted() && !ref.HasDigest() {
|
||||
// Check if tag is digest
|
||||
return cli.trustedPull(ctx, repoInfo, ref, authConfig, requestPrivilege)
|
||||
}
|
||||
|
||||
return cli.imagePullPrivileged(ctx, authConfig, distributionRef.String(), requestPrivilege, *allTags)
|
||||
}
|
||||
|
||||
func (cli *DockerCli) imagePullPrivileged(ctx context.Context, authConfig types.AuthConfig, ref string, requestPrivilege types.RequestPrivilegeFunc, all bool) error {
|
||||
|
||||
encodedAuth, err := encodeAuthToBase64(authConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
options := types.ImagePullOptions{
|
||||
PrivilegeFunc: requestPrivilege,
|
||||
RegistryAuth: encodedAuth,
|
||||
All: all,
|
||||
}
|
||||
|
||||
responseBody, err := cli.client.ImagePull(context.Background(), ref, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer responseBody.Close()
|
||||
|
||||
return jsonmessage.DisplayJSONMessagesStream(responseBody, cli.out, cli.outFd, cli.isTerminalOut, nil)
|
||||
}
|
||||
66
vendor/github.com/hyperhq/hypercli/api/client/push.go
generated
vendored
66
vendor/github.com/hyperhq/hypercli/api/client/push.go
generated
vendored
@@ -1,66 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/pkg/jsonmessage"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/reference"
|
||||
"github.com/hyperhq/hypercli/registry"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// CmdPush pushes an image or repository to the registry.
|
||||
//
|
||||
// Usage: hyper push NAME[:TAG]
|
||||
func (cli *DockerCli) CmdPush(args ...string) error {
|
||||
cmd := Cli.Subcmd("push", []string{"NAME[:TAG]"}, Cli.DockerCommands["push"].Description, true)
|
||||
addTrustedFlags(cmd, false)
|
||||
cmd.Require(flag.Exact, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
ref, err := reference.ParseNamed(cmd.Arg(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Resolve the Repository name from fqn to RepositoryInfo
|
||||
repoInfo, err := registry.ParseRepositoryInfo(ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Resolve the Auth config relevant for this server
|
||||
authConfig := cli.resolveAuthConfig(ctx, cli.configFile.AuthConfigs, repoInfo.Index)
|
||||
requestPrivilege := cli.registryAuthenticationPrivilegedFunc(repoInfo.Index, "push")
|
||||
|
||||
if isTrusted() {
|
||||
return cli.trustedPush(ctx, repoInfo, ref, authConfig, requestPrivilege)
|
||||
}
|
||||
|
||||
responseBody, err := cli.imagePushPrivileged(ctx, authConfig, ref.String(), requestPrivilege)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer responseBody.Close()
|
||||
|
||||
return jsonmessage.DisplayJSONMessagesStream(responseBody, cli.out, cli.outFd, cli.isTerminalOut, nil)
|
||||
}
|
||||
|
||||
func (cli *DockerCli) imagePushPrivileged(ctx context.Context, authConfig types.AuthConfig, ref string, requestPrivilege types.RequestPrivilegeFunc) (io.ReadCloser, error) {
|
||||
encodedAuth, err := encodeAuthToBase64(authConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options := types.ImagePushOptions{
|
||||
RegistryAuth: encodedAuth,
|
||||
PrivilegeFunc: requestPrivilege,
|
||||
}
|
||||
|
||||
return cli.client.ImagePush(ctx, ref, options)
|
||||
}
|
||||
34
vendor/github.com/hyperhq/hypercli/api/client/rename.go
generated
vendored
34
vendor/github.com/hyperhq/hypercli/api/client/rename.go
generated
vendored
@@ -1,34 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdRename renames a container.
|
||||
//
|
||||
// Usage: docker rename OLD_NAME NEW_NAME
|
||||
func (cli *DockerCli) CmdRename(args ...string) error {
|
||||
cmd := Cli.Subcmd("rename", []string{"OLD_NAME NEW_NAME"}, Cli.DockerCommands["rename"].Description, true)
|
||||
cmd.Require(flag.Exact, 2)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
oldName := strings.TrimSpace(cmd.Arg(0))
|
||||
newName := strings.TrimSpace(cmd.Arg(1))
|
||||
|
||||
if oldName == "" || newName == "" {
|
||||
return fmt.Errorf("Error: Neither old nor new names may be empty")
|
||||
}
|
||||
|
||||
if err := cli.client.ContainerRename(context.Background(), oldName, newName); err != nil {
|
||||
fmt.Fprintf(cli.err, "%s\n", err)
|
||||
return fmt.Errorf("Error: failed to rename container named %s", oldName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
37
vendor/github.com/hyperhq/hypercli/api/client/restart.go
generated
vendored
37
vendor/github.com/hyperhq/hypercli/api/client/restart.go
generated
vendored
@@ -1,37 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdRestart restarts one or more containers.
|
||||
//
|
||||
// Usage: docker restart [OPTIONS] CONTAINER [CONTAINER...]
|
||||
func (cli *DockerCli) CmdRestart(args ...string) error {
|
||||
cmd := Cli.Subcmd("restart", []string{"CONTAINER [CONTAINER...]"}, Cli.DockerCommands["restart"].Description, true)
|
||||
nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Seconds to wait for stop before killing the container")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
var errs []string
|
||||
for _, name := range cmd.Args() {
|
||||
if err := cli.client.ContainerRestart(ctx, name, *nSeconds); err != nil {
|
||||
errs = append(errs, err.Error())
|
||||
} else {
|
||||
fmt.Fprintf(cli.out, "%s\n", name)
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("%s", strings.Join(errs, "\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
61
vendor/github.com/hyperhq/hypercli/api/client/rm.go
generated
vendored
61
vendor/github.com/hyperhq/hypercli/api/client/rm.go
generated
vendored
@@ -1,61 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdRm removes one or more containers.
|
||||
//
|
||||
// Usage: docker rm [OPTIONS] CONTAINER [CONTAINER...]
|
||||
func (cli *DockerCli) CmdRm(args ...string) error {
|
||||
cmd := Cli.Subcmd("rm", []string{"CONTAINER [CONTAINER...]"}, Cli.DockerCommands["rm"].Description, true)
|
||||
v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated with the container")
|
||||
link := cmd.Bool([]string{"l", "-link"}, false, "Remove the specified link")
|
||||
force := cmd.Bool([]string{"f", "-force"}, false, "Force the removal of a running container (uses SIGKILL)")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
ctx := context.Background()
|
||||
var errs []string
|
||||
for _, name := range cmd.Args() {
|
||||
if name == "" {
|
||||
return fmt.Errorf("Container name cannot be empty")
|
||||
}
|
||||
name = strings.Trim(name, "/")
|
||||
|
||||
warnings, err := cli.removeContainer(ctx, name, *v, *link, *force)
|
||||
if err != nil {
|
||||
errs = append(errs, err.Error())
|
||||
} else {
|
||||
fmt.Fprintf(cli.out, "%s\n", name)
|
||||
for _, w := range warnings {
|
||||
fmt.Fprintf(cli.out, "NOTICE : %s\n", w)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("%s", strings.Join(errs, "\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) removeContainer(ctx context.Context, containerID string, removeVolumes, removeLinks, force bool) ([]string, error) {
|
||||
options := types.ContainerRemoveOptions{
|
||||
RemoveVolumes: removeVolumes,
|
||||
RemoveLinks: removeLinks,
|
||||
Force: force,
|
||||
}
|
||||
warnings, err := cli.client.ContainerRemove(ctx, containerID, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return warnings, nil
|
||||
}
|
||||
60
vendor/github.com/hyperhq/hypercli/api/client/rmi.go
generated
vendored
60
vendor/github.com/hyperhq/hypercli/api/client/rmi.go
generated
vendored
@@ -1,60 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdRmi removes all images with the specified name(s).
|
||||
//
|
||||
// Usage: docker rmi [OPTIONS] IMAGE [IMAGE...]
|
||||
func (cli *DockerCli) CmdRmi(args ...string) error {
|
||||
cmd := Cli.Subcmd("rmi", []string{"IMAGE [IMAGE...]"}, Cli.DockerCommands["rmi"].Description, true)
|
||||
force := cmd.Bool([]string{"f", "-force"}, false, "Force removal of the image")
|
||||
noprune := cmd.Bool([]string{"-no-prune"}, false, "Do not delete untagged parents")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
v := url.Values{}
|
||||
if *force {
|
||||
v.Set("force", "1")
|
||||
}
|
||||
if *noprune {
|
||||
v.Set("noprune", "1")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
var errs []string
|
||||
for _, name := range cmd.Args() {
|
||||
options := types.ImageRemoveOptions{
|
||||
Force: *force,
|
||||
PruneChildren: !*noprune,
|
||||
}
|
||||
|
||||
dels, err := cli.client.ImageRemove(ctx, name, options)
|
||||
if err != nil {
|
||||
errs = append(errs, err.Error())
|
||||
} else {
|
||||
for _, del := range dels {
|
||||
if del.Deleted != "" {
|
||||
fmt.Fprintf(cli.out, "Deleted: %s\n", del.Deleted)
|
||||
} else {
|
||||
fmt.Fprintf(cli.out, "Untagged: %s\n", del.Untagged)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("%s", strings.Join(errs, "\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
312
vendor/github.com/hyperhq/hypercli/api/client/run.go
generated
vendored
312
vendor/github.com/hyperhq/hypercli/api/client/run.go
generated
vendored
@@ -1,312 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libnetwork/resolvconf/dns"
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
derr "github.com/hyperhq/hypercli/errors"
|
||||
"github.com/hyperhq/hypercli/opts"
|
||||
"github.com/hyperhq/hypercli/pkg/promise"
|
||||
"github.com/hyperhq/hypercli/pkg/signal"
|
||||
"github.com/hyperhq/hypercli/pkg/stringid"
|
||||
runconfigopts "github.com/hyperhq/hypercli/runconfig/opts"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type InitVolume struct {
|
||||
Source string
|
||||
Destination string
|
||||
Name string
|
||||
}
|
||||
|
||||
func (cid *cidFile) Close() error {
|
||||
cid.file.Close()
|
||||
|
||||
if !cid.written {
|
||||
if err := os.Remove(cid.path); err != nil {
|
||||
return fmt.Errorf("failed to remove the CID file '%s': %s \n", cid.path, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cid *cidFile) Write(id string) error {
|
||||
if _, err := cid.file.Write([]byte(id)); err != nil {
|
||||
return fmt.Errorf("Failed to write the container ID to the file: %s", err)
|
||||
}
|
||||
cid.written = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// if container start fails with 'command not found' error, return 127
|
||||
// if container start fails with 'command cannot be invoked' error, return 126
|
||||
// return 125 for generic docker daemon failures
|
||||
func runStartContainerErr(err error) error {
|
||||
trimmedErr := strings.Trim(err.Error(), "Error response from daemon: ")
|
||||
statusError := Cli.StatusError{}
|
||||
derrCmdNotFound := derr.ErrorCodeCmdNotFound.Message()
|
||||
derrCouldNotInvoke := derr.ErrorCodeCmdCouldNotBeInvoked.Message()
|
||||
derrNoSuchImage := derr.ErrorCodeNoSuchImageHash.Message()
|
||||
derrNoSuchImageTag := derr.ErrorCodeNoSuchImageTag.Message()
|
||||
switch trimmedErr {
|
||||
case derrCmdNotFound:
|
||||
statusError = Cli.StatusError{StatusCode: 127}
|
||||
case derrCouldNotInvoke:
|
||||
statusError = Cli.StatusError{StatusCode: 126}
|
||||
case derrNoSuchImage, derrNoSuchImageTag:
|
||||
statusError = Cli.StatusError{StatusCode: 125}
|
||||
default:
|
||||
statusError = Cli.StatusError{StatusCode: 125}
|
||||
}
|
||||
return statusError
|
||||
}
|
||||
|
||||
// CmdRun runs a command in a new container.
|
||||
//
|
||||
// Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
|
||||
func (cli *DockerCli) CmdRun(args ...string) error {
|
||||
cmd := Cli.Subcmd("run", []string{"IMAGE [COMMAND] [ARG...]"}, Cli.DockerCommands["run"].Description, true)
|
||||
addTrustedFlags(cmd, true)
|
||||
|
||||
// These are flags not stored in Config/HostConfig
|
||||
var (
|
||||
flAutoRemove = cmd.Bool([]string{"-rm"}, false, "Automatically remove the container when it exits")
|
||||
flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Run container in background and print container ID")
|
||||
flSigProxy = cmd.Bool([]string{}, true, "Proxy received signals to the process")
|
||||
flName = cmd.String([]string{"-name"}, "", "Assign a name to the container")
|
||||
flDetachKeys = cmd.String([]string{}, "", "Override the key sequence for detaching a container")
|
||||
flAttach *opts.ListOpts
|
||||
|
||||
ErrConflictAttachDetach = fmt.Errorf("Conflicting options: -a and -d")
|
||||
ErrConflictRestartPolicyAndAutoRemove = fmt.Errorf("Conflicting options: --restart and --rm")
|
||||
ErrConflictDetachAutoRemove = fmt.Errorf("Conflicting options: --rm and -d")
|
||||
ErrConflictProtectionAutoRemove = fmt.Errorf("Conflicting options: --rm and --protection")
|
||||
)
|
||||
|
||||
config, hostConfig, networkingConfig, cmd, err := runconfigopts.Parse(cmd, args)
|
||||
|
||||
// just in case the Parse does not exit
|
||||
if err != nil {
|
||||
cmd.ReportError(err.Error(), true)
|
||||
os.Exit(125)
|
||||
}
|
||||
|
||||
if hostConfig.OomKillDisable != nil && *hostConfig.OomKillDisable && hostConfig.Memory == 0 {
|
||||
fmt.Fprintf(cli.err, "WARNING: Disabling the OOM killer on containers without setting a '-m/--memory' limit may be dangerous.\n")
|
||||
}
|
||||
|
||||
if len(hostConfig.DNS) > 0 {
|
||||
// check the DNS settings passed via --dns against
|
||||
// localhost regexp to warn if they are trying to
|
||||
// set a DNS to a localhost address
|
||||
for _, dnsIP := range hostConfig.DNS {
|
||||
if dns.IsLocalhost(dnsIP) {
|
||||
fmt.Fprintf(cli.err, "WARNING: Localhost DNS setting (--dns=%s) may fail in containers.\n", dnsIP)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if config.Image == "" {
|
||||
cmd.Usage()
|
||||
return nil
|
||||
}
|
||||
|
||||
config.ArgsEscaped = false
|
||||
|
||||
if !*flDetach {
|
||||
if err := cli.CheckTtyInput(config.AttachStdin, config.Tty); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if fl := cmd.Lookup("-attach"); fl != nil {
|
||||
flAttach = fl.Value.(*opts.ListOpts)
|
||||
if flAttach.Len() != 0 {
|
||||
return ErrConflictAttachDetach
|
||||
}
|
||||
}
|
||||
if *flAutoRemove {
|
||||
return ErrConflictDetachAutoRemove
|
||||
}
|
||||
|
||||
config.AttachStdin = false
|
||||
config.AttachStdout = false
|
||||
config.AttachStderr = false
|
||||
config.StdinOnce = false
|
||||
}
|
||||
|
||||
// Disable flSigProxy when in TTY mode
|
||||
sigProxy := *flSigProxy
|
||||
if config.Tty {
|
||||
sigProxy = false
|
||||
}
|
||||
|
||||
// Telling the Windows daemon the initial size of the tty during start makes
|
||||
// a far better user experience rather than relying on subsequent resizes
|
||||
// to cause things to catch up.
|
||||
if runtime.GOOS == "windows" {
|
||||
hostConfig.ConsoleSize[0], hostConfig.ConsoleSize[1] = cli.getTtySize()
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
createResponse, err := cli.createContainer(ctx, config, hostConfig, networkingConfig, hostConfig.ContainerIDFile, *flName)
|
||||
if err != nil {
|
||||
cmd.ReportError(err.Error(), true)
|
||||
return runStartContainerErr(err)
|
||||
}
|
||||
|
||||
if sigProxy {
|
||||
sigc := cli.forwardAllSignals(ctx, createResponse.ID)
|
||||
defer signal.StopCatch(sigc)
|
||||
}
|
||||
var (
|
||||
waitDisplayID chan struct{}
|
||||
errCh chan error
|
||||
)
|
||||
if !config.AttachStdout && !config.AttachStderr {
|
||||
// Make this asynchronous to allow the client to write to stdin before having to read the ID
|
||||
waitDisplayID = make(chan struct{})
|
||||
go func() {
|
||||
defer close(waitDisplayID)
|
||||
fmt.Fprintf(cli.out, "%s\n", createResponse.ID)
|
||||
}()
|
||||
}
|
||||
if *flAutoRemove {
|
||||
if hostConfig.RestartPolicy.IsAlways() || hostConfig.RestartPolicy.IsOnFailure() {
|
||||
return ErrConflictRestartPolicyAndAutoRemove
|
||||
}
|
||||
if _, ok := config.Labels["sh_hyper_container_protection"]; ok {
|
||||
return ErrConflictProtectionAutoRemove
|
||||
}
|
||||
}
|
||||
|
||||
if config.AttachStdin || config.AttachStdout || config.AttachStderr {
|
||||
var (
|
||||
out, stderr io.Writer
|
||||
in io.ReadCloser
|
||||
)
|
||||
if config.AttachStdin {
|
||||
in = cli.in
|
||||
}
|
||||
if config.AttachStdout {
|
||||
out = cli.out
|
||||
}
|
||||
if config.AttachStderr {
|
||||
if config.Tty {
|
||||
stderr = cli.out
|
||||
} else {
|
||||
stderr = cli.err
|
||||
}
|
||||
}
|
||||
|
||||
if *flDetachKeys != "" {
|
||||
cli.configFile.DetachKeys = *flDetachKeys
|
||||
}
|
||||
|
||||
options := types.ContainerAttachOptions{
|
||||
Stream: true,
|
||||
Stdin: config.AttachStdin,
|
||||
Stdout: config.AttachStdout,
|
||||
Stderr: config.AttachStderr,
|
||||
DetachKeys: cli.configFile.DetachKeys,
|
||||
}
|
||||
|
||||
resp, err := cli.client.ContainerAttach(ctx, createResponse.ID, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if in != nil && config.Tty {
|
||||
if err := cli.setRawTerminal(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.restoreTerminal(in)
|
||||
}
|
||||
errCh = promise.Go(func() error {
|
||||
return cli.holdHijackedConnection(config.Tty, in, out, stderr, resp)
|
||||
})
|
||||
}
|
||||
|
||||
if *flAutoRemove {
|
||||
defer func() {
|
||||
if _, err := cli.removeContainer(ctx, createResponse.ID, true, false, false); err != nil {
|
||||
fmt.Fprintf(cli.err, "%v\n", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
//start the container
|
||||
if err := cli.client.ContainerStart(ctx, createResponse.ID, ""); err != nil {
|
||||
cmd.ReportError(err.Error(), false)
|
||||
return runStartContainerErr(err)
|
||||
}
|
||||
|
||||
if (config.AttachStdin || config.AttachStdout || config.AttachStderr) && config.Tty && cli.isTerminalOut {
|
||||
if err := cli.monitorTtySize(ctx, createResponse.ID, false); err != nil {
|
||||
fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
if errCh != nil {
|
||||
if err := <-errCh; err != nil {
|
||||
logrus.Debugf("Error hijack: %s", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Detached mode: wait for the id to be displayed and return.
|
||||
if !config.AttachStdout && !config.AttachStderr {
|
||||
// Detached mode
|
||||
<-waitDisplayID
|
||||
return nil
|
||||
}
|
||||
|
||||
var status int
|
||||
|
||||
// Attached mode
|
||||
if *flAutoRemove {
|
||||
// Warn user if they detached us
|
||||
js, err := cli.client.ContainerInspect(ctx, createResponse.ID)
|
||||
if err != nil {
|
||||
return runStartContainerErr(err)
|
||||
}
|
||||
if js.State.Running == true || js.State.Paused == true {
|
||||
fmt.Fprintf(cli.err, "Detached from %s, awaiting its termination in order to uphold \"--rm\".\n",
|
||||
stringid.TruncateID(createResponse.ID))
|
||||
}
|
||||
|
||||
// Autoremove: wait for the container to finish, retrieve
|
||||
// the exit code and remove the container
|
||||
if status, err = cli.client.ContainerWait(ctx, createResponse.ID); err != nil {
|
||||
return runStartContainerErr(err)
|
||||
}
|
||||
if _, status, err = getExitCode(ctx, cli, createResponse.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// No Autoremove: Simply retrieve the exit code
|
||||
if !config.Tty {
|
||||
// In non-TTY mode, we can't detach, so we must wait for container exit
|
||||
if status, err = cli.client.ContainerWait(ctx, createResponse.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// In TTY mode, there is a race: if the process dies too slowly, the state could
|
||||
// be updated after the getExitCode call and result in the wrong exit code being reported
|
||||
if _, status, err = getExitCode(ctx, cli, createResponse.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if status != 0 {
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
42
vendor/github.com/hyperhq/hypercli/api/client/save.go
generated
vendored
42
vendor/github.com/hyperhq/hypercli/api/client/save.go
generated
vendored
@@ -1,42 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdSave saves one or more images to a tar archive.
|
||||
//
|
||||
// The tar archive is written to STDOUT by default, or written to a file.
|
||||
//
|
||||
// Usage: docker save [OPTIONS] IMAGE [IMAGE...]
|
||||
func (cli *DockerCli) Save(args ...string) error {
|
||||
cmd := Cli.Subcmd("save", []string{"IMAGE [IMAGE...]"}, Cli.DockerCommands["save"].Description+" (streamed to STDOUT by default)", true)
|
||||
outfile := cmd.String([]string{"o", "-output"}, "", "Write to a file, instead of STDOUT")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
if *outfile == "" && cli.isTerminalOut {
|
||||
return errors.New("Cowardly refusing to save to a terminal. Use the -o flag or redirect.")
|
||||
}
|
||||
|
||||
responseBody, err := cli.client.ImageSave(context.Background(), cmd.Args())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer responseBody.Close()
|
||||
|
||||
if *outfile == "" {
|
||||
_, err := io.Copy(cli.out, responseBody)
|
||||
return err
|
||||
}
|
||||
|
||||
return copyToFile(*outfile, responseBody)
|
||||
|
||||
}
|
||||
99
vendor/github.com/hyperhq/hypercli/api/client/search.go
generated
vendored
99
vendor/github.com/hyperhq/hypercli/api/client/search.go
generated
vendored
@@ -1,99 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
registrytypes "github.com/hyperhq/hyper-api/types/registry"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/pkg/stringutils"
|
||||
"github.com/hyperhq/hypercli/registry"
|
||||
)
|
||||
|
||||
// CmdSearch searches the Docker Hub for images.
|
||||
//
|
||||
// Usage: docker search [OPTIONS] TERM
|
||||
func (cli *DockerCli) CmdSearch(args ...string) error {
|
||||
cmd := Cli.Subcmd("search", []string{"TERM"}, Cli.DockerCommands["search"].Description, true)
|
||||
noTrunc := cmd.Bool([]string{"-no-trunc"}, false, "Don't truncate output")
|
||||
automated := cmd.Bool([]string{"-automated"}, false, "Only show automated builds")
|
||||
stars := cmd.Uint([]string{"s", "-stars"}, 0, "Only displays with at least x stars")
|
||||
cmd.Require(flag.Exact, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
name := cmd.Arg(0)
|
||||
v := url.Values{}
|
||||
v.Set("term", name)
|
||||
|
||||
indexInfo, err := registry.ParseSearchIndexInfo(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = cli.checkCloudConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
authConfig := cli.resolveAuthConfig(ctx, cli.configFile.AuthConfigs, indexInfo)
|
||||
requestPrivilege := cli.registryAuthenticationPrivilegedFunc(indexInfo, "search")
|
||||
|
||||
encodedAuth, err := encodeAuthToBase64(authConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
options := types.ImageSearchOptions{
|
||||
RegistryAuth: encodedAuth,
|
||||
PrivilegeFunc: requestPrivilege,
|
||||
}
|
||||
|
||||
unorderedResults, err := cli.client.ImageSearch(ctx, name, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
results := searchResultsByStars(unorderedResults)
|
||||
sort.Sort(results)
|
||||
|
||||
w := tabwriter.NewWriter(cli.out, 10, 1, 3, ' ', 0)
|
||||
fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tAUTOMATED\n")
|
||||
for _, res := range results {
|
||||
if (*automated && !res.IsAutomated) || (int(*stars) > res.StarCount) {
|
||||
continue
|
||||
}
|
||||
desc := strings.Replace(res.Description, "\n", " ", -1)
|
||||
desc = strings.Replace(desc, "\r", " ", -1)
|
||||
if !*noTrunc && len(desc) > 45 {
|
||||
desc = stringutils.Truncate(desc, 42) + "..."
|
||||
}
|
||||
fmt.Fprintf(w, "%s\t%s\t%d\t", res.Name, desc, res.StarCount)
|
||||
if res.IsOfficial {
|
||||
fmt.Fprint(w, "[OK]")
|
||||
|
||||
}
|
||||
fmt.Fprint(w, "\t")
|
||||
if res.IsAutomated {
|
||||
fmt.Fprint(w, "[OK]")
|
||||
}
|
||||
fmt.Fprint(w, "\n")
|
||||
}
|
||||
w.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
// SearchResultsByStars sorts search results in descending order by number of stars.
|
||||
type searchResultsByStars []registrytypes.SearchResult
|
||||
|
||||
func (r searchResultsByStars) Len() int { return len(r) }
|
||||
func (r searchResultsByStars) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
||||
func (r searchResultsByStars) Less(i, j int) bool { return r[j].StarCount < r[i].StarCount }
|
||||
423
vendor/github.com/hyperhq/hypercli/api/client/service.go
generated
vendored
423
vendor/github.com/hyperhq/hypercli/api/client/service.go
generated
vendored
@@ -1,423 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hyper-api/types/filters"
|
||||
"github.com/hyperhq/hyper-api/types/strslice"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
ropts "github.com/hyperhq/hypercli/opts"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/pkg/signal"
|
||||
"github.com/hyperhq/hypercli/runconfig/opts"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// CmdService is the parent subcommand for all service commands
|
||||
//
|
||||
// Usage: docker service <COMMAND> [OPTIONS]
|
||||
func (cli *DockerCli) CmdService(args ...string) error {
|
||||
cmd := Cli.Subcmd("service", []string{"COMMAND [OPTIONS]"}, serviceUsage(), false)
|
||||
cmd.Require(flag.Min, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
// CmdServiceCreate creates a new service with a given name
|
||||
//
|
||||
// Usage: hyper service create [OPTIONS] COUNT
|
||||
func (cli *DockerCli) CmdServiceCreate(args ...string) error {
|
||||
cmd := Cli.Subcmd("service create", []string{"IMAGE"}, "Create a new service", false)
|
||||
var (
|
||||
flSecurityGroups = ropts.NewListOpts(nil)
|
||||
flEnv = ropts.NewListOpts(opts.ValidateEnv)
|
||||
flLabels = ropts.NewListOpts(opts.ValidateEnv)
|
||||
flEnvFile = ropts.NewListOpts(nil)
|
||||
flVolumes = ropts.NewListOpts(nil)
|
||||
flLabelsFile = ropts.NewListOpts(nil)
|
||||
|
||||
flName = cmd.String([]string{"-name"}, "", "Service name")
|
||||
flStdin = cmd.Bool([]string{"i", "-interactive"}, false, "Keep STDIN open even if not attached")
|
||||
flTty = cmd.Bool([]string{"t", "-tty"}, false, "Allocate a pseudo-TTY")
|
||||
flEntrypoint = cmd.String([]string{"-entrypoint"}, "", "Overwrite the default ENTRYPOINT of the image")
|
||||
flNetMode = cmd.String([]string{}, "bridge", "Connect containers to a network, only bridge is supported now")
|
||||
flStopSignal = cmd.String([]string{"-stop-signal"}, signal.DefaultStopSignal, fmt.Sprintf("Signal to stop a container, %v by default", signal.DefaultStopSignal))
|
||||
flContainerSize = cmd.String([]string{"-size"}, "s4", "The size of service containers (e.g. s1, s2, s3, s4, m1, m2, m3, l1, l2, l3)")
|
||||
flWorkingDir = cmd.String([]string{"w", "-workdir"}, "", "Working directory inside the container")
|
||||
flSSLCert = cmd.String([]string{"-ssl-cert"}, "", "SSL cert file for httpsTerm service")
|
||||
flServicePort = cmd.Int([]string{"-service-port"}, 0, "Publish port of the service")
|
||||
flContainerPort = cmd.Int([]string{"-container-port"}, 0, "Container port of the service, default same with service port")
|
||||
flReplicas = cmd.Int([]string{"-replicas"}, -1, "Number of containers belonging to this service")
|
||||
flHealthCheckInterval = cmd.Int([]string{"-health-check-interval"}, 3, "Interval in seconds for health checking the containers")
|
||||
flHealthCheckFall = cmd.Int([]string{"-health-check-fall"}, 3, "Number of consecutive valid health checks before considering the server as DOWN")
|
||||
flHealthCheckRise = cmd.Int([]string{"-health-check-rise"}, 2, "Number of consecutive valid health checks before considering the server as UP")
|
||||
flSessionAffinity = cmd.Bool([]string{"-session-affinity"}, false, "Whether the service uses sticky sessions")
|
||||
flAlgorithm = cmd.String([]string{"-algorithm"}, types.LBAlgorithmRoundRobin, "Algorithm of the service (e.g. roundrobin, leastconn, source)")
|
||||
flProtocol = cmd.String([]string{"-protocol"}, types.LBProtocolTCP, "Protocol of the service (e.g. http, https, tcp, httpsTerm).")
|
||||
)
|
||||
cmd.Var(&flLabels, []string{"l", "-label"}, "Set meta data on a container")
|
||||
cmd.Var(&flLabelsFile, []string{"-label-file"}, "Read in a line delimited file of labels")
|
||||
cmd.Var(&flEnv, []string{"e", "-env"}, "Set environment variables")
|
||||
cmd.Var(&flEnvFile, []string{"-env-file"}, "Read in a file of environment variables")
|
||||
cmd.Var(&flSecurityGroups, []string{"-sg"}, "Security group for each container")
|
||||
cmd.Var(&flVolumes, []string{"v", "--volume"}, "Volume for each container")
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if *flReplicas <= 0 {
|
||||
return fmt.Errorf("replicas must be bigger than 0")
|
||||
}
|
||||
|
||||
var binds = map[string]struct{}{}
|
||||
// add any bind targets to the list of container services
|
||||
for bind := range flVolumes.GetMap() {
|
||||
binds[bind] = struct{}{}
|
||||
}
|
||||
var (
|
||||
parsedArgs = cmd.Args()
|
||||
runCmd strslice.StrSlice
|
||||
entrypoint strslice.StrSlice
|
||||
image = cmd.Arg(0)
|
||||
)
|
||||
|
||||
if _, _, err = cli.client.ImageInspectWithRaw(context.Background(), image, false); err != nil && strings.Contains(err.Error(), "No such image") {
|
||||
if err := cli.pullImage(context.Background(), image); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(parsedArgs) > 1 {
|
||||
runCmd = strslice.StrSlice(parsedArgs[1:])
|
||||
}
|
||||
if *flEntrypoint != "" {
|
||||
entrypoint = strslice.StrSlice{*flEntrypoint}
|
||||
}
|
||||
// collect all the environment variables for the container
|
||||
envVariables, err := opts.ReadKVStrings(flEnvFile.GetAll(), flEnv.GetAll())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// collect all the labels for the container
|
||||
labels, err := opts.ReadKVStrings(flLabelsFile.GetAll(), flLabels.GetAll())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var sgs = map[string]struct{}{}
|
||||
for sg := range flSecurityGroups.GetMap() {
|
||||
sgs[sg] = struct{}{}
|
||||
}
|
||||
|
||||
sslData := []byte{}
|
||||
if *flSSLCert != "" {
|
||||
sslData, err = ioutil.ReadFile(*flSSLCert)
|
||||
}
|
||||
|
||||
sv := types.Service{
|
||||
Name: *flName,
|
||||
Image: image,
|
||||
WorkingDir: *flWorkingDir,
|
||||
ContainerSize: *flContainerSize,
|
||||
ServicePort: *flServicePort,
|
||||
ContainerPort: *flContainerPort,
|
||||
Replicas: *flReplicas,
|
||||
Entrypoint: entrypoint,
|
||||
Cmd: runCmd,
|
||||
Env: envVariables,
|
||||
Volumes: binds,
|
||||
Labels: opts.ConvertKVStringsToMap(labels),
|
||||
SecurityGroups: sgs,
|
||||
Tty: *flTty,
|
||||
Stdin: *flStdin,
|
||||
NetMode: *flNetMode,
|
||||
StopSignal: *flStopSignal,
|
||||
HealthCheckInterval: *flHealthCheckInterval,
|
||||
HealthCheckFall: *flHealthCheckFall,
|
||||
HealthCheckRise: *flHealthCheckRise,
|
||||
Algorithm: *flAlgorithm,
|
||||
Protocol: *flProtocol,
|
||||
SessionAffinity: *flSessionAffinity,
|
||||
SSLCert: string(sslData),
|
||||
}
|
||||
|
||||
service, err := cli.client.ServiceCreate(context.Background(), sv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cli.out, "Service %s is created.\n", service.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdServiceDelete deletes one or more services
|
||||
//
|
||||
// Usage: hyper service rm service [service...]
|
||||
func (cli *DockerCli) CmdServiceRm(args ...string) error {
|
||||
cmd := Cli.Subcmd("service rm", []string{"service [service...]"}, "Remove one or more services", false)
|
||||
flKeep := cmd.Bool([]string{"-keep"}, false, "Keep the service container")
|
||||
cmd.Require(flag.Min, 1)
|
||||
if err := cmd.ParseFlags(args, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
status := 0
|
||||
for _, sn := range cmd.Args() {
|
||||
if err := cli.client.ServiceDelete(context.Background(), sn, *flKeep); err != nil {
|
||||
fmt.Fprintf(cli.err, "%s\n", err)
|
||||
status = 1
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(cli.out, "%s\n", sn)
|
||||
}
|
||||
if status != 0 {
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdServiceLs lists all the services
|
||||
//
|
||||
// Usage: hyper service ls [OPTIONS]
|
||||
func (cli *DockerCli) CmdServiceLs(args ...string) error {
|
||||
cmd := Cli.Subcmd("service ls", nil, "Lists services", true)
|
||||
|
||||
flFilter := ropts.NewListOpts(nil)
|
||||
cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided")
|
||||
|
||||
cmd.Require(flag.Exact, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Consolidate all filter flags, and sanity check them early.
|
||||
// They'll get process after get response from server.
|
||||
serviceFilterArgs := filters.NewArgs()
|
||||
for _, f := range flFilter.GetAll() {
|
||||
if serviceFilterArgs, err = filters.ParseFlag(f, serviceFilterArgs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
options := types.ServiceListOptions{
|
||||
Filters: serviceFilterArgs,
|
||||
}
|
||||
|
||||
services, err := cli.client.ServiceList(context.Background(), options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
||||
fmt.Fprintf(w, "Name\tFIP\tContainers\tStatus\tMessage\n")
|
||||
for _, service := range services {
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", service.Name, service.FIP, showContainersInList(service.Containers), service.Status, service.Message)
|
||||
}
|
||||
|
||||
w.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func showContainersInList(containers []string) string {
|
||||
var result = []string{}
|
||||
for _, c := range containers {
|
||||
result = append(result, c[:12])
|
||||
}
|
||||
if len(result) > 2 {
|
||||
return strings.Join([]string{result[0], result[1], "..."}, ", ")
|
||||
}
|
||||
return strings.Join(result, ", ")
|
||||
}
|
||||
|
||||
// CmdServiceInspect
|
||||
//
|
||||
// Usage: docker service inspect [OPTIONS] service [service...]
|
||||
func (cli *DockerCli) CmdServiceInspect(args ...string) error {
|
||||
cmd := Cli.Subcmd("service inspect", []string{"service [service...]"}, "Display detailed information on the given service", true)
|
||||
tmplStr := cmd.String([]string{"f", "-format"}, "", "Format the output using the given go template")
|
||||
|
||||
cmd.Require(flag.Min, 1)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
inspectSearcher := func(name string) (interface{}, []byte, error) {
|
||||
i, err := cli.client.ServiceInspect(ctx, name)
|
||||
return i, nil, err
|
||||
}
|
||||
|
||||
return cli.inspectElements(*tmplStr, cmd.Args(), inspectSearcher)
|
||||
}
|
||||
|
||||
// CmdServiceScale
|
||||
//
|
||||
// Usage: hyper service scale [OPTIONS] SERVICE=REPLICAS [SERVICE=REPLICAS...]
|
||||
func (cli *DockerCli) CmdServiceScale(args ...string) error {
|
||||
cmd := Cli.Subcmd("service scale", []string{"SERVICE=REPLICAS [SERVICE=REPLICAS...]"}, "", true)
|
||||
|
||||
cmd.Require(flag.Min, 1)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
for _, sr := range cmd.Args() {
|
||||
fields := strings.SplitN(sr, "=", 2)
|
||||
if len(fields) != 2 {
|
||||
fmt.Fprintf(cli.err, "invalid argument")
|
||||
continue
|
||||
}
|
||||
replicas, err := strconv.Atoi(fields[1])
|
||||
if err != nil {
|
||||
fmt.Fprintf(cli.err, "%v\n", err)
|
||||
continue
|
||||
}
|
||||
sv := types.ServiceUpdate{
|
||||
Replicas: &replicas,
|
||||
}
|
||||
|
||||
service, err := cli.client.ServiceUpdate(ctx, fields[0], sv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cli.out, "%s\n", service.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdServiceRolling_update
|
||||
//
|
||||
// Usage: hyper service rolling-update [OPTIONS] SERVICE [SERVICE...]
|
||||
func (cli *DockerCli) CmdServiceRolling_update(args ...string) error {
|
||||
cmd := Cli.Subcmd("service rolling-update", []string{"SERVICE [SERVICE...]"}, "Perform a rolling update of the given service", true)
|
||||
flImage := cmd.String([]string{"-image"}, "", "New container image")
|
||||
|
||||
cmd.Require(flag.Min, 1)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(*flImage) == 0 {
|
||||
return fmt.Errorf("image is required for rolling-update")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
if _, _, err := cli.client.ImageInspectWithRaw(ctx, *flImage, false); err != nil && strings.Contains(err.Error(), "No such image") {
|
||||
if err := cli.pullImage(ctx, *flImage); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, sr := range cmd.Args() {
|
||||
sv := types.ServiceUpdate{
|
||||
Image: flImage,
|
||||
}
|
||||
|
||||
service, err := cli.client.ServiceUpdate(ctx, sr, sv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cli.out, "Rolling-update is requested for service %s.\n", service.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdServiceAttach_fip
|
||||
//
|
||||
// Usage: hyper service attach_fip [OPTIONS] SERVICE [SERVICE...]
|
||||
func (cli *DockerCli) CmdServiceAttach_fip(args ...string) error {
|
||||
cmd := Cli.Subcmd("service attach-fip", []string{"SERVICE"}, "Attach a fip to the service", true)
|
||||
flFip := cmd.String([]string{"-fip"}, "", "Attach a fip to the service")
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
if *flFip == "" {
|
||||
return fmt.Errorf("Error: please provide the attached FIP via --fip")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
sv := types.ServiceUpdate{
|
||||
FIP: flFip,
|
||||
}
|
||||
|
||||
service, err := cli.client.ServiceUpdate(ctx, cmd.Arg(0), sv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cli.out, "%s\n", service.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdServiceDetach_fip
|
||||
//
|
||||
// Usage: hyper service detach_fip [OPTIONS] SERVICE [SERVICE...]
|
||||
func (cli *DockerCli) CmdServiceDetach_fip(args ...string) error {
|
||||
cmd := Cli.Subcmd("service detach-fip", []string{"SERVICE [SERVICE...]"}, "Detach a fip from the service", true)
|
||||
|
||||
cmd.Require(flag.Min, 1)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
fip := ""
|
||||
for _, sr := range cmd.Args() {
|
||||
sv := types.ServiceUpdate{
|
||||
FIP: &fip,
|
||||
}
|
||||
|
||||
service, err := cli.client.ServiceUpdate(ctx, sr, sv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cli.out, "%s\n", service.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func serviceUsage() string {
|
||||
serviceCommands := [][]string{
|
||||
{"create", "Create a service"},
|
||||
{"inspect", "Display detailed information on the given service"},
|
||||
{"ls", "List all services"},
|
||||
{"scale", "Scale the service"},
|
||||
{"rolling-update", "Perform a rolling update of the given service"},
|
||||
{"attach-fip", "Attach a fip to the service"},
|
||||
{"detach-fip", "Detach the fip from the service"},
|
||||
{"rm", "Remove one or more services"},
|
||||
}
|
||||
|
||||
help := "Commands:\n"
|
||||
|
||||
for _, cmd := range serviceCommands {
|
||||
help += fmt.Sprintf(" %-25.25s%s\n", cmd[0], cmd[1])
|
||||
}
|
||||
|
||||
help += fmt.Sprintf("\nRun 'hyper service COMMAND --help' for more information on a command.")
|
||||
return help
|
||||
}
|
||||
167
vendor/github.com/hyperhq/hypercli/api/client/sg.go
generated
vendored
167
vendor/github.com/hyperhq/hypercli/api/client/sg.go
generated
vendored
@@ -1,167 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"golang.org/x/net/context"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// CmdSg is the parent subcommand for all sg commands
|
||||
//
|
||||
// Usage: hyper sg <COMMAND> [OPTIONS]
|
||||
func (cli *DockerCli) CmdSg(args ...string) error {
|
||||
cmd := Cli.Subcmd("sg", []string{"COMMAND [OPTIONS]"}, sgUsage(), false)
|
||||
cmd.Require(flag.Min, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
// CmdSgCreate creates a new sg with a given name
|
||||
//
|
||||
// Usage: hyper sg create [OPTIONS] NAME
|
||||
func (cli *DockerCli) CmdSgCreate(args ...string) error {
|
||||
cmd := Cli.Subcmd("sg create", []string{"NAME"}, "Create a new security group", false)
|
||||
file := cmd.String([]string{"f", "-file"}, "", "Yaml file to create security group")
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := os.Open(*file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = cli.client.SgCreate(context.Background(), cmd.Arg(0), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdSgRm removes a sg with a given name
|
||||
//
|
||||
// Usage: hyper sg rm [OPTIONS] NAME
|
||||
func (cli *DockerCli) CmdSgRm(args ...string) error {
|
||||
cmd := Cli.Subcmd("sg rm", []string{"NAME"}, "Remove a security group", false)
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = cli.client.SgRm(context.Background(), cmd.Arg(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdSgLs list security groups
|
||||
//
|
||||
// Usage: hyper sg ls [OPTIONS]
|
||||
func (cli *DockerCli) CmdSgLs(args ...string) error {
|
||||
cmd := Cli.Subcmd("sg ls", []string{}, "List security groups", false)
|
||||
|
||||
cmd.Require(flag.Exact, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sgs, err := cli.client.SgLs(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
||||
fmt.Fprintf(w, "Name\tDescription")
|
||||
fmt.Fprintf(w, "\n")
|
||||
for _, sg := range sgs {
|
||||
fmt.Fprintf(w, "%s\t%s\n", sg.GroupName, sg.Description)
|
||||
}
|
||||
w.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdSgInspect Inspect security groups
|
||||
//
|
||||
// Usage: hyper sg inspect [OPTIONS] NAME
|
||||
func (cli *DockerCli) CmdSgInspect(args ...string) error {
|
||||
cmd := Cli.Subcmd("sg inspect", []string{"NAME"}, "Inspect the security group", false)
|
||||
output := cmd.String([]string{"o", "-output"}, "json", "Output format with inspect operation (e.g. yaml or json)")
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sg, err := cli.client.SgInspect(context.Background(), cmd.Arg(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var data []byte
|
||||
if *output == "json" {
|
||||
data, err = json.MarshalIndent(sg, "", "\t")
|
||||
} else {
|
||||
data, err = yaml.Marshal(sg)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s\n", string(data))
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdSgUpdate Update the security group
|
||||
//
|
||||
// Usage: hyper sg update [OPTIONS] NAME
|
||||
func (cli *DockerCli) CmdSgUpdate(args ...string) error {
|
||||
cmd := Cli.Subcmd("sg update", []string{"NAME"}, "Update the security group", false)
|
||||
file := cmd.String([]string{"f", "-file"}, "", "Yaml file to update security group")
|
||||
|
||||
cmd.Require(flag.Exact, 1)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := os.Open(*file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = cli.client.SgUpdate(context.Background(), cmd.Arg(0), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func sgUsage() string {
|
||||
sgCommands := [][]string{
|
||||
{"create", "Create a new security group"},
|
||||
{"ls", "List all security groups"},
|
||||
{"rm", "Remove a security group"},
|
||||
{"inspect", "Inspect the security group"},
|
||||
{"update", "Update the security group"},
|
||||
}
|
||||
|
||||
help := "Commands:\n"
|
||||
|
||||
for _, cmd := range sgCommands {
|
||||
help += fmt.Sprintf(" %-25.25s%s\n", cmd[0], cmd[1])
|
||||
}
|
||||
|
||||
help += fmt.Sprintf("\nRun 'hyper sg COMMAND --help' for more information on a command.")
|
||||
return help
|
||||
}
|
||||
160
vendor/github.com/hyperhq/hypercli/api/client/snapshot.go
generated
vendored
160
vendor/github.com/hyperhq/hypercli/api/client/snapshot.go
generated
vendored
@@ -1,160 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"text/tabwriter"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hyper-api/types/filters"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/opts"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdSnapshot is the parent subcommand for all snapshot commands
|
||||
//
|
||||
// Usage: docker snapshot <COMMAND> <OPTS>
|
||||
func (cli *DockerCli) CmdSnapshot(args ...string) error {
|
||||
description := Cli.DockerCommands["snapshot"].Description + "\n\nSnapshots:\n"
|
||||
commands := [][]string{
|
||||
{"create", "Create a snapshot"},
|
||||
{"inspect", "Return low-level information on a snapshot"},
|
||||
{"ls", "List snapshots"},
|
||||
{"rm", "Remove a snapshot"},
|
||||
}
|
||||
|
||||
for _, cmd := range commands {
|
||||
description += fmt.Sprintf(" %-25.25s%s\n", cmd[0], cmd[1])
|
||||
}
|
||||
|
||||
description += "\nRun 'hyper snapshot COMMAND --help' for more information on a command"
|
||||
cmd := Cli.Subcmd("snapshot", []string{"[COMMAND]"}, description, false)
|
||||
|
||||
cmd.Require(flag.Exact, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
// CmdSnapshotLs outputs a list of Docker snapshots.
|
||||
//
|
||||
// Usage: hyper snapshot ls [OPTIONS]
|
||||
func (cli *DockerCli) CmdSnapshotLs(args ...string) error {
|
||||
cmd := Cli.Subcmd("snapshot ls", nil, "List snapshots", true)
|
||||
|
||||
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display snapshot names")
|
||||
flFilter := opts.NewListOpts(nil)
|
||||
cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")
|
||||
|
||||
cmd.Require(flag.Exact, 0)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
volFilterArgs := filters.NewArgs()
|
||||
for _, f := range flFilter.GetAll() {
|
||||
var err error
|
||||
volFilterArgs, err = filters.ParseFlag(f, volFilterArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
snapshots, err := cli.client.SnapshotList(context.Background(), volFilterArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
||||
if !*quiet {
|
||||
for _, warn := range snapshots.Warnings {
|
||||
fmt.Fprintln(cli.err, warn)
|
||||
}
|
||||
fmt.Fprintf(w, "Snapshot Name \tVolume\tSize")
|
||||
fmt.Fprintf(w, "\n")
|
||||
}
|
||||
|
||||
for _, vol := range snapshots.Snapshots {
|
||||
if *quiet {
|
||||
fmt.Fprintln(w, vol.Name)
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(w, "%s\t%s\t%d\n", vol.Name, vol.Volume, vol.Size)
|
||||
}
|
||||
w.Flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdSnapshotInspect displays low-level information on one or more snapshots.
|
||||
//
|
||||
// Usage: docker snapshot inspect [OPTIONS] snapshot [snapshot...]
|
||||
func (cli *DockerCli) CmdSnapshotInspect(args ...string) error {
|
||||
cmd := Cli.Subcmd("snapshot inspect", []string{"snapshot [snapshot...]"}, "Return low-level information on a snapshot", true)
|
||||
tmplStr := cmd.String([]string{"f", "-format"}, "", "Format the output using the given go template")
|
||||
|
||||
cmd.Require(flag.Min, 1)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
inspectSearcher := func(name string) (interface{}, []byte, error) {
|
||||
i, err := cli.client.SnapshotInspect(context.Background(), name)
|
||||
return i, nil, err
|
||||
}
|
||||
|
||||
return cli.inspectElements(*tmplStr, cmd.Args(), inspectSearcher)
|
||||
}
|
||||
|
||||
// CmdSnapshotCreate creates a new snapshot.
|
||||
//
|
||||
// Usage: docker snapshot create [OPTIONS]
|
||||
func (cli *DockerCli) CmdSnapshotCreate(args ...string) error {
|
||||
cmd := Cli.Subcmd("snapshot create", []string{"-v volume"}, "Create a snapshot", true)
|
||||
flForce := cmd.Bool([]string{"f", "-force"}, false, "Force to create snapshot, needed if volume is in use")
|
||||
flVolume := cmd.String([]string{"v", "-volume"}, "", "Specify volume to create snapshot")
|
||||
flName := cmd.String([]string{"-name"}, "", "Specify snapshot name")
|
||||
|
||||
cmd.Require(flag.Exact, 0)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
volReq := types.SnapshotCreateRequest{
|
||||
Name: *flName,
|
||||
Volume: *flVolume,
|
||||
Force: *flForce,
|
||||
}
|
||||
|
||||
vol, err := cli.client.SnapshotCreate(context.Background(), volReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(cli.out, "%s\n", vol.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdSnapshotRm removes one or more snapshots.
|
||||
//
|
||||
// Usage: docker snapshot rm snapshot [snapshot...]
|
||||
func (cli *DockerCli) CmdSnapshotRm(args ...string) error {
|
||||
cmd := Cli.Subcmd("snapshot rm", []string{"snapshot [snapshot...]"}, "Remove a snapshot", true)
|
||||
cmd.Require(flag.Min, 1)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
var status = 0
|
||||
|
||||
for _, name := range cmd.Args() {
|
||||
if err := cli.client.SnapshotRemove(context.Background(), name); err != nil {
|
||||
fmt.Fprintf(cli.err, "%s\n", err)
|
||||
status = 1
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(cli.out, "%s\n", name)
|
||||
}
|
||||
|
||||
if status != 0 {
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
158
vendor/github.com/hyperhq/hypercli/api/client/start.go
generated
vendored
158
vendor/github.com/hyperhq/hypercli/api/client/start.go
generated
vendored
@@ -1,158 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/pkg/promise"
|
||||
"github.com/hyperhq/hypercli/pkg/signal"
|
||||
)
|
||||
|
||||
func (cli *DockerCli) forwardAllSignals(ctx context.Context, cid string) chan os.Signal {
|
||||
sigc := make(chan os.Signal, 128)
|
||||
signal.CatchAll(sigc)
|
||||
go func() {
|
||||
for s := range sigc {
|
||||
if s == signal.SIGCHLD {
|
||||
continue
|
||||
}
|
||||
var sig string
|
||||
for sigStr, sigN := range signal.SignalMap {
|
||||
if sigN == s {
|
||||
sig = sigStr
|
||||
break
|
||||
}
|
||||
}
|
||||
if sig == "" {
|
||||
fmt.Fprintf(cli.err, "Unsupported signal: %v. Discarding.\n", s)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := cli.client.ContainerKill(ctx, cid, sig); err != nil {
|
||||
logrus.Debugf("Error sending signal: %s", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
return sigc
|
||||
}
|
||||
|
||||
// CmdStart starts one or more containers.
|
||||
//
|
||||
// Usage: docker start [OPTIONS] CONTAINER [CONTAINER...]
|
||||
func (cli *DockerCli) CmdStart(args ...string) error {
|
||||
cmd := Cli.Subcmd("start", []string{"CONTAINER [CONTAINER...]"}, Cli.DockerCommands["start"].Description, true)
|
||||
attach := cmd.Bool([]string{"a", "-attach"}, false, "Attach STDOUT/STDERR and forward signals")
|
||||
openStdin := cmd.Bool([]string{"i", "-interactive"}, false, "Attach container's STDIN")
|
||||
detachKeys := cmd.String([]string{}, "", "Override the key sequence for detaching a container")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
if *attach || *openStdin {
|
||||
// We're going to attach to a container.
|
||||
// 1. Ensure we only have one container.
|
||||
if cmd.NArg() > 1 {
|
||||
return fmt.Errorf("You cannot start and attach multiple containers at once.")
|
||||
}
|
||||
|
||||
// 2. Attach to the container.
|
||||
containerID := cmd.Arg(0)
|
||||
c, err := cli.client.ContainerInspect(ctx, containerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !c.Config.Tty {
|
||||
sigc := cli.forwardAllSignals(ctx, containerID)
|
||||
defer signal.StopCatch(sigc)
|
||||
}
|
||||
|
||||
if *detachKeys != "" {
|
||||
cli.configFile.DetachKeys = *detachKeys
|
||||
}
|
||||
|
||||
options := types.ContainerAttachOptions{
|
||||
Stream: true,
|
||||
Stdin: *openStdin && c.Config.OpenStdin,
|
||||
Stdout: true,
|
||||
Stderr: true,
|
||||
DetachKeys: cli.configFile.DetachKeys,
|
||||
}
|
||||
|
||||
var in io.ReadCloser
|
||||
if options.Stdin {
|
||||
in = cli.in
|
||||
}
|
||||
|
||||
resp, err := cli.client.ContainerAttach(ctx, containerID, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Close()
|
||||
if in != nil && c.Config.Tty {
|
||||
if err := cli.setRawTerminal(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.restoreTerminal(in)
|
||||
}
|
||||
|
||||
cErr := promise.Go(func() error {
|
||||
return cli.holdHijackedConnection(c.Config.Tty, in, cli.out, cli.err, resp)
|
||||
})
|
||||
|
||||
// 3. Start the container.
|
||||
if err := cli.client.ContainerStart(ctx, containerID, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 4. Wait for attachment to break.
|
||||
if c.Config.Tty && cli.isTerminalOut {
|
||||
if err := cli.monitorTtySize(ctx, containerID, false); err != nil {
|
||||
fmt.Fprintf(cli.err, "Error monitoring TTY size: %s\n", err)
|
||||
}
|
||||
}
|
||||
if attchErr := <-cErr; attchErr != nil {
|
||||
return attchErr
|
||||
}
|
||||
_, status, err := getExitCode(ctx, cli, containerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if status != 0 {
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
} else {
|
||||
// We're not going to attach to anything.
|
||||
// Start as many containers as we want.
|
||||
return cli.startContainersWithoutAttachments(ctx, cmd.Args())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) startContainersWithoutAttachments(ctx context.Context, containerIDs []string) error {
|
||||
var failedContainers []string
|
||||
for _, containerID := range containerIDs {
|
||||
if err := cli.client.ContainerStart(ctx, containerID, ""); err != nil {
|
||||
fmt.Fprintf(cli.err, "%s\n", err)
|
||||
failedContainers = append(failedContainers, containerID)
|
||||
} else {
|
||||
fmt.Fprintf(cli.out, "%s\n", containerID)
|
||||
}
|
||||
}
|
||||
|
||||
if len(failedContainers) > 0 {
|
||||
return fmt.Errorf("Error: failed to start containers: %v", strings.Join(failedContainers, ", "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
190
vendor/github.com/hyperhq/hypercli/api/client/stats.go
generated
vendored
190
vendor/github.com/hyperhq/hypercli/api/client/stats.go
generated
vendored
@@ -1,190 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hyper-api/types/events"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/cli/command"
|
||||
"github.com/hyperhq/hypercli/cli/command/formatter"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// CmdStats displays a live stream of resource usage statistics for one or more containers.
|
||||
//
|
||||
// This shows real-time information on CPU usage, memory usage, and network I/O.
|
||||
//
|
||||
// Usage: hyper stats [OPTIONS] [CONTAINER...]
|
||||
func (cli *DockerCli) CmdStats(args ...string) error {
|
||||
cmd := Cli.Subcmd("stats", []string{"[CONTAINER...]"}, Cli.DockerCommands["stats"].Description, true)
|
||||
all := cmd.Bool([]string{"a", "-all"}, false, "Show all containers (default shows just running)")
|
||||
noStream := cmd.Bool([]string{"-no-stream"}, false, "Disable streaming stats and only pull the first result")
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
names := cmd.Args()
|
||||
showAll := len(names) == 0
|
||||
closeChan := make(chan error)
|
||||
ctx := context.Background()
|
||||
eventChan := make(chan events.Message)
|
||||
|
||||
// monitorContainerEvents watches for container creation and removal (only
|
||||
// used when calling `docker stats` without arguments).
|
||||
monitorContainerEvents := func(started chan<- struct{}, c chan events.Message) {
|
||||
eventq, errq := cli.Events(ctx)
|
||||
|
||||
// Whether we successfully subscribed to eventq or not, we can now
|
||||
// unblock the main goroutine.
|
||||
close(started)
|
||||
|
||||
for {
|
||||
select {
|
||||
case event := <-eventq:
|
||||
c <- event
|
||||
case err := <-errq:
|
||||
closeChan <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// waitFirst is a WaitGroup to wait first stat data's reach for each container
|
||||
waitFirst := &sync.WaitGroup{}
|
||||
|
||||
cStats := stats{}
|
||||
// getContainerList simulates creation event for all previously existing
|
||||
// containers (only used when calling `docker stats` without arguments).
|
||||
getContainerList := func() {
|
||||
options := types.ContainerListOptions{
|
||||
All: *all,
|
||||
}
|
||||
cs, err := cli.client.ContainerList(ctx, options)
|
||||
if err != nil {
|
||||
closeChan <- err
|
||||
}
|
||||
for _, container := range cs {
|
||||
s := formatter.NewContainerStats(container.ID[:12])
|
||||
if cStats.add(s) {
|
||||
waitFirst.Add(1)
|
||||
go collect(ctx, s, cli, !*noStream, waitFirst, eventChan, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if showAll {
|
||||
// If no names were specified, start a long running goroutine which
|
||||
// monitors container events. We make sure we're subscribed before
|
||||
// retrieving the list of running containers to avoid a race where we
|
||||
// would "miss" a creation.
|
||||
started := make(chan struct{})
|
||||
eh := command.InitEventHandler()
|
||||
|
||||
eh.Handle("start", func(e events.Message) {
|
||||
s := formatter.NewContainerStats(e.ID[:12])
|
||||
if cStats.add(s) {
|
||||
waitFirst.Add(1)
|
||||
go collect(ctx, s, cli, !*noStream, waitFirst, eventChan, false)
|
||||
}
|
||||
})
|
||||
|
||||
eh.Handle("stop", func(e events.Message) {
|
||||
if !*all {
|
||||
cStats.remove(e.ID[:12])
|
||||
}
|
||||
})
|
||||
|
||||
go eh.Watch(eventChan)
|
||||
go monitorContainerEvents(started, eventChan)
|
||||
defer close(eventChan)
|
||||
<-started
|
||||
|
||||
// Start a short-lived goroutine to retrieve the initial list of
|
||||
// containers.
|
||||
getContainerList()
|
||||
} else {
|
||||
// Artificially send creation events for the containers we were asked to
|
||||
// monitor (same code path than we use when monitoring all containers).
|
||||
for _, name := range names {
|
||||
s := formatter.NewContainerStats(name)
|
||||
if cStats.add(s) {
|
||||
waitFirst.Add(1)
|
||||
go collect(ctx, s, cli, !*noStream, waitFirst, nil, true)
|
||||
}
|
||||
}
|
||||
|
||||
// We don't expect any asynchronous errors: closeChan can be closed.
|
||||
close(closeChan)
|
||||
|
||||
// Do a quick pause to detect any error with the provided list of
|
||||
// container names.
|
||||
time.Sleep(1500 * time.Millisecond)
|
||||
var errs []string
|
||||
cStats.mu.Lock()
|
||||
for _, c := range cStats.cs {
|
||||
cErr := c.GetError()
|
||||
if cErr != nil {
|
||||
errs = append(errs, fmt.Sprintf("%s: %v", c.Name, cErr))
|
||||
}
|
||||
}
|
||||
cStats.mu.Unlock()
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("%s", strings.Join(errs, ", "))
|
||||
}
|
||||
}
|
||||
|
||||
// before print to screen, make sure each container get at least one valid stat data
|
||||
waitFirst.Wait()
|
||||
|
||||
statsCtx := formatter.Context{
|
||||
Output: cli.out,
|
||||
Format: formatter.NewStatsFormat(formatter.TableFormatKey),
|
||||
}
|
||||
|
||||
cleanScreen := func() {
|
||||
if !*noStream {
|
||||
fmt.Fprint(cli.out, "\033[2J")
|
||||
fmt.Fprint(cli.out, "\033[H")
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
for range time.Tick(500 * time.Millisecond) {
|
||||
cleanScreen()
|
||||
ccstats := []formatter.StatsEntry{}
|
||||
cStats.mu.Lock()
|
||||
for _, c := range cStats.cs {
|
||||
ccstats = append(ccstats, c.GetStatistics())
|
||||
}
|
||||
cStats.mu.Unlock()
|
||||
if err = formatter.ContainerStatsWrite(statsCtx, ccstats); err != nil {
|
||||
break
|
||||
}
|
||||
if len(cStats.cs) == 0 && !showAll {
|
||||
break
|
||||
}
|
||||
if *noStream {
|
||||
break
|
||||
}
|
||||
select {
|
||||
case err, ok := <-closeChan:
|
||||
if ok {
|
||||
if err != nil {
|
||||
// this is suppressing "unexpected EOF" in the cli when the
|
||||
// daemon restarts so it shutdowns cleanly
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
// just skip
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
206
vendor/github.com/hyperhq/hypercli/api/client/stats_helper.go
generated
vendored
206
vendor/github.com/hyperhq/hypercli/api/client/stats_helper.go
generated
vendored
@@ -1,206 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hyper-api/types/events"
|
||||
"github.com/hyperhq/hypercli/cli/command/formatter"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type stats struct {
|
||||
mu sync.Mutex
|
||||
cs []*formatter.ContainerStats
|
||||
}
|
||||
|
||||
func (s *stats) add(cs *formatter.ContainerStats) bool {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if _, exists := s.isKnownContainer(cs.Container); !exists {
|
||||
s.cs = append(s.cs, cs)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *stats) remove(id string) {
|
||||
s.mu.Lock()
|
||||
if i, exists := s.isKnownContainer(id); exists {
|
||||
s.cs = append(s.cs[:i], s.cs[i+1:]...)
|
||||
}
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
func (s *stats) isKnownContainer(cid string) (int, bool) {
|
||||
for i, c := range s.cs {
|
||||
if c.Container == cid {
|
||||
return i, true
|
||||
}
|
||||
}
|
||||
return -1, false
|
||||
}
|
||||
|
||||
func collect(ctx context.Context, s *formatter.ContainerStats, cli *DockerCli, streamStats bool, waitFirst *sync.WaitGroup, c chan events.Message, specified bool) {
|
||||
var (
|
||||
getFirst bool
|
||||
previousCPU uint64
|
||||
previousSystem uint64
|
||||
u = make(chan error, 1)
|
||||
end = make(chan bool, 1)
|
||||
)
|
||||
|
||||
defer func() {
|
||||
// if error happens and we get nothing of stats, release wait group whatever
|
||||
if !getFirst {
|
||||
getFirst = true
|
||||
waitFirst.Done()
|
||||
}
|
||||
}()
|
||||
|
||||
responseBody, err := cli.client.ContainerStats(ctx, s.Container, streamStats)
|
||||
if err != nil {
|
||||
s.SetError(err)
|
||||
return
|
||||
}
|
||||
defer responseBody.Close()
|
||||
|
||||
dec := json.NewDecoder(responseBody)
|
||||
go func() {
|
||||
for {
|
||||
var (
|
||||
v *types.StatsJSON
|
||||
memPercent = 0.0
|
||||
cpuPercent = 0.0
|
||||
blkRead, blkWrite uint64
|
||||
mem = 0.0
|
||||
memLimit = 0.0
|
||||
memPerc = 0.0
|
||||
)
|
||||
|
||||
if err := dec.Decode(&v); err != nil {
|
||||
dec = json.NewDecoder(io.MultiReader(dec.Buffered(), responseBody))
|
||||
u <- err
|
||||
// TODO: add EOF in hyper.sh
|
||||
if err == io.EOF {
|
||||
end <- true
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
|
||||
// if mem usage == 0, we think this container is stopped.
|
||||
if v.MemoryStats.Usage == 0 {
|
||||
if !specified {
|
||||
stopEvent := events.Message{
|
||||
ID: s.Container,
|
||||
Action: "stop",
|
||||
}
|
||||
c <- stopEvent
|
||||
end <- true
|
||||
break
|
||||
} else {
|
||||
u <- errors.New("This container is stopped.")
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// MemoryStats.Limit will never be 0 unless the container is not running and we haven't
|
||||
// got any data from cgroup
|
||||
if v.MemoryStats.Limit != 0 {
|
||||
memPercent = float64(v.MemoryStats.Usage) / float64(v.MemoryStats.Limit) * 100.0
|
||||
}
|
||||
|
||||
previousCPU = v.PreCPUStats.CPUUsage.TotalUsage
|
||||
previousSystem = v.PreCPUStats.SystemUsage
|
||||
cpuPercent = calculateCPUPercent(previousCPU, previousSystem, v)
|
||||
blkRead, blkWrite = calculateBlockIO(v.BlkioStats)
|
||||
mem = float64(v.MemoryStats.Usage)
|
||||
memLimit = float64(v.MemoryStats.Limit)
|
||||
memPerc = memPercent
|
||||
netRx, netTx := calculateNetwork(v.Networks)
|
||||
|
||||
s.SetStatistics(formatter.StatsEntry{
|
||||
CPUPercentage: cpuPercent,
|
||||
Memory: mem,
|
||||
MemoryPercentage: memPerc,
|
||||
MemoryLimit: memLimit,
|
||||
NetworkRx: netRx,
|
||||
NetworkTx: netTx,
|
||||
BlockRead: float64(blkRead),
|
||||
BlockWrite: float64(blkWrite),
|
||||
})
|
||||
u <- nil
|
||||
if !streamStats {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-time.After(2 * time.Second):
|
||||
// zero out the values if we have not received an update within
|
||||
// the specified duration.
|
||||
s.SetErrorAndReset(errors.New("timeout waiting for stats"))
|
||||
// if this is the first stat you get, release WaitGroup
|
||||
if !getFirst {
|
||||
getFirst = true
|
||||
waitFirst.Done()
|
||||
}
|
||||
case err := <-u:
|
||||
if err != nil {
|
||||
s.SetError(err)
|
||||
continue
|
||||
}
|
||||
s.SetError(nil)
|
||||
// if this is the first stat you get, release WaitGroup
|
||||
if !getFirst {
|
||||
getFirst = true
|
||||
waitFirst.Done()
|
||||
}
|
||||
case <-end:
|
||||
s.SetError(errors.New("This container is stopped."))
|
||||
if !getFirst {
|
||||
getFirst = true
|
||||
waitFirst.Done()
|
||||
}
|
||||
break
|
||||
}
|
||||
if !streamStats {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func calculateCPUPercent(previousCPU, previousSystem uint64, v *types.StatsJSON) float64 {
|
||||
return float64(v.CPUStats.CPUUsage.TotalUsage) / 100.0
|
||||
}
|
||||
|
||||
func calculateBlockIO(blkio types.BlkioStats) (blkRead uint64, blkWrite uint64) {
|
||||
for _, bioEntry := range blkio.IoServiceBytesRecursive {
|
||||
switch strings.ToLower(bioEntry.Op) {
|
||||
case "read":
|
||||
blkRead = blkRead + bioEntry.Value
|
||||
case "write":
|
||||
blkWrite = blkWrite + bioEntry.Value
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func calculateNetwork(network map[string]types.NetworkStats) (float64, float64) {
|
||||
var rx, tx float64
|
||||
|
||||
for _, v := range network {
|
||||
rx += float64(v.RxBytes)
|
||||
tx += float64(v.TxBytes)
|
||||
}
|
||||
return rx, tx
|
||||
}
|
||||
39
vendor/github.com/hyperhq/hypercli/api/client/stop.go
generated
vendored
39
vendor/github.com/hyperhq/hypercli/api/client/stop.go
generated
vendored
@@ -1,39 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdStop stops one or more containers.
|
||||
//
|
||||
// A running container is stopped by first sending SIGTERM and then SIGKILL if the container fails to stop within a grace period (the default is 10 seconds).
|
||||
//
|
||||
// Usage: docker stop [OPTIONS] CONTAINER [CONTAINER...]
|
||||
func (cli *DockerCli) CmdStop(args ...string) error {
|
||||
cmd := Cli.Subcmd("stop", []string{"CONTAINER [CONTAINER...]"}, Cli.DockerCommands["stop"].Description+".\nSending SIGTERM and then SIGKILL after a grace period", true)
|
||||
nSeconds := cmd.Int([]string{"t", "-time"}, 10, "Seconds to wait for stop before killing it")
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
var errs []string
|
||||
for _, name := range cmd.Args() {
|
||||
if err := cli.client.ContainerStop(ctx, name, *nSeconds); err != nil {
|
||||
errs = append(errs, err.Error())
|
||||
} else {
|
||||
fmt.Fprintf(cli.out, "%s\n", name)
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("%s", strings.Join(errs, "\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
26
vendor/github.com/hyperhq/hypercli/api/client/tag.go
generated
vendored
26
vendor/github.com/hyperhq/hypercli/api/client/tag.go
generated
vendored
@@ -1,26 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdTag tags an image into a repository.
|
||||
//
|
||||
// Usage: docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
|
||||
func (cli *DockerCli) Tag(args ...string) error {
|
||||
cmd := Cli.Subcmd("tag", []string{"IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]"}, Cli.DockerCommands["tag"].Description, true)
|
||||
force := cmd.Bool([]string{"#f", "#-force"}, false, "Force the tagging even if there's a conflict")
|
||||
cmd.Require(flag.Exact, 2)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
options := types.ImageTagOptions{
|
||||
Force: *force,
|
||||
}
|
||||
|
||||
return cli.client.ImageTag(context.Background(), cmd.Arg(0), cmd.Arg(1), options)
|
||||
}
|
||||
246
vendor/github.com/hyperhq/hypercli/api/client/tarfile.go
generated
vendored
246
vendor/github.com/hyperhq/hypercli/api/client/tarfile.go
generated
vendored
@@ -1,246 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/cheggaaa/pb"
|
||||
)
|
||||
|
||||
const (
|
||||
TARINFO_HEADER = iota
|
||||
TARINFO_FILE
|
||||
TARINFO_PAD
|
||||
TARINFO_UPLOADED
|
||||
TARINFO_FINISHED
|
||||
)
|
||||
|
||||
type tarInfo struct {
|
||||
info os.FileInfo
|
||||
relPath string
|
||||
linkName string
|
||||
path string
|
||||
pad int // number of zeros to pad at the end of the file entry
|
||||
|
||||
headerBuf *bytes.Buffer
|
||||
pos int64
|
||||
state int
|
||||
}
|
||||
|
||||
type TarFile struct {
|
||||
fileList []*tarInfo
|
||||
blockSize int
|
||||
endPad int
|
||||
padding []byte
|
||||
closed bool
|
||||
|
||||
source string
|
||||
progress *pb.ProgressBar
|
||||
}
|
||||
|
||||
func (t *TarFile) writeHeader(p []byte, info *tarInfo) (int, error) {
|
||||
if info.headerBuf == nil {
|
||||
header, err := tar.FileInfoHeader(info.info, info.linkName)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
header.Name = info.relPath
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
tarWriter := tar.NewWriter(buf)
|
||||
defer tarWriter.Close()
|
||||
err = tarWriter.WriteHeader(header)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
info.headerBuf = &bytes.Buffer{}
|
||||
io.Copy(info.headerBuf, buf)
|
||||
}
|
||||
|
||||
size, err := info.headerBuf.Read(p)
|
||||
if err != nil && err != io.EOF {
|
||||
return 0, err
|
||||
}
|
||||
if info.headerBuf.Len() == 0 {
|
||||
info.headerBuf.Truncate(0)
|
||||
}
|
||||
return size, nil
|
||||
}
|
||||
|
||||
func (t *TarFile) writeFile(p []byte, info *tarInfo) (int, error) {
|
||||
var f *os.File
|
||||
var err error
|
||||
|
||||
if f, err = os.Open(info.path); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer f.Close()
|
||||
// resuming
|
||||
if info.pos != 0 {
|
||||
if _, err = f.Seek(info.pos, os.SEEK_SET); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
if ret, err := f.Read(p); err != nil && err != io.EOF {
|
||||
return 0, err
|
||||
} else {
|
||||
return ret, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TarFile) writePad(p []byte, info *tarInfo) (int, error) {
|
||||
buf := bytes.NewBuffer(t.padding[0:info.pad])
|
||||
if ret, err := buf.Read(p); err != nil && err != io.EOF {
|
||||
return 0, err
|
||||
} else {
|
||||
return ret, nil
|
||||
}
|
||||
}
|
||||
|
||||
// write the trailing zeros of a tar file
|
||||
func (t *TarFile) writeClose(p []byte) (n int, err error) {
|
||||
size := t.endPad
|
||||
buf := bytes.NewBuffer(make([]byte, size))
|
||||
if ret, err := buf.Read(p); err != nil && err != io.EOF {
|
||||
return 0, err
|
||||
} else {
|
||||
t.endPad -= ret
|
||||
}
|
||||
if t.endPad <= 0 {
|
||||
if t.progress != nil {
|
||||
t.progress.Finish()
|
||||
}
|
||||
t.closed = true
|
||||
return size, io.EOF
|
||||
}
|
||||
return size - t.endPad, nil
|
||||
}
|
||||
|
||||
func (t *TarFile) AllocBar(pool *pb.Pool) *pb.ProgressBar {
|
||||
if t.progress == nil {
|
||||
t.progress = pb.New(len(t.fileList)).Prefix(fmt.Sprintf("Sending %s", t.source))
|
||||
pool.Add(t.progress)
|
||||
}
|
||||
return t.progress
|
||||
}
|
||||
|
||||
func (t *TarFile) AddFile(info os.FileInfo, relPath, linkName, path string) {
|
||||
t.fileList = append(t.fileList, &tarInfo{
|
||||
info: info,
|
||||
relPath: relPath,
|
||||
linkName: linkName,
|
||||
path: path,
|
||||
pad: (t.blockSize - (int(info.Size()) % t.blockSize)) % t.blockSize,
|
||||
})
|
||||
}
|
||||
|
||||
func (t *TarFile) Close() error {
|
||||
if !t.closed {
|
||||
if t.progress != nil {
|
||||
t.progress.Finish()
|
||||
}
|
||||
}
|
||||
t.closed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TarFile) Read(p []byte) (n int, err error) {
|
||||
var (
|
||||
file *tarInfo
|
||||
idx int
|
||||
length = len(p)
|
||||
)
|
||||
|
||||
if length == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if t.closed {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
for idx, file = range t.fileList {
|
||||
if file.state != TARINFO_FINISHED {
|
||||
break
|
||||
}
|
||||
if idx == len(t.fileList)-1 {
|
||||
file = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil && err != io.EOF {
|
||||
t.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
if file == nil {
|
||||
return t.writeClose(p)
|
||||
}
|
||||
|
||||
for n < length && file.state != TARINFO_FINISHED {
|
||||
switch file.state {
|
||||
case TARINFO_HEADER:
|
||||
if ret, err := t.writeHeader(p, file); err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
n += ret
|
||||
p = p[n:]
|
||||
if file.headerBuf.Len() == 0 {
|
||||
if file.info.Mode().IsRegular() {
|
||||
file.state = TARINFO_FILE
|
||||
} else {
|
||||
file.state = TARINFO_UPLOADED
|
||||
}
|
||||
}
|
||||
}
|
||||
case TARINFO_FILE:
|
||||
if ret, err := t.writeFile(p, file); err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
file.pos += int64(ret)
|
||||
n += ret
|
||||
p = p[ret:]
|
||||
if file.pos >= file.info.Size() {
|
||||
file.pos = 0
|
||||
file.state = TARINFO_PAD
|
||||
}
|
||||
}
|
||||
case TARINFO_PAD:
|
||||
if file.pad == 0 {
|
||||
file.state = TARINFO_UPLOADED
|
||||
} else if ret, err := t.writePad(p, file); err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
file.pos += int64(ret)
|
||||
n += ret
|
||||
p = p[ret:]
|
||||
if file.pos >= int64(file.pad) {
|
||||
file.state = TARINFO_UPLOADED
|
||||
}
|
||||
}
|
||||
case TARINFO_UPLOADED:
|
||||
file.state = TARINFO_FINISHED
|
||||
if t.progress != nil {
|
||||
t.progress.Increment()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func NewTarFile(path string, blockSize int) *TarFile {
|
||||
return &TarFile{
|
||||
blockSize: blockSize,
|
||||
endPad: blockSize * 2,
|
||||
source: filepath.Base(path),
|
||||
padding: make([]byte, blockSize),
|
||||
}
|
||||
}
|
||||
41
vendor/github.com/hyperhq/hypercli/api/client/top.go
generated
vendored
41
vendor/github.com/hyperhq/hypercli/api/client/top.go
generated
vendored
@@ -1,41 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdTop displays the running processes of a container.
|
||||
//
|
||||
// Usage: docker top CONTAINER
|
||||
func (cli *DockerCli) Top(args ...string) error {
|
||||
cmd := Cli.Subcmd("top", []string{"CONTAINER [ps OPTIONS]"}, Cli.DockerCommands["top"].Description, true)
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
var arguments []string
|
||||
if cmd.NArg() > 1 {
|
||||
arguments = cmd.Args()[1:]
|
||||
}
|
||||
|
||||
procList, err := cli.client.ContainerTop(context.Background(), cmd.Arg(0), arguments)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
||||
fmt.Fprintln(w, strings.Join(procList.Titles, "\t"))
|
||||
|
||||
for _, proc := range procList.Processes {
|
||||
fmt.Fprintln(w, strings.Join(proc, "\t"))
|
||||
}
|
||||
w.Flush()
|
||||
return nil
|
||||
}
|
||||
467
vendor/github.com/hyperhq/hypercli/api/client/trust.go
generated
vendored
467
vendor/github.com/hyperhq/hypercli/api/client/trust.go
generated
vendored
@@ -1,467 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/registry/client/auth"
|
||||
"github.com/docker/distribution/registry/client/transport"
|
||||
"github.com/docker/go-connections/tlsconfig"
|
||||
"github.com/docker/notary/client"
|
||||
"github.com/docker/notary/passphrase"
|
||||
"github.com/docker/notary/trustmanager"
|
||||
"github.com/docker/notary/tuf/data"
|
||||
"github.com/docker/notary/tuf/signed"
|
||||
"github.com/docker/notary/tuf/store"
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
registrytypes "github.com/hyperhq/hyper-api/types/registry"
|
||||
"github.com/hyperhq/hypercli/cliconfig"
|
||||
"github.com/hyperhq/hypercli/distribution"
|
||||
"github.com/hyperhq/hypercli/dockerversion"
|
||||
"github.com/hyperhq/hypercli/pkg/jsonmessage"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/reference"
|
||||
"github.com/hyperhq/hypercli/registry"
|
||||
)
|
||||
|
||||
var (
|
||||
releasesRole = path.Join(data.CanonicalTargetsRole, "releases")
|
||||
untrusted bool
|
||||
)
|
||||
|
||||
func addTrustedFlags(fs *flag.FlagSet, verify bool) {
|
||||
var trusted bool
|
||||
if e := os.Getenv("HYPER_CONTENT_TRUST"); e != "" {
|
||||
if t, err := strconv.ParseBool(e); t || err != nil {
|
||||
// treat any other value as true
|
||||
trusted = true
|
||||
}
|
||||
}
|
||||
message := "Skip image signing"
|
||||
if verify {
|
||||
message = "Skip image verification"
|
||||
}
|
||||
fs.BoolVar(&untrusted, []string{"-disable-content-trust"}, !trusted, message)
|
||||
}
|
||||
|
||||
func isTrusted() bool {
|
||||
return !untrusted
|
||||
}
|
||||
|
||||
type target struct {
|
||||
reference registry.Reference
|
||||
digest digest.Digest
|
||||
size int64
|
||||
}
|
||||
|
||||
func (cli *DockerCli) trustDirectory() string {
|
||||
return filepath.Join(cliconfig.ConfigDir(), "trust")
|
||||
}
|
||||
|
||||
// certificateDirectory returns the directory containing
|
||||
// TLS certificates for the given server. An error is
|
||||
// returned if there was an error parsing the server string.
|
||||
func (cli *DockerCli) certificateDirectory(server string) (string, error) {
|
||||
u, err := url.Parse(server)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return filepath.Join(cliconfig.ConfigDir(), "tls", u.Host), nil
|
||||
}
|
||||
|
||||
func trustServer(index *registrytypes.IndexInfo) (string, error) {
|
||||
if s := os.Getenv("HYPER_CONTENT_TRUST_SERVER"); s != "" {
|
||||
urlObj, err := url.Parse(s)
|
||||
if err != nil || urlObj.Scheme != "https" {
|
||||
return "", fmt.Errorf("valid https URL required for trust server, got %s", s)
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
if index.Official {
|
||||
return registry.NotaryServer, nil
|
||||
}
|
||||
return "https://" + index.Name, nil
|
||||
}
|
||||
|
||||
type simpleCredentialStore struct {
|
||||
auth types.AuthConfig
|
||||
}
|
||||
|
||||
func (scs simpleCredentialStore) Basic(u *url.URL) (string, string) {
|
||||
return scs.auth.Username, scs.auth.Password
|
||||
}
|
||||
|
||||
func (cli *DockerCli) getNotaryRepository(repoInfo *registry.RepositoryInfo, authConfig types.AuthConfig) (*client.NotaryRepository, error) {
|
||||
server, err := trustServer(repoInfo.Index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var cfg = tlsconfig.ClientDefault()
|
||||
cfg.InsecureSkipVerify = !repoInfo.Index.Secure
|
||||
|
||||
// Get certificate base directory
|
||||
certDir, err := cli.certificateDirectory(server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
logrus.Debugf("reading certificate directory: %s", certDir)
|
||||
|
||||
if err := registry.ReadCertsDirectory(cfg, certDir); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
base := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
DualStack: true,
|
||||
}).Dial,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
TLSClientConfig: cfg,
|
||||
DisableKeepAlives: true,
|
||||
}
|
||||
|
||||
// Skip configuration headers since request is not going to Docker daemon
|
||||
modifiers := registry.DockerHeaders(dockerversion.DockerUserAgent(), http.Header{})
|
||||
authTransport := transport.NewTransport(base, modifiers...)
|
||||
pingClient := &http.Client{
|
||||
Transport: authTransport,
|
||||
Timeout: 5 * time.Second,
|
||||
}
|
||||
endpointStr := server + "/v2/"
|
||||
req, err := http.NewRequest("GET", endpointStr, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
challengeManager := auth.NewSimpleChallengeManager()
|
||||
|
||||
resp, err := pingClient.Do(req)
|
||||
if err != nil {
|
||||
// Ignore error on ping to operate in offline mode
|
||||
logrus.Debugf("Error pinging notary server %q: %s", endpointStr, err)
|
||||
} else {
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Add response to the challenge manager to parse out
|
||||
// authentication header and register authentication method
|
||||
if err := challengeManager.AddResponse(resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
creds := simpleCredentialStore{auth: authConfig}
|
||||
tokenHandler := auth.NewTokenHandler(authTransport, creds, repoInfo.FullName(), "push", "pull")
|
||||
basicHandler := auth.NewBasicHandler(creds)
|
||||
modifiers = append(modifiers, transport.RequestModifier(auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler)))
|
||||
tr := transport.NewTransport(base, modifiers...)
|
||||
|
||||
return client.NewNotaryRepository(cli.trustDirectory(), repoInfo.FullName(), server, tr, cli.getPassphraseRetriever())
|
||||
}
|
||||
|
||||
func convertTarget(t client.Target) (target, error) {
|
||||
h, ok := t.Hashes["sha256"]
|
||||
if !ok {
|
||||
return target{}, errors.New("no valid hash, expecting sha256")
|
||||
}
|
||||
return target{
|
||||
reference: registry.ParseReference(t.Name),
|
||||
digest: digest.NewDigestFromHex("sha256", hex.EncodeToString(h)),
|
||||
size: t.Length,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) getPassphraseRetriever() passphrase.Retriever {
|
||||
aliasMap := map[string]string{
|
||||
"root": "root",
|
||||
"snapshot": "repository",
|
||||
"targets": "repository",
|
||||
"targets/releases": "repository",
|
||||
}
|
||||
baseRetriever := passphrase.PromptRetrieverWithInOut(cli.in, cli.out, aliasMap)
|
||||
env := map[string]string{
|
||||
"root": os.Getenv("HYPER_CONTENT_TRUST_ROOT_PASSPHRASE"),
|
||||
"snapshot": os.Getenv("HYPER_CONTENT_TRUST_REPOSITORY_PASSPHRASE"),
|
||||
"targets": os.Getenv("HYPER_CONTENT_TRUST_REPOSITORY_PASSPHRASE"),
|
||||
"targets/releases": os.Getenv("HYPER_CONTENT_TRUST_REPOSITORY_PASSPHRASE"),
|
||||
}
|
||||
|
||||
// Backwards compatibility with old env names. We should remove this in 1.10
|
||||
if env["root"] == "" {
|
||||
if passphrase := os.Getenv("HYPER_CONTENT_TRUST_OFFLINE_PASSPHRASE"); passphrase != "" {
|
||||
env["root"] = passphrase
|
||||
fmt.Fprintf(cli.err, "[DEPRECATED] The environment variable HYPER_CONTENT_TRUST_OFFLINE_PASSPHRASE has been deprecated and will be removed in v1.10. Please use HYPER_CONTENT_TRUST_ROOT_PASSPHRASE\n")
|
||||
}
|
||||
}
|
||||
if env["snapshot"] == "" || env["targets"] == "" || env["targets/releases"] == "" {
|
||||
if passphrase := os.Getenv("HYPER_CONTENT_TRUST_TAGGING_PASSPHRASE"); passphrase != "" {
|
||||
env["snapshot"] = passphrase
|
||||
env["targets"] = passphrase
|
||||
env["targets/releases"] = passphrase
|
||||
fmt.Fprintf(cli.err, "[DEPRECATED] The environment variable HYPER_CONTENT_TRUST_TAGGING_PASSPHRASE has been deprecated and will be removed in v1.10. Please use HYPER_CONTENT_TRUST_REPOSITORY_PASSPHRASE\n")
|
||||
}
|
||||
}
|
||||
|
||||
return func(keyName string, alias string, createNew bool, numAttempts int) (string, bool, error) {
|
||||
if v := env[alias]; v != "" {
|
||||
return v, numAttempts > 1, nil
|
||||
}
|
||||
return baseRetriever(keyName, alias, createNew, numAttempts)
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *DockerCli) trustedReference(ctx context.Context, ref reference.NamedTagged) (reference.Canonical, error) {
|
||||
repoInfo, err := registry.ParseRepositoryInfo(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Resolve the Auth config relevant for this server
|
||||
authConfig := cli.resolveAuthConfig(ctx, cli.configFile.AuthConfigs, repoInfo.Index)
|
||||
|
||||
notaryRepo, err := cli.getNotaryRepository(repoInfo, authConfig)
|
||||
if err != nil {
|
||||
fmt.Fprintf(cli.out, "Error establishing connection to trust repository: %s\n", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t, err := notaryRepo.GetTargetByName(ref.Tag(), releasesRole, data.CanonicalTargetsRole)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, err := convertTarget(t.Target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
}
|
||||
|
||||
return reference.WithDigest(ref, r.digest)
|
||||
}
|
||||
|
||||
func (cli *DockerCli) tagTrusted(ctx context.Context, trustedRef reference.Canonical, ref reference.NamedTagged) error {
|
||||
fmt.Fprintf(cli.out, "Tagging %s as %s\n", trustedRef.String(), ref.String())
|
||||
|
||||
options := types.ImageTagOptions{
|
||||
Force: true,
|
||||
}
|
||||
|
||||
return cli.client.ImageTag(ctx, trustedRef.String(), ref.String(), options)
|
||||
}
|
||||
|
||||
func notaryError(repoName string, err error) error {
|
||||
switch err.(type) {
|
||||
case *json.SyntaxError:
|
||||
logrus.Debugf("Notary syntax error: %s", err)
|
||||
return fmt.Errorf("Error: no trust data available for remote repository %s. Try running notary server and setting HYPER_CONTENT_TRUST_SERVER to its HTTPS address?", repoName)
|
||||
case signed.ErrExpired:
|
||||
return fmt.Errorf("Error: remote repository %s out-of-date: %v", repoName, err)
|
||||
case trustmanager.ErrKeyNotFound:
|
||||
return fmt.Errorf("Error: signing keys for remote repository %s not found: %v", repoName, err)
|
||||
case *net.OpError:
|
||||
return fmt.Errorf("Error: error contacting notary server: %v", err)
|
||||
case store.ErrMetaNotFound:
|
||||
return fmt.Errorf("Error: trust data missing for remote repository %s or remote repository not found: %v", repoName, err)
|
||||
case signed.ErrInvalidKeyType:
|
||||
return fmt.Errorf("Warning: potential malicious behavior - trust data mismatch for remote repository %s: %v", repoName, err)
|
||||
case signed.ErrNoKeys:
|
||||
return fmt.Errorf("Error: could not find signing keys for remote repository %s, or could not decrypt signing key: %v", repoName, err)
|
||||
case signed.ErrLowVersion:
|
||||
return fmt.Errorf("Warning: potential malicious behavior - trust data version is lower than expected for remote repository %s: %v", repoName, err)
|
||||
case signed.ErrRoleThreshold:
|
||||
return fmt.Errorf("Warning: potential malicious behavior - trust data has insufficient signatures for remote repository %s: %v", repoName, err)
|
||||
case client.ErrRepositoryNotExist:
|
||||
return fmt.Errorf("Error: remote trust data does not exist for %s: %v", repoName, err)
|
||||
case signed.ErrInsufficientSignatures:
|
||||
return fmt.Errorf("Error: could not produce valid signature for %s. If Yubikey was used, was touch input provided?: %v", repoName, err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (cli *DockerCli) trustedPull(ctx context.Context, repoInfo *registry.RepositoryInfo, ref registry.Reference, authConfig types.AuthConfig, requestPrivilege types.RequestPrivilegeFunc) error {
|
||||
var refs []target
|
||||
|
||||
notaryRepo, err := cli.getNotaryRepository(repoInfo, authConfig)
|
||||
if err != nil {
|
||||
fmt.Fprintf(cli.out, "Error establishing connection to trust repository: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if ref.String() == "" {
|
||||
// List all targets
|
||||
targets, err := notaryRepo.ListTargets(releasesRole, data.CanonicalTargetsRole)
|
||||
if err != nil {
|
||||
return notaryError(repoInfo.FullName(), err)
|
||||
}
|
||||
for _, tgt := range targets {
|
||||
t, err := convertTarget(tgt.Target)
|
||||
if err != nil {
|
||||
fmt.Fprintf(cli.out, "Skipping target for %q\n", repoInfo.Name())
|
||||
continue
|
||||
}
|
||||
refs = append(refs, t)
|
||||
}
|
||||
} else {
|
||||
t, err := notaryRepo.GetTargetByName(ref.String(), releasesRole, data.CanonicalTargetsRole)
|
||||
if err != nil {
|
||||
return notaryError(repoInfo.FullName(), err)
|
||||
}
|
||||
r, err := convertTarget(t.Target)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
}
|
||||
refs = append(refs, r)
|
||||
}
|
||||
|
||||
for i, r := range refs {
|
||||
displayTag := r.reference.String()
|
||||
if displayTag != "" {
|
||||
displayTag = ":" + displayTag
|
||||
}
|
||||
fmt.Fprintf(cli.out, "Pull (%d of %d): %s%s@%s\n", i+1, len(refs), repoInfo.Name(), displayTag, r.digest)
|
||||
ref, err := reference.WithDigest(repoInfo, r.digest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cli.imagePullPrivileged(ctx, authConfig, ref.String(), requestPrivilege, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If reference is not trusted, tag by trusted reference
|
||||
if !r.reference.HasDigest() {
|
||||
tagged, err := reference.WithTag(repoInfo, r.reference.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
trustedRef, err := reference.WithDigest(repoInfo, r.digest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cli.tagTrusted(ctx, trustedRef, tagged); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) trustedPush(ctx context.Context, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig types.AuthConfig, requestPrivilege types.RequestPrivilegeFunc) error {
|
||||
responseBody, err := cli.imagePushPrivileged(ctx, authConfig, ref.String(), requestPrivilege)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer responseBody.Close()
|
||||
|
||||
targets := []target{}
|
||||
handleTarget := func(aux *json.RawMessage) {
|
||||
var pushResult distribution.PushResult
|
||||
err := json.Unmarshal(*aux, &pushResult)
|
||||
if err == nil && pushResult.Tag != "" && pushResult.Digest.Validate() == nil {
|
||||
targets = append(targets, target{
|
||||
reference: registry.ParseReference(pushResult.Tag),
|
||||
digest: pushResult.Digest,
|
||||
size: int64(pushResult.Size),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var tag string
|
||||
switch x := ref.(type) {
|
||||
case reference.Canonical:
|
||||
return errors.New("cannot push a digest reference")
|
||||
case reference.NamedTagged:
|
||||
tag = x.Tag()
|
||||
}
|
||||
|
||||
if tag == "" {
|
||||
err = jsonmessage.DisplayJSONMessagesStream(responseBody, cli.out, cli.outFd, cli.isTerminalOut, handleTarget)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(cli.out, "No tag specified, skipping trust metadata push\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
err = jsonmessage.DisplayJSONMessagesStream(responseBody, cli.out, cli.outFd, cli.isTerminalOut, handleTarget)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(targets) == 0 {
|
||||
fmt.Fprintf(cli.out, "No targets found, skipping trust metadata push\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Fprintf(cli.out, "Signing and pushing trust metadata\n")
|
||||
|
||||
repo, err := cli.getNotaryRepository(repoInfo, authConfig)
|
||||
if err != nil {
|
||||
fmt.Fprintf(cli.out, "Error establishing connection to notary repository: %s\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, target := range targets {
|
||||
h, err := hex.DecodeString(target.digest.Hex())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t := &client.Target{
|
||||
Name: target.reference.String(),
|
||||
Hashes: data.Hashes{
|
||||
string(target.digest.Algorithm()): h,
|
||||
},
|
||||
Length: int64(target.size),
|
||||
}
|
||||
if err := repo.AddTarget(t, releasesRole); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = repo.Publish()
|
||||
if _, ok := err.(client.ErrRepoNotInitialized); !ok {
|
||||
return notaryError(repoInfo.FullName(), err)
|
||||
}
|
||||
|
||||
keys := repo.CryptoService.ListKeys(data.CanonicalRootRole)
|
||||
|
||||
var rootKeyID string
|
||||
// always select the first root key
|
||||
if len(keys) > 0 {
|
||||
sort.Strings(keys)
|
||||
rootKeyID = keys[0]
|
||||
} else {
|
||||
rootPublicKey, err := repo.CryptoService.Create(data.CanonicalRootRole, data.ECDSAKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rootKeyID = rootPublicKey.ID()
|
||||
}
|
||||
|
||||
if err := repo.Initialize(rootKeyID); err != nil {
|
||||
return notaryError(repoInfo.FullName(), err)
|
||||
}
|
||||
fmt.Fprintf(cli.out, "Finished initializing %q\n", repoInfo.FullName())
|
||||
|
||||
return notaryError(repoInfo.FullName(), repo.Publish())
|
||||
}
|
||||
56
vendor/github.com/hyperhq/hypercli/api/client/trust_test.go
generated
vendored
56
vendor/github.com/hyperhq/hypercli/api/client/trust_test.go
generated
vendored
@@ -1,56 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
registrytypes "github.com/hyperhq/hyper-api/types/registry"
|
||||
"github.com/hyperhq/hypercli/registry"
|
||||
)
|
||||
|
||||
func unsetENV() {
|
||||
os.Unsetenv("DOCKER_CONTENT_TRUST")
|
||||
os.Unsetenv("DOCKER_CONTENT_TRUST_SERVER")
|
||||
}
|
||||
|
||||
func TestENVTrustServer(t *testing.T) {
|
||||
defer unsetENV()
|
||||
indexInfo := ®istrytypes.IndexInfo{Name: "testserver"}
|
||||
if err := os.Setenv("DOCKER_CONTENT_TRUST_SERVER", "https://notary-test.com:5000"); err != nil {
|
||||
t.Fatal("Failed to set ENV variable")
|
||||
}
|
||||
output, err := trustServer(indexInfo)
|
||||
expectedStr := "https://notary-test.com:5000"
|
||||
if err != nil || output != expectedStr {
|
||||
t.Fatalf("Expected server to be %s, got %s", expectedStr, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPENVTrustServer(t *testing.T) {
|
||||
defer unsetENV()
|
||||
indexInfo := ®istrytypes.IndexInfo{Name: "testserver"}
|
||||
if err := os.Setenv("DOCKER_CONTENT_TRUST_SERVER", "http://notary-test.com:5000"); err != nil {
|
||||
t.Fatal("Failed to set ENV variable")
|
||||
}
|
||||
_, err := trustServer(indexInfo)
|
||||
if err == nil {
|
||||
t.Fatal("Expected error with invalid scheme")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOfficialTrustServer(t *testing.T) {
|
||||
indexInfo := ®istrytypes.IndexInfo{Name: "testserver", Official: true}
|
||||
output, err := trustServer(indexInfo)
|
||||
if err != nil || output != registry.NotaryServer {
|
||||
t.Fatalf("Expected server to be %s, got %s", registry.NotaryServer, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonOfficialTrustServer(t *testing.T) {
|
||||
indexInfo := ®istrytypes.IndexInfo{Name: "testserver", Official: false}
|
||||
output, err := trustServer(indexInfo)
|
||||
expectedStr := "https://" + indexInfo.Name
|
||||
if err != nil || output != expectedStr {
|
||||
t.Fatalf("Expected server to be %s, got %s", expectedStr, output)
|
||||
}
|
||||
}
|
||||
36
vendor/github.com/hyperhq/hypercli/api/client/unpause.go
generated
vendored
36
vendor/github.com/hyperhq/hypercli/api/client/unpause.go
generated
vendored
@@ -1,36 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdUnpause unpauses all processes within a container, for one or more containers.
|
||||
//
|
||||
// Usage: docker unpause CONTAINER [CONTAINER...]
|
||||
func (cli *DockerCli) Unpause(args ...string) error {
|
||||
cmd := Cli.Subcmd("unpause", []string{"CONTAINER [CONTAINER...]"}, Cli.DockerCommands["unpause"].Description, true)
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
var errs []string
|
||||
for _, name := range cmd.Args() {
|
||||
if err := cli.client.ContainerUnpause(ctx, name); err != nil {
|
||||
errs = append(errs, err.Error())
|
||||
} else {
|
||||
fmt.Fprintf(cli.out, "%s\n", name)
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("%s", strings.Join(errs, "\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
78
vendor/github.com/hyperhq/hypercli/api/client/update.go
generated
vendored
78
vendor/github.com/hyperhq/hypercli/api/client/update.go
generated
vendored
@@ -1,78 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/opts"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdUpdate updates resources of one or more containers.
|
||||
//
|
||||
// Usage: hyper update [OPTIONS] CONTAINER [CONTAINER...]
|
||||
func (cli *DockerCli) CmdUpdate(args ...string) error {
|
||||
cmd := Cli.Subcmd("update", []string{"CONTAINER [CONTAINER...]"}, Cli.DockerCommands["update"].Description, true)
|
||||
flAddSecurityGroups := opts.NewListOpts(nil)
|
||||
flRmSecurityGroups := opts.NewListOpts(nil)
|
||||
cmd.Var(&flAddSecurityGroups, []string{"-sg-add"}, "Add a new security group for each container")
|
||||
cmd.Var(&flRmSecurityGroups, []string{"-sg-rm"}, "Remove a new security group for each container")
|
||||
// make this flag string type to distinguish between 'not set', 'set to false' and 'set to true'
|
||||
flContainerProtection := cmd.String([]string{"-protection"}, "", "Termination protection for container (true|false)")
|
||||
|
||||
cmd.Require(flag.Min, 1)
|
||||
cmd.ParseFlags(args, true)
|
||||
if cmd.NFlag() == 0 {
|
||||
return fmt.Errorf("You must provide one or more flags when using this command.")
|
||||
}
|
||||
if *flContainerProtection != "" {
|
||||
value, err := strconv.ParseBool(*flContainerProtection)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Parse protection false failed: %v", err)
|
||||
}
|
||||
*flContainerProtection = strconv.FormatBool(value)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
names := cmd.Args()
|
||||
var errs []string
|
||||
for _, name := range names {
|
||||
var updateConfig struct {
|
||||
AddSecurityGroups map[string]string
|
||||
RemoveSecurityGroups map[string]string
|
||||
SetContainerProtection string
|
||||
}
|
||||
sgs := map[string]string{}
|
||||
for _, label := range flAddSecurityGroups.GetAll() {
|
||||
if label == "" {
|
||||
continue
|
||||
}
|
||||
sgs[label] = "yes"
|
||||
}
|
||||
updateConfig.AddSecurityGroups = sgs
|
||||
sgs = map[string]string{}
|
||||
for _, label := range flRmSecurityGroups.GetAll() {
|
||||
if label == "" {
|
||||
continue
|
||||
}
|
||||
sgs[label] = "yes"
|
||||
}
|
||||
updateConfig.RemoveSecurityGroups = sgs
|
||||
updateConfig.SetContainerProtection = *flContainerProtection
|
||||
if err := cli.client.ContainerUpdate(ctx, name, updateConfig); err != nil {
|
||||
errs = append(errs, err.Error())
|
||||
} else {
|
||||
fmt.Fprintf(cli.out, "%s\n", name)
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("%s", strings.Join(errs, "\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
261
vendor/github.com/hyperhq/hypercli/api/client/utils.go
generated
vendored
261
vendor/github.com/hyperhq/hypercli/api/client/utils.go
generated
vendored
@@ -1,261 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
gosignal "os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/dutchcoders/goftp"
|
||||
"github.com/hyperhq/hyper-api/client"
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
registrytypes "github.com/hyperhq/hyper-api/types/registry"
|
||||
"github.com/hyperhq/hypercli/pkg/signal"
|
||||
"github.com/hyperhq/hypercli/pkg/term"
|
||||
"github.com/hyperhq/hypercli/registry"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (cli *DockerCli) electAuthServer(ctx context.Context) string {
|
||||
// The daemon `/info` endpoint informs us of the default registry being
|
||||
// used. This is essential in cross-platforms environment, where for
|
||||
// example a Linux client might be interacting with a Windows daemon, hence
|
||||
// the default registry URL might be Windows specific.
|
||||
serverAddress := registry.IndexServer
|
||||
if info, err := cli.client.Info(ctx); err != nil {
|
||||
fmt.Fprintf(cli.out, "Warning: failed to get default registry endpoint from daemon (%v). Using system default: %s\n", err, serverAddress)
|
||||
} else {
|
||||
serverAddress = info.IndexServerAddress
|
||||
}
|
||||
return serverAddress
|
||||
}
|
||||
|
||||
// encodeAuthToBase64 serializes the auth configuration as JSON base64 payload
|
||||
func encodeAuthToBase64(authConfig types.AuthConfig) (string, error) {
|
||||
buf, err := json.Marshal(authConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.URLEncoding.EncodeToString(buf), nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) registryAuthenticationPrivilegedFunc(index *registrytypes.IndexInfo, cmdName string) types.RequestPrivilegeFunc {
|
||||
return func() (string, error) {
|
||||
fmt.Fprintf(cli.out, "\nPlease login prior to %s:\n", cmdName)
|
||||
indexServer := registry.GetAuthConfigKey(index)
|
||||
authConfig, err := cli.configureAuth("", "", "", indexServer)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return encodeAuthToBase64(authConfig)
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *DockerCli) resizeTty(ctx context.Context, id string, isExec bool) {
|
||||
height, width := cli.getTtySize()
|
||||
if height == 0 && width == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
options := types.ResizeOptions{
|
||||
Height: height,
|
||||
Width: width,
|
||||
}
|
||||
|
||||
var err error
|
||||
if isExec {
|
||||
err = cli.client.ContainerExecResize(ctx, id, options)
|
||||
} else {
|
||||
err = cli.client.ContainerResize(ctx, id, options)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logrus.Debugf("Error resize: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// getExitCode perform an inspect on the container. It returns
|
||||
// the running state and the exit code.
|
||||
func getExitCode(ctx context.Context, cli *DockerCli, containerID string) (bool, int, error) {
|
||||
c, err := cli.client.ContainerInspect(ctx, containerID)
|
||||
if err != nil {
|
||||
// If we can't connect, then the daemon probably died.
|
||||
if err != client.ErrConnectionFailed {
|
||||
return false, -1, err
|
||||
}
|
||||
return false, -1, nil
|
||||
}
|
||||
|
||||
return c.State.Running, c.State.ExitCode, nil
|
||||
}
|
||||
|
||||
// getExecExitCode perform an inspect on the exec command. It returns
|
||||
// the running state and the exit code.
|
||||
func getExecExitCode(ctx context.Context, cli *DockerCli, execID string) (bool, int, error) {
|
||||
resp, err := cli.client.ContainerExecInspect(ctx, execID)
|
||||
if err != nil {
|
||||
// If we can't connect, then the daemon probably died.
|
||||
if err != client.ErrConnectionFailed {
|
||||
return false, -1, err
|
||||
}
|
||||
return false, -1, nil
|
||||
}
|
||||
|
||||
return resp.Running, resp.ExitCode, nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) monitorTtySize(ctx context.Context, id string, isExec bool) error {
|
||||
cli.resizeTty(ctx, id, isExec)
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
go func() {
|
||||
prevH, prevW := cli.getTtySize()
|
||||
for {
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
h, w := cli.getTtySize()
|
||||
|
||||
if prevW != w || prevH != h {
|
||||
cli.resizeTty(ctx, id, isExec)
|
||||
}
|
||||
prevH = h
|
||||
prevW = w
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
sigchan := make(chan os.Signal, 1)
|
||||
gosignal.Notify(sigchan, signal.SIGWINCH)
|
||||
go func() {
|
||||
for range sigchan {
|
||||
cli.resizeTty(ctx, id, isExec)
|
||||
}
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cli *DockerCli) getTtySize() (int, int) {
|
||||
if !cli.isTerminalOut {
|
||||
return 0, 0
|
||||
}
|
||||
ws, err := term.GetWinsize(cli.outFd)
|
||||
if err != nil {
|
||||
logrus.Debugf("Error getting size: %s", err)
|
||||
if ws == nil {
|
||||
return 0, 0
|
||||
}
|
||||
}
|
||||
return int(ws.Height), int(ws.Width)
|
||||
}
|
||||
|
||||
func copyToFile(outfile string, r io.Reader) error {
|
||||
tmpFile, err := ioutil.TempFile(filepath.Dir(outfile), ".docker_temp_")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpPath := tmpFile.Name()
|
||||
|
||||
_, err = io.Copy(tmpFile, r)
|
||||
tmpFile.Close()
|
||||
|
||||
if err != nil {
|
||||
os.Remove(tmpPath)
|
||||
return err
|
||||
}
|
||||
|
||||
if err = os.Rename(tmpPath, outfile); err != nil {
|
||||
os.Remove(tmpPath)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// resolveAuthConfig is like registry.ResolveAuthConfig, but if using the
|
||||
// default index, it uses the default index name for the daemon's platform,
|
||||
// not the client's platform.
|
||||
func (cli *DockerCli) resolveAuthConfig(ctx context.Context, authConfigs map[string]types.AuthConfig, index *registrytypes.IndexInfo) types.AuthConfig {
|
||||
configKey := index.Name
|
||||
if index.Official {
|
||||
configKey = cli.electAuthServer(ctx)
|
||||
}
|
||||
|
||||
// First try the happy case
|
||||
if c, found := authConfigs[configKey]; found || index.Official {
|
||||
return c
|
||||
}
|
||||
|
||||
convertToHostname := func(url string) string {
|
||||
stripped := url
|
||||
if strings.HasPrefix(url, "http://") {
|
||||
stripped = strings.Replace(url, "http://", "", 1)
|
||||
} else if strings.HasPrefix(url, "https://") {
|
||||
stripped = strings.Replace(url, "https://", "", 1)
|
||||
}
|
||||
|
||||
nameParts := strings.SplitN(stripped, "/", 2)
|
||||
|
||||
return nameParts[0]
|
||||
}
|
||||
|
||||
// Maybe they have a legacy config file, we will iterate the keys converting
|
||||
// them to the new format and testing
|
||||
for registry, ac := range authConfigs {
|
||||
if configKey == convertToHostname(registry) {
|
||||
return ac
|
||||
}
|
||||
}
|
||||
|
||||
// When all else fails, return an empty auth config
|
||||
return types.AuthConfig{}
|
||||
}
|
||||
|
||||
// uploadLocalResource upload a local file/directory to a container
|
||||
func (cli *DockerCli) uploadLocalResource(source, dest, serverIP, user, passwd string, isFile bool) error {
|
||||
if !strings.Contains(serverIP, ":") {
|
||||
serverIP += ":21"
|
||||
}
|
||||
ftp, err := goftp.Connect(serverIP)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
ftp.Close()
|
||||
}()
|
||||
|
||||
if err = ftp.Login(user, passwd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if isFile {
|
||||
file, err := os.Open(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
file.Close()
|
||||
}()
|
||||
if err = ftp.Stor(dest, file); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err = ftp.Cwd(dest); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = ftp.Upload(source); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
19
vendor/github.com/hyperhq/hypercli/api/client/utils_unix.go
generated
vendored
19
vendor/github.com/hyperhq/hypercli/api/client/utils_unix.go
generated
vendored
@@ -1,19 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func getContextRoot(srcPath string) (string, error) {
|
||||
return filepath.Join(srcPath, "."), nil
|
||||
}
|
||||
|
||||
func convertToUnixPath(path string) (int, string) {
|
||||
return 0, path
|
||||
}
|
||||
|
||||
func recoverPath(pathType int, path string) string {
|
||||
return path
|
||||
}
|
||||
60
vendor/github.com/hyperhq/hypercli/api/client/utils_windows.go
generated
vendored
60
vendor/github.com/hyperhq/hypercli/api/client/utils_windows.go
generated
vendored
@@ -1,60 +0,0 @@
|
||||
// +build windows
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/hyperhq/hypercli/pkg/longpath"
|
||||
)
|
||||
|
||||
const (
|
||||
LOCAL_PATH_UNIX = iota
|
||||
LOCAL_PATH_WIN_VOLUME
|
||||
LOCAL_PATH_WIN_SHARE
|
||||
)
|
||||
|
||||
func getContextRoot(srcPath string) (string, error) {
|
||||
cr, err := filepath.Abs(srcPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return longpath.AddPrefix(cr), nil
|
||||
}
|
||||
|
||||
// convertToUnixPath converts whatever valid path to unix format
|
||||
// network path is treated as unix path unchanged
|
||||
// /foo/bar -> /foo/bar
|
||||
// C:\foo\bar -> /C/foo/bar
|
||||
// \\host\share\foo\bar -> //host/share/foo/bar
|
||||
func convertToUnixPath(path string) (int, string) {
|
||||
if strings.HasPrefix(path, "git://") || strings.HasPrefix(path, "http://") || strings.HasPrefix(path, "https://") {
|
||||
return LOCAL_PATH_UNIX, path
|
||||
}
|
||||
switch len(filepath.VolumeName(path)) {
|
||||
case 0:
|
||||
return LOCAL_PATH_UNIX, path
|
||||
case 2:
|
||||
// C:
|
||||
return LOCAL_PATH_WIN_VOLUME, "/" + strings.Replace(filepath.ToSlash(path), ":", "", 1)
|
||||
default:
|
||||
// \\host\share
|
||||
return LOCAL_PATH_WIN_SHARE, filepath.ToSlash(path)
|
||||
}
|
||||
}
|
||||
|
||||
// recoverPath recovers a file path according to path type
|
||||
func recoverPath(pathType int, path string) string {
|
||||
switch pathType {
|
||||
case LOCAL_PATH_WIN_VOLUME:
|
||||
path = filepath.FromSlash(path)
|
||||
return strings.Replace(path[1:], "\\", ":\\", 1)
|
||||
case LOCAL_PATH_WIN_SHARE:
|
||||
return filepath.FromSlash(path)
|
||||
default:
|
||||
// LOCAL_PATH_UNIX
|
||||
return path
|
||||
}
|
||||
|
||||
}
|
||||
96
vendor/github.com/hyperhq/hypercli/api/client/version.go
generated
vendored
96
vendor/github.com/hyperhq/hypercli/api/client/version.go
generated
vendored
@@ -1,96 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/dockerversion"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
"github.com/hyperhq/hypercli/utils"
|
||||
)
|
||||
|
||||
var versionTemplate = `Client:
|
||||
Version: {{.Client.Version}}
|
||||
API version: {{.Client.APIVersion}}
|
||||
Go version: {{.Client.GoVersion}}
|
||||
Git commit: {{.Client.GitCommit}}
|
||||
Built: {{.Client.BuildTime}}
|
||||
OS/Arch: {{.Client.Os}}/{{.Client.Arch}}{{if .Client.Experimental}}
|
||||
Experimental: {{.Client.Experimental}}{{end}}{{if .ServerOK}}
|
||||
|
||||
Server:
|
||||
Version: {{.Server.Version}}
|
||||
API version: {{.Server.APIVersion}}
|
||||
Go version: {{.Server.GoVersion}}
|
||||
Git commit: {{.Server.GitCommit}}
|
||||
Built: {{.Server.BuildTime}}
|
||||
OS/Arch: {{.Server.Os}}/{{.Server.Arch}}{{if .Server.Experimental}}
|
||||
Experimental: {{.Server.Experimental}}{{end}}{{end}}`
|
||||
|
||||
// CmdVersion shows Docker version information.
|
||||
//
|
||||
// Available version information is shown for: client Docker version, client API version, client Go version, client Git commit, client OS/Arch, server Docker version, server API version, server Go version, server Git commit, and server OS/Arch.
|
||||
//
|
||||
// Usage: docker version
|
||||
func (cli *DockerCli) CmdVersion(args ...string) (err error) {
|
||||
cmd := Cli.Subcmd("version", nil, Cli.DockerCommands["version"].Description, true)
|
||||
tmplStr := cmd.String([]string{"f", "#format", "-format"}, "", "Format the output using the given go template")
|
||||
cmd.Require(flag.Exact, 0)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
templateFormat := versionTemplate
|
||||
if *tmplStr != "" {
|
||||
templateFormat = *tmplStr
|
||||
}
|
||||
|
||||
var tmpl *template.Template
|
||||
if tmpl, err = template.New("").Funcs(funcMap).Parse(templateFormat); err != nil {
|
||||
return Cli.StatusError{StatusCode: 64,
|
||||
Status: "Template parsing error: " + err.Error()}
|
||||
}
|
||||
|
||||
vd := types.VersionResponse{
|
||||
Client: &types.Version{
|
||||
Version: dockerversion.Version,
|
||||
APIVersion: cli.client.ClientVersion(),
|
||||
GoVersion: runtime.Version(),
|
||||
GitCommit: dockerversion.GitCommit,
|
||||
BuildTime: dockerversion.BuildTime,
|
||||
Os: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
Experimental: utils.ExperimentalBuild(),
|
||||
},
|
||||
}
|
||||
|
||||
serverVersion, err := cli.client.ServerVersion(ctx)
|
||||
if err == nil {
|
||||
vd.Server = &serverVersion
|
||||
}
|
||||
|
||||
// first we need to make BuildTime more human friendly
|
||||
t, errTime := time.Parse(time.RFC3339Nano, vd.Client.BuildTime)
|
||||
if errTime == nil {
|
||||
vd.Client.BuildTime = t.Format(time.ANSIC)
|
||||
}
|
||||
|
||||
if vd.ServerOK() {
|
||||
t, errTime = time.Parse(time.RFC3339Nano, vd.Server.BuildTime)
|
||||
if errTime == nil {
|
||||
vd.Server.BuildTime = t.Format(time.ANSIC)
|
||||
}
|
||||
}
|
||||
|
||||
if err2 := tmpl.Execute(cli.out, vd); err2 != nil && err == nil {
|
||||
err = err2
|
||||
}
|
||||
cli.out.Write([]byte{'\n'})
|
||||
return err
|
||||
}
|
||||
411
vendor/github.com/hyperhq/hypercli/api/client/volume.go
generated
vendored
411
vendor/github.com/hyperhq/hypercli/api/client/volume.go
generated
vendored
@@ -1,411 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/hyperhq/hypercli/api/client/formatter"
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
"github.com/hyperhq/hypercli/opts"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
|
||||
"github.com/cheggaaa/pb"
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hyper-api/types/filters"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// CmdVolume is the parent subcommand for all volume commands
|
||||
//
|
||||
// Usage: docker volume <COMMAND> <OPTS>
|
||||
func (cli *DockerCli) CmdVolume(args ...string) error {
|
||||
description := Cli.DockerCommands["volume"].Description + "\n\nCommands:\n"
|
||||
commands := [][]string{
|
||||
{"create", "Create a volume"},
|
||||
{"inspect", "Return low-level information on a volume"},
|
||||
{"ls", "List volumes"},
|
||||
{"init", "Initialize volumes"},
|
||||
{"rm", "Remove a volume"},
|
||||
}
|
||||
|
||||
for _, cmd := range commands {
|
||||
description += fmt.Sprintf(" %-25.25s%s\n", cmd[0], cmd[1])
|
||||
}
|
||||
|
||||
description += "\nRun 'hyper volume COMMAND --help' for more information on a command"
|
||||
cmd := Cli.Subcmd("volume", []string{"[COMMAND]"}, description, false)
|
||||
|
||||
cmd.Require(flag.Exact, 0)
|
||||
err := cmd.ParseFlags(args, true)
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
// CmdVolumeLs outputs a list of Docker volumes.
|
||||
//
|
||||
// Usage: docker volume ls [OPTIONS]
|
||||
func (cli *DockerCli) CmdVolumeLs(args ...string) error {
|
||||
cmd := Cli.Subcmd("volume ls", nil, "List volumes", true)
|
||||
|
||||
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display volume names")
|
||||
format := cmd.String([]string{"-format"}, "", "Pretty-print containers using a Go template")
|
||||
flFilter := opts.NewListOpts(nil)
|
||||
cmd.Var(&flFilter, []string{"f", "-filter"}, "Provide filter values (i.e. 'dangling=true')")
|
||||
|
||||
cmd.Require(flag.Exact, 0)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
volFilterArgs := filters.NewArgs()
|
||||
for _, f := range flFilter.GetAll() {
|
||||
var err error
|
||||
volFilterArgs, err = filters.ParseFlag(f, volFilterArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
volumes, err := cli.client.VolumeList(context.Background(), volFilterArgs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
/*
|
||||
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
|
||||
if !*quiet {
|
||||
for _, warn := range volumes.Warnings {
|
||||
fmt.Fprintln(cli.err, warn)
|
||||
}
|
||||
fmt.Fprintf(w, "DRIVER \tVOLUME NAME\tSIZE\tCONTAINER")
|
||||
fmt.Fprintf(w, "\n")
|
||||
}
|
||||
|
||||
for _, vol := range volumes.Volumes {
|
||||
if *quiet {
|
||||
fmt.Fprintln(w, vol.Name)
|
||||
continue
|
||||
}
|
||||
var size, container string
|
||||
if vol.Labels != nil {
|
||||
size = vol.Labels["size"]
|
||||
container = vol.Labels["container"]
|
||||
if container != "" {
|
||||
container = stringid.TruncateID(container)
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(w, "%s\t%s\t%s GB\t%s\n", vol.Driver, vol.Name, size, container)
|
||||
}
|
||||
w.Flush()
|
||||
*/
|
||||
f := *format
|
||||
if len(f) == 0 {
|
||||
if len(cli.VolumesFormat()) > 0 && !*quiet {
|
||||
f = cli.VolumesFormat()
|
||||
} else {
|
||||
f = "table"
|
||||
}
|
||||
}
|
||||
|
||||
volCtx := formatter.VolumeContext{
|
||||
Context: formatter.Context{
|
||||
Output: cli.out,
|
||||
Format: f,
|
||||
Quiet: *quiet,
|
||||
},
|
||||
Volumes: volumes.Volumes,
|
||||
}
|
||||
|
||||
volCtx.Write()
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdVolumeInspect displays low-level information on one or more volumes.
|
||||
//
|
||||
// Usage: docker volume inspect [OPTIONS] VOLUME [VOLUME...]
|
||||
func (cli *DockerCli) CmdVolumeInspect(args ...string) error {
|
||||
cmd := Cli.Subcmd("volume inspect", []string{"VOLUME [VOLUME...]"}, "Return low-level information on a volume", true)
|
||||
tmplStr := cmd.String([]string{"f", "-format"}, "", "Format the output using the given go template")
|
||||
|
||||
cmd.Require(flag.Min, 1)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
inspectSearcher := func(name string) (interface{}, []byte, error) {
|
||||
i, err := cli.client.VolumeInspect(ctx, name)
|
||||
return i, nil, err
|
||||
}
|
||||
|
||||
return cli.inspectElements(*tmplStr, cmd.Args(), inspectSearcher)
|
||||
}
|
||||
|
||||
// CmdVolumeCreate creates a new volume.
|
||||
//
|
||||
// Usage: docker volume create [OPTIONS]
|
||||
func (cli *DockerCli) CmdVolumeCreate(args ...string) error {
|
||||
cmd := Cli.Subcmd("volume create", nil, "Create a volume", true)
|
||||
flDriver := cmd.String([]string{}, "hyper", "Specify volume driver name")
|
||||
flName := cmd.String([]string{"-name"}, "", "Specify volume name")
|
||||
flSnapshot := cmd.String([]string{"-snapshot"}, "", "Specify snapshot to create volume")
|
||||
flSize := cmd.Int([]string{"-size"}, 10, "Specify volume size")
|
||||
|
||||
cmd.Require(flag.Exact, 0)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
volReq := types.VolumeCreateRequest{
|
||||
Driver: *flDriver,
|
||||
DriverOpts: make(map[string]string),
|
||||
Name: *flName,
|
||||
}
|
||||
|
||||
volReq.DriverOpts["size"] = fmt.Sprintf("%d", *flSize)
|
||||
if *flSnapshot != "" {
|
||||
volReq.DriverOpts["snapshot"] = *flSnapshot
|
||||
if *flSize == 10 {
|
||||
volReq.DriverOpts["size"] = ""
|
||||
}
|
||||
}
|
||||
|
||||
vol, err := cli.client.VolumeCreate(context.Background(), volReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(cli.out, "%s\n", vol.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CmdVolumeRm removes one or more volumes.
|
||||
//
|
||||
// Usage: docker volume rm VOLUME [VOLUME...]
|
||||
func (cli *DockerCli) CmdVolumeRm(args ...string) error {
|
||||
cmd := Cli.Subcmd("volume rm", []string{"VOLUME [VOLUME...]"}, "Remove a volume", true)
|
||||
cmd.Require(flag.Min, 1)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
var status = 0
|
||||
ctx := context.Background()
|
||||
for _, name := range cmd.Args() {
|
||||
if err := cli.client.VolumeRemove(ctx, name); err != nil {
|
||||
fmt.Fprintf(cli.err, "%s\n", err)
|
||||
status = 1
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(cli.out, "%s\n", name)
|
||||
}
|
||||
|
||||
if status != 0 {
|
||||
return Cli.StatusError{StatusCode: status}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateVolumeSource(source string) error {
|
||||
switch {
|
||||
case strings.HasPrefix(source, "git://"):
|
||||
fallthrough
|
||||
case strings.HasPrefix(source, "http://"):
|
||||
fallthrough
|
||||
case strings.HasPrefix(source, "https://"):
|
||||
break
|
||||
case filepath.VolumeName(source) != "":
|
||||
fallthrough
|
||||
case strings.HasPrefix(source, "/"):
|
||||
info, err := os.Stat(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !info.Mode().IsDir() && !info.Mode().IsRegular() {
|
||||
return fmt.Errorf("Unsupported local volume source(%s): %s", source, info.Mode().String())
|
||||
}
|
||||
break
|
||||
default:
|
||||
return fmt.Errorf("%s is not supported volume source", source)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateVolumeInitArgs(args []string, req *types.VolumesInitializeRequest) ([]int, error) {
|
||||
var sourceType []int
|
||||
for _, desc := range args {
|
||||
idx := strings.LastIndexByte(desc, ':')
|
||||
if idx == -1 || idx >= len(desc)-1 {
|
||||
return nil, fmt.Errorf("%s does not match format SOURCE:VOLUME", desc)
|
||||
}
|
||||
source := desc[:idx]
|
||||
name := desc[idx+1:]
|
||||
if err := validateVolumeSource(source); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pathType, source := convertToUnixPath(source)
|
||||
req.Volume = append(req.Volume, types.VolumeInitDesc{
|
||||
Name: name,
|
||||
Source: source,
|
||||
})
|
||||
sourceType = append(sourceType, pathType)
|
||||
}
|
||||
return sourceType, nil
|
||||
}
|
||||
|
||||
// CmdVolumeInit Initializes one or more volumes.
|
||||
//
|
||||
// Usage: docker volume init SOURCE:VOLUME [SOURCE:VOLUME...]
|
||||
func (cli *DockerCli) CmdVolumeInit(args ...string) error {
|
||||
cmd := Cli.Subcmd("volume init", []string{"SOURCE:VOLUME [SOURCE:VOLUME...]"}, "Initialize a volume", true)
|
||||
cmd.Require(flag.Min, 1)
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
return cli.initVolumes(cmd.Args(), false)
|
||||
}
|
||||
|
||||
func (cli *DockerCli) initVolumes(vols []string, reload bool) error {
|
||||
var req types.VolumesInitializeRequest
|
||||
pathType, err := validateVolumeInitArgs(vols, &req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx := context.Background()
|
||||
req.Reload = reload
|
||||
resp, err := cli.client.VolumeInitialize(ctx, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(resp.Session) == 0 {
|
||||
return nil
|
||||
}
|
||||
// Upload local volumes
|
||||
var wg sync.WaitGroup
|
||||
var results []error
|
||||
pool, err := pb.StartPool()
|
||||
if err != nil {
|
||||
// Ignore progress bar failures
|
||||
fmt.Fprintf(cli.err, "Warning: do not show upload progress: %s\n", err.Error())
|
||||
pool = nil
|
||||
err = nil
|
||||
}
|
||||
for idx, desc := range req.Volume {
|
||||
if url, ok := resp.Uploaders[desc.Name]; ok {
|
||||
source := recoverPath(pathType[idx], desc.Source)
|
||||
wg.Add(1)
|
||||
go uploadLocalVolume(source, url, resp.Cookie, &results, &wg, pool)
|
||||
}
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
if pool != nil {
|
||||
pool.Stop()
|
||||
}
|
||||
for _, err = range results {
|
||||
fmt.Fprintf(cli.err, "Upload local volume failed: %s\n", err.Error())
|
||||
}
|
||||
|
||||
finishErr := cli.client.VolumeUploadFinish(ctx, resp.Session)
|
||||
if err == nil {
|
||||
err = finishErr
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func uploadLocalVolume(source, url, cookie string, results *[]error, wg *sync.WaitGroup, pool *pb.Pool) {
|
||||
var (
|
||||
resp io.ReadCloser
|
||||
tar *TarFile
|
||||
fullPath string
|
||||
err error
|
||||
)
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
*results = append(*results, err)
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
fullPath, err = filepath.Abs(source)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tar = NewTarFile(source, 512)
|
||||
walkFunc := func(path string, info os.FileInfo, err error) error {
|
||||
var relPath, linkName string
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||
linkName, err = os.Readlink(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if path == fullPath {
|
||||
if info.IsDir() {
|
||||
// "." as indicator that it is a dir volume
|
||||
relPath = "."
|
||||
} else {
|
||||
relPath = filepath.Base(path)
|
||||
}
|
||||
} else {
|
||||
relPath, err = filepath.Rel(fullPath, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
tar.AddFile(info, relPath, linkName, path)
|
||||
return nil
|
||||
}
|
||||
|
||||
err = filepath.Walk(fullPath, walkFunc)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if pool != nil {
|
||||
tar.AllocBar(pool)
|
||||
}
|
||||
|
||||
resp, err = sendTarball(url, cookie, tar)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Close()
|
||||
}
|
||||
|
||||
func sendTarball(uri, cookie string, input io.ReadCloser) (io.ReadCloser, error) {
|
||||
req, err := http.NewRequest("POST", uri+"?cookie="+cookie, input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-tar")
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
defer resp.Body.Close()
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(resp.Body)
|
||||
if buf.Len() > 0 {
|
||||
err = fmt.Errorf("%s: %s", http.StatusText(resp.StatusCode), buf.String())
|
||||
} else {
|
||||
err = fmt.Errorf("%s", http.StatusText(resp.StatusCode))
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return resp.Body, nil
|
||||
}
|
||||
39
vendor/github.com/hyperhq/hypercli/api/client/wait.go
generated
vendored
39
vendor/github.com/hyperhq/hypercli/api/client/wait.go
generated
vendored
@@ -1,39 +0,0 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
Cli "github.com/hyperhq/hypercli/cli"
|
||||
flag "github.com/hyperhq/hypercli/pkg/mflag"
|
||||
)
|
||||
|
||||
// CmdWait blocks until a container stops, then prints its exit code.
|
||||
//
|
||||
// If more than one container is specified, this will wait synchronously on each container.
|
||||
//
|
||||
// Usage: docker wait CONTAINER [CONTAINER...]
|
||||
func (cli *DockerCli) CmdWait(args ...string) error {
|
||||
cmd := Cli.Subcmd("wait", []string{"CONTAINER [CONTAINER...]"}, Cli.DockerCommands["wait"].Description, true)
|
||||
cmd.Require(flag.Min, 1)
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
var errs []string
|
||||
for _, name := range cmd.Args() {
|
||||
status, err := cli.client.ContainerWait(ctx, name)
|
||||
if err != nil {
|
||||
errs = append(errs, err.Error())
|
||||
} else {
|
||||
fmt.Fprintf(cli.out, "%d\n", status)
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf("%s", strings.Join(errs, "\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
149
vendor/github.com/hyperhq/hypercli/api/common.go
generated
vendored
149
vendor/github.com/hyperhq/hypercli/api/common.go
generated
vendored
@@ -1,149 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mime"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/libtrust"
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
"github.com/hyperhq/hypercli/pkg/system"
|
||||
"github.com/hyperhq/hypercli/pkg/version"
|
||||
)
|
||||
|
||||
// Common constants for daemon and client.
|
||||
const (
|
||||
// Version of Current REST API
|
||||
DefaultVersion version.Version = "1.23"
|
||||
|
||||
// MinVersion represents Minimum REST API version supported
|
||||
MinVersion version.Version = "1.12"
|
||||
|
||||
// DefaultDockerfileName is the Default filename with Docker commands, read by docker build
|
||||
DefaultDockerfileName string = "Dockerfile"
|
||||
|
||||
// NoBaseImageSpecifier is the symbol used by the FROM
|
||||
// command to specify that no base image is to be used.
|
||||
NoBaseImageSpecifier string = "scratch"
|
||||
)
|
||||
|
||||
// byPortInfo is a temporary type used to sort types.Port by its fields
|
||||
type byPortInfo []types.Port
|
||||
|
||||
func (r byPortInfo) Len() int { return len(r) }
|
||||
func (r byPortInfo) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
||||
func (r byPortInfo) Less(i, j int) bool {
|
||||
if r[i].PrivatePort != r[j].PrivatePort {
|
||||
return r[i].PrivatePort < r[j].PrivatePort
|
||||
}
|
||||
|
||||
if r[i].IP != r[j].IP {
|
||||
return r[i].IP < r[j].IP
|
||||
}
|
||||
|
||||
if r[i].PublicPort != r[j].PublicPort {
|
||||
return r[i].PublicPort < r[j].PublicPort
|
||||
}
|
||||
|
||||
return r[i].Type < r[j].Type
|
||||
}
|
||||
|
||||
// DisplayablePorts returns formatted string representing open ports of container
|
||||
// e.g. "0.0.0.0:80->9090/tcp, 9988/tcp"
|
||||
// it's used by command 'docker ps'
|
||||
func DisplayablePorts(ports []types.Port) string {
|
||||
type portGroup struct {
|
||||
first int
|
||||
last int
|
||||
}
|
||||
groupMap := make(map[string]*portGroup)
|
||||
var result []string
|
||||
var hostMappings []string
|
||||
var groupMapKeys []string
|
||||
sort.Sort(byPortInfo(ports))
|
||||
for _, port := range ports {
|
||||
current := port.PrivatePort
|
||||
portKey := port.Type
|
||||
if port.IP != "" {
|
||||
if port.PublicPort != current {
|
||||
hostMappings = append(hostMappings, fmt.Sprintf("%s:%d->%d/%s", port.IP, port.PublicPort, port.PrivatePort, port.Type))
|
||||
continue
|
||||
}
|
||||
portKey = fmt.Sprintf("%s/%s", port.IP, port.Type)
|
||||
}
|
||||
group := groupMap[portKey]
|
||||
|
||||
if group == nil {
|
||||
groupMap[portKey] = &portGroup{first: current, last: current}
|
||||
// record order that groupMap keys are created
|
||||
groupMapKeys = append(groupMapKeys, portKey)
|
||||
continue
|
||||
}
|
||||
if current == (group.last + 1) {
|
||||
group.last = current
|
||||
continue
|
||||
}
|
||||
|
||||
result = append(result, formGroup(portKey, group.first, group.last))
|
||||
groupMap[portKey] = &portGroup{first: current, last: current}
|
||||
}
|
||||
for _, portKey := range groupMapKeys {
|
||||
g := groupMap[portKey]
|
||||
result = append(result, formGroup(portKey, g.first, g.last))
|
||||
}
|
||||
result = append(result, hostMappings...)
|
||||
return strings.Join(result, ", ")
|
||||
}
|
||||
|
||||
func formGroup(key string, start, last int) string {
|
||||
parts := strings.Split(key, "/")
|
||||
groupType := parts[0]
|
||||
var ip string
|
||||
if len(parts) > 1 {
|
||||
ip = parts[0]
|
||||
groupType = parts[1]
|
||||
}
|
||||
group := strconv.Itoa(start)
|
||||
if start != last {
|
||||
group = fmt.Sprintf("%s-%d", group, last)
|
||||
}
|
||||
if ip != "" {
|
||||
group = fmt.Sprintf("%s:%s->%s", ip, group, group)
|
||||
}
|
||||
return fmt.Sprintf("%s/%s", group, groupType)
|
||||
}
|
||||
|
||||
// MatchesContentType validates the content type against the expected one
|
||||
func MatchesContentType(contentType, expectedType string) bool {
|
||||
mimetype, _, err := mime.ParseMediaType(contentType)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error parsing media type: %s error: %v", contentType, err)
|
||||
}
|
||||
return err == nil && mimetype == expectedType
|
||||
}
|
||||
|
||||
// LoadOrCreateTrustKey attempts to load the libtrust key at the given path,
|
||||
// otherwise generates a new one
|
||||
func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) {
|
||||
err := system.MkdirAll(filepath.Dir(trustKeyPath), 0700)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
trustKey, err := libtrust.LoadKeyFile(trustKeyPath)
|
||||
if err == libtrust.ErrKeyFileDoesNotExist {
|
||||
trustKey, err = libtrust.GenerateECP256PrivateKey()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error generating key: %s", err)
|
||||
}
|
||||
if err := libtrust.SaveKey(trustKeyPath, trustKey); err != nil {
|
||||
return nil, fmt.Errorf("Error saving key file: %s", err)
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err)
|
||||
}
|
||||
return trustKey, nil
|
||||
}
|
||||
341
vendor/github.com/hyperhq/hypercli/api/common_test.go
generated
vendored
341
vendor/github.com/hyperhq/hypercli/api/common_test.go
generated
vendored
@@ -1,341 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"os"
|
||||
|
||||
"github.com/hyperhq/hyper-api/types"
|
||||
)
|
||||
|
||||
type ports struct {
|
||||
ports []types.Port
|
||||
expected string
|
||||
}
|
||||
|
||||
// DisplayablePorts
|
||||
func TestDisplayablePorts(t *testing.T) {
|
||||
cases := []ports{
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9988,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"9988/tcp"},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9988,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"9988/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "0.0.0.0",
|
||||
PrivatePort: 9988,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"0.0.0.0:0->9988/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"9988/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "4.3.2.1",
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"4.3.2.1:8899->9988/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "4.3.2.1",
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 9988,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"4.3.2.1:9988->9988/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9988,
|
||||
Type: "udp",
|
||||
}, {
|
||||
PrivatePort: 9988,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"9988/udp, 9988/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "1.2.3.4",
|
||||
PublicPort: 9998,
|
||||
PrivatePort: 9998,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.2.3.4",
|
||||
PublicPort: 9999,
|
||||
PrivatePort: 9999,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"1.2.3.4:9998-9999->9998-9999/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "1.2.3.4",
|
||||
PublicPort: 8887,
|
||||
PrivatePort: 9998,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.2.3.4",
|
||||
PublicPort: 8888,
|
||||
PrivatePort: 9999,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"1.2.3.4:8887->9998/udp, 1.2.3.4:8888->9999/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9998,
|
||||
Type: "udp",
|
||||
}, {
|
||||
PrivatePort: 9999,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"9998-9999/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "1.2.3.4",
|
||||
PrivatePort: 6677,
|
||||
PublicPort: 7766,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"9988/udp, 1.2.3.4:7766->6677/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
IP: "1.2.3.4",
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.2.3.4",
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "4.3.2.1",
|
||||
PrivatePort: 2233,
|
||||
PublicPort: 3322,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"4.3.2.1:3322->2233/tcp, 1.2.3.4:8899->9988/tcp, 1.2.3.4:8899->9988/udp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 9988,
|
||||
PublicPort: 8899,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.2.3.4",
|
||||
PrivatePort: 6677,
|
||||
PublicPort: 7766,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "4.3.2.1",
|
||||
PrivatePort: 2233,
|
||||
PublicPort: 3322,
|
||||
Type: "tcp",
|
||||
},
|
||||
},
|
||||
"9988/udp, 4.3.2.1:3322->2233/tcp, 1.2.3.4:7766->6677/tcp",
|
||||
},
|
||||
{
|
||||
[]types.Port{
|
||||
{
|
||||
PrivatePort: 80,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
PrivatePort: 1024,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
PrivatePort: 80,
|
||||
Type: "udp",
|
||||
}, {
|
||||
PrivatePort: 1024,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.1.1.1",
|
||||
PublicPort: 80,
|
||||
PrivatePort: 1024,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "1.1.1.1",
|
||||
PublicPort: 80,
|
||||
PrivatePort: 1024,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "1.1.1.1",
|
||||
PublicPort: 1024,
|
||||
PrivatePort: 80,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "1.1.1.1",
|
||||
PublicPort: 1024,
|
||||
PrivatePort: 80,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "2.1.1.1",
|
||||
PublicPort: 80,
|
||||
PrivatePort: 1024,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "2.1.1.1",
|
||||
PublicPort: 80,
|
||||
PrivatePort: 1024,
|
||||
Type: "udp",
|
||||
}, {
|
||||
IP: "2.1.1.1",
|
||||
PublicPort: 1024,
|
||||
PrivatePort: 80,
|
||||
Type: "tcp",
|
||||
}, {
|
||||
IP: "2.1.1.1",
|
||||
PublicPort: 1024,
|
||||
PrivatePort: 80,
|
||||
Type: "udp",
|
||||
},
|
||||
},
|
||||
"80/tcp, 80/udp, 1024/tcp, 1024/udp, 1.1.1.1:1024->80/tcp, 1.1.1.1:1024->80/udp, 2.1.1.1:1024->80/tcp, 2.1.1.1:1024->80/udp, 1.1.1.1:80->1024/tcp, 1.1.1.1:80->1024/udp, 2.1.1.1:80->1024/tcp, 2.1.1.1:80->1024/udp",
|
||||
},
|
||||
}
|
||||
|
||||
for _, port := range cases {
|
||||
actual := DisplayablePorts(port.ports)
|
||||
if port.expected != actual {
|
||||
t.Fatalf("Expected %s, got %s.", port.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MatchesContentType
|
||||
func TestJsonContentType(t *testing.T) {
|
||||
if !MatchesContentType("application/json", "application/json") {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if !MatchesContentType("application/json; charset=utf-8", "application/json") {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if MatchesContentType("dockerapplication/json", "application/json") {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
// LoadOrCreateTrustKey
|
||||
func TestLoadOrCreateTrustKeyInvalidKeyFile(t *testing.T) {
|
||||
tmpKeyFolderPath, err := ioutil.TempDir("", "api-trustkey-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpKeyFolderPath)
|
||||
|
||||
tmpKeyFile, err := ioutil.TempFile(tmpKeyFolderPath, "keyfile")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := LoadOrCreateTrustKey(tmpKeyFile.Name()); err == nil {
|
||||
t.Fatalf("expected an error, got nothing.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestLoadOrCreateTrustKeyCreateKey(t *testing.T) {
|
||||
tmpKeyFolderPath, err := ioutil.TempDir("", "api-trustkey-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpKeyFolderPath)
|
||||
|
||||
// Without the need to create the folder hierarchy
|
||||
tmpKeyFile := filepath.Join(tmpKeyFolderPath, "keyfile")
|
||||
|
||||
if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil {
|
||||
t.Fatalf("expected a new key file, got : %v and %v", err, key)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(tmpKeyFile); err != nil {
|
||||
t.Fatalf("Expected to find a file %s, got %v", tmpKeyFile, err)
|
||||
}
|
||||
|
||||
// With the need to create the folder hierarchy as tmpKeyFie is in a path
|
||||
// where some folder do not exists.
|
||||
tmpKeyFile = filepath.Join(tmpKeyFolderPath, "folder/hierarchy/keyfile")
|
||||
|
||||
if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil {
|
||||
t.Fatalf("expected a new key file, got : %v and %v", err, key)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(tmpKeyFile); err != nil {
|
||||
t.Fatalf("Expected to find a file %s, got %v", tmpKeyFile, err)
|
||||
}
|
||||
|
||||
// With no path at all
|
||||
defer os.Remove("keyfile")
|
||||
if key, err := LoadOrCreateTrustKey("keyfile"); err != nil || key == nil {
|
||||
t.Fatalf("expected a new key file, got : %v and %v", err, key)
|
||||
}
|
||||
|
||||
if _, err := os.Stat("keyfile"); err != nil {
|
||||
t.Fatalf("Expected to find a file keyfile, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadOrCreateTrustKeyLoadValidKey(t *testing.T) {
|
||||
tmpKeyFile := filepath.Join("fixtures", "keyfile")
|
||||
|
||||
if key, err := LoadOrCreateTrustKey(tmpKeyFile); err != nil || key == nil {
|
||||
t.Fatalf("expected a key file, got : %v and %v", err, key)
|
||||
}
|
||||
}
|
||||
7
vendor/github.com/hyperhq/hypercli/api/fixtures/keyfile
generated
vendored
7
vendor/github.com/hyperhq/hypercli/api/fixtures/keyfile
generated
vendored
@@ -1,7 +0,0 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
keyID: AWX2:I27X:WQFX:IOMK:CNAK:O7PW:VYNB:ZLKC:CVAE:YJP2:SI4A:XXAY
|
||||
|
||||
MHcCAQEEILHTRWdcpKWsnORxSFyBnndJ4ROU41hMtr/GCiLVvwBQoAoGCCqGSM49
|
||||
AwEHoUQDQgAElpVFbQ2V2UQKajqdE3fVxJ+/pE/YuEFOxWbOxF2be19BY209/iky
|
||||
NzeFFK7SLpQ4CBJ7zDVXOHsMzrkY/GquGA==
|
||||
-----END EC PRIVATE KEY-----
|
||||
73
vendor/github.com/hyperhq/hypercli/api/server/httputils/form.go
generated
vendored
73
vendor/github.com/hyperhq/hypercli/api/server/httputils/form.go
generated
vendored
@@ -1,73 +0,0 @@
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// BoolValue transforms a form value in different formats into a boolean type.
|
||||
func BoolValue(r *http.Request, k string) bool {
|
||||
s := strings.ToLower(strings.TrimSpace(r.FormValue(k)))
|
||||
return !(s == "" || s == "0" || s == "no" || s == "false" || s == "none")
|
||||
}
|
||||
|
||||
// BoolValueOrDefault returns the default bool passed if the query param is
|
||||
// missing, otherwise it's just a proxy to boolValue above
|
||||
func BoolValueOrDefault(r *http.Request, k string, d bool) bool {
|
||||
if _, ok := r.Form[k]; !ok {
|
||||
return d
|
||||
}
|
||||
return BoolValue(r, k)
|
||||
}
|
||||
|
||||
// Int64ValueOrZero parses a form value into an int64 type.
|
||||
// It returns 0 if the parsing fails.
|
||||
func Int64ValueOrZero(r *http.Request, k string) int64 {
|
||||
val, err := Int64ValueOrDefault(r, k, 0)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Int64ValueOrDefault parses a form value into an int64 type. If there is an
|
||||
// error, returns the error. If there is no value returns the default value.
|
||||
func Int64ValueOrDefault(r *http.Request, field string, def int64) (int64, error) {
|
||||
if r.Form.Get(field) != "" {
|
||||
value, err := strconv.ParseInt(r.Form.Get(field), 10, 64)
|
||||
if err != nil {
|
||||
return value, err
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
return def, nil
|
||||
}
|
||||
|
||||
// ArchiveOptions stores archive information for different operations.
|
||||
type ArchiveOptions struct {
|
||||
Name string
|
||||
Path string
|
||||
}
|
||||
|
||||
// ArchiveFormValues parses form values and turns them into ArchiveOptions.
|
||||
// It fails if the archive name and path are not in the request.
|
||||
func ArchiveFormValues(r *http.Request, vars map[string]string) (ArchiveOptions, error) {
|
||||
if err := ParseForm(r); err != nil {
|
||||
return ArchiveOptions{}, err
|
||||
}
|
||||
|
||||
name := vars["name"]
|
||||
path := filepath.FromSlash(r.Form.Get("path"))
|
||||
|
||||
switch {
|
||||
case name == "":
|
||||
return ArchiveOptions{}, fmt.Errorf("bad parameter: 'name' cannot be empty")
|
||||
case path == "":
|
||||
return ArchiveOptions{}, fmt.Errorf("bad parameter: 'path' cannot be empty")
|
||||
}
|
||||
|
||||
return ArchiveOptions{name, path}, nil
|
||||
}
|
||||
105
vendor/github.com/hyperhq/hypercli/api/server/httputils/form_test.go
generated
vendored
105
vendor/github.com/hyperhq/hypercli/api/server/httputils/form_test.go
generated
vendored
@@ -1,105 +0,0 @@
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBoolValue(t *testing.T) {
|
||||
cases := map[string]bool{
|
||||
"": false,
|
||||
"0": false,
|
||||
"no": false,
|
||||
"false": false,
|
||||
"none": false,
|
||||
"1": true,
|
||||
"yes": true,
|
||||
"true": true,
|
||||
"one": true,
|
||||
"100": true,
|
||||
}
|
||||
|
||||
for c, e := range cases {
|
||||
v := url.Values{}
|
||||
v.Set("test", c)
|
||||
r, _ := http.NewRequest("POST", "", nil)
|
||||
r.Form = v
|
||||
|
||||
a := BoolValue(r, "test")
|
||||
if a != e {
|
||||
t.Fatalf("Value: %s, expected: %v, actual: %v", c, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoolValueOrDefault(t *testing.T) {
|
||||
r, _ := http.NewRequest("GET", "", nil)
|
||||
if !BoolValueOrDefault(r, "queryparam", true) {
|
||||
t.Fatal("Expected to get true default value, got false")
|
||||
}
|
||||
|
||||
v := url.Values{}
|
||||
v.Set("param", "")
|
||||
r, _ = http.NewRequest("GET", "", nil)
|
||||
r.Form = v
|
||||
if BoolValueOrDefault(r, "param", true) {
|
||||
t.Fatal("Expected not to get true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64ValueOrZero(t *testing.T) {
|
||||
cases := map[string]int64{
|
||||
"": 0,
|
||||
"asdf": 0,
|
||||
"0": 0,
|
||||
"1": 1,
|
||||
}
|
||||
|
||||
for c, e := range cases {
|
||||
v := url.Values{}
|
||||
v.Set("test", c)
|
||||
r, _ := http.NewRequest("POST", "", nil)
|
||||
r.Form = v
|
||||
|
||||
a := Int64ValueOrZero(r, "test")
|
||||
if a != e {
|
||||
t.Fatalf("Value: %s, expected: %v, actual: %v", c, e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64ValueOrDefault(t *testing.T) {
|
||||
cases := map[string]int64{
|
||||
"": -1,
|
||||
"-1": -1,
|
||||
"42": 42,
|
||||
}
|
||||
|
||||
for c, e := range cases {
|
||||
v := url.Values{}
|
||||
v.Set("test", c)
|
||||
r, _ := http.NewRequest("POST", "", nil)
|
||||
r.Form = v
|
||||
|
||||
a, err := Int64ValueOrDefault(r, "test", -1)
|
||||
if a != e {
|
||||
t.Fatalf("Value: %s, expected: %v, actual: %v", c, e, a)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("Error should be nil, but received: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64ValueOrDefaultWithError(t *testing.T) {
|
||||
v := url.Values{}
|
||||
v.Set("test", "invalid")
|
||||
r, _ := http.NewRequest("POST", "", nil)
|
||||
r.Form = v
|
||||
|
||||
_, err := Int64ValueOrDefault(r, "test", -1)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected an error.")
|
||||
}
|
||||
}
|
||||
178
vendor/github.com/hyperhq/hypercli/api/server/httputils/httputils.go
generated
vendored
178
vendor/github.com/hyperhq/hypercli/api/server/httputils/httputils.go
generated
vendored
@@ -1,178 +0,0 @@
|
||||
package httputils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/hyperhq/hypercli/api"
|
||||
"github.com/hyperhq/hypercli/pkg/version"
|
||||
)
|
||||
|
||||
// APIVersionKey is the client's requested API version.
|
||||
const APIVersionKey = "api-version"
|
||||
|
||||
// APIFunc is an adapter to allow the use of ordinary functions as Docker API endpoints.
|
||||
// Any function that has the appropriate signature can be register as a API endpoint (e.g. getVersion).
|
||||
type APIFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error
|
||||
|
||||
// HijackConnection interrupts the http response writer to get the
|
||||
// underlying connection and operate with it.
|
||||
func HijackConnection(w http.ResponseWriter) (io.ReadCloser, io.Writer, error) {
|
||||
conn, _, err := w.(http.Hijacker).Hijack()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Flush the options to make sure the client sets the raw mode
|
||||
conn.Write([]byte{})
|
||||
return conn, conn, nil
|
||||
}
|
||||
|
||||
// CloseStreams ensures that a list for http streams are properly closed.
|
||||
func CloseStreams(streams ...interface{}) {
|
||||
for _, stream := range streams {
|
||||
if tcpc, ok := stream.(interface {
|
||||
CloseWrite() error
|
||||
}); ok {
|
||||
tcpc.CloseWrite()
|
||||
} else if closer, ok := stream.(io.Closer); ok {
|
||||
closer.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CheckForJSON makes sure that the request's Content-Type is application/json.
|
||||
func CheckForJSON(r *http.Request) error {
|
||||
ct := r.Header.Get("Content-Type")
|
||||
|
||||
// No Content-Type header is ok as long as there's no Body
|
||||
if ct == "" {
|
||||
if r.Body == nil || r.ContentLength == 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise it better be json
|
||||
if api.MatchesContentType(ct, "application/json") {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Content-Type specified (%s) must be 'application/json'", ct)
|
||||
}
|
||||
|
||||
// ParseForm ensures the request form is parsed even with invalid content types.
|
||||
// If we don't do this, POST method without Content-type (even with empty body) will fail.
|
||||
func ParseForm(r *http.Request) error {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
if err := r.ParseForm(); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseMultipartForm ensure the request form is parsed, even with invalid content types.
|
||||
func ParseMultipartForm(r *http.Request) error {
|
||||
if err := r.ParseMultipartForm(4096); err != nil && !strings.HasPrefix(err.Error(), "mime:") {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteError decodes a specific docker error and sends it in the response.
|
||||
func WriteError(w http.ResponseWriter, err error) {
|
||||
if err == nil || w == nil {
|
||||
logrus.WithFields(logrus.Fields{"error": err, "writer": w}).Error("unexpected HTTP error handling")
|
||||
return
|
||||
}
|
||||
|
||||
statusCode := http.StatusInternalServerError
|
||||
errMsg := err.Error()
|
||||
|
||||
// Based on the type of error we get we need to process things
|
||||
// slightly differently to extract the error message.
|
||||
// In the 'errcode.*' cases there are two different type of
|
||||
// error that could be returned. errocode.ErrorCode is the base
|
||||
// type of error object - it is just an 'int' that can then be
|
||||
// used as the look-up key to find the message. errorcode.Error
|
||||
// extends errorcode.Error by adding error-instance specific
|
||||
// data, like 'details' or variable strings to be inserted into
|
||||
// the message.
|
||||
//
|
||||
// Ideally, we should just be able to call err.Error() for all
|
||||
// cases but the errcode package doesn't support that yet.
|
||||
//
|
||||
// Additionally, in both errcode cases, there might be an http
|
||||
// status code associated with it, and if so use it.
|
||||
switch err.(type) {
|
||||
case errcode.ErrorCode:
|
||||
daError, _ := err.(errcode.ErrorCode)
|
||||
statusCode = daError.Descriptor().HTTPStatusCode
|
||||
errMsg = daError.Message()
|
||||
|
||||
case errcode.Error:
|
||||
// For reference, if you're looking for a particular error
|
||||
// then you can do something like :
|
||||
// import ( derr "github.com/hyperhq/hypercli/errors" )
|
||||
// if daError.ErrorCode() == derr.ErrorCodeNoSuchContainer { ... }
|
||||
|
||||
daError, _ := err.(errcode.Error)
|
||||
statusCode = daError.ErrorCode().Descriptor().HTTPStatusCode
|
||||
errMsg = daError.Message
|
||||
|
||||
default:
|
||||
// This part of will be removed once we've
|
||||
// converted everything over to use the errcode package
|
||||
|
||||
// FIXME: this is brittle and should not be necessary.
|
||||
// If we need to differentiate between different possible error types,
|
||||
// we should create appropriate error types with clearly defined meaning
|
||||
errStr := strings.ToLower(err.Error())
|
||||
for keyword, status := range map[string]int{
|
||||
"not found": http.StatusNotFound,
|
||||
"no such": http.StatusNotFound,
|
||||
"bad parameter": http.StatusBadRequest,
|
||||
"conflict": http.StatusConflict,
|
||||
"impossible": http.StatusNotAcceptable,
|
||||
"wrong login/password": http.StatusUnauthorized,
|
||||
"hasn't been activated": http.StatusForbidden,
|
||||
} {
|
||||
if strings.Contains(errStr, keyword) {
|
||||
statusCode = status
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if statusCode == 0 {
|
||||
statusCode = http.StatusInternalServerError
|
||||
}
|
||||
|
||||
http.Error(w, errMsg, statusCode)
|
||||
}
|
||||
|
||||
// WriteJSON writes the value v to the http response stream as json with standard json encoding.
|
||||
func WriteJSON(w http.ResponseWriter, code int, v interface{}) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(code)
|
||||
return json.NewEncoder(w).Encode(v)
|
||||
}
|
||||
|
||||
// VersionFromContext returns an API version from the context using APIVersionKey.
|
||||
// It panics if the context value does not have version.Version type.
|
||||
func VersionFromContext(ctx context.Context) (ver version.Version) {
|
||||
if ctx == nil {
|
||||
return
|
||||
}
|
||||
val := ctx.Value(APIVersionKey)
|
||||
if val == nil {
|
||||
return
|
||||
}
|
||||
return val.(version.Version)
|
||||
}
|
||||
195
vendor/github.com/hyperhq/hypercli/api/server/middleware.go
generated
vendored
195
vendor/github.com/hyperhq/hypercli/api/server/middleware.go
generated
vendored
@@ -1,195 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/hyperhq/hypercli/api"
|
||||
"github.com/hyperhq/hypercli/api/server/httputils"
|
||||
"github.com/hyperhq/hypercli/dockerversion"
|
||||
"github.com/hyperhq/hypercli/errors"
|
||||
"github.com/hyperhq/hypercli/pkg/authorization"
|
||||
"github.com/hyperhq/hypercli/pkg/ioutils"
|
||||
"github.com/hyperhq/hypercli/pkg/version"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// middleware is an adapter to allow the use of ordinary functions as Docker API filters.
|
||||
// Any function that has the appropriate signature can be register as a middleware.
|
||||
type middleware func(handler httputils.APIFunc) httputils.APIFunc
|
||||
|
||||
// debugRequestMiddleware dumps the request to logger
|
||||
func debugRequestMiddleware(handler httputils.APIFunc) httputils.APIFunc {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
logrus.Debugf("%s %s", r.Method, r.RequestURI)
|
||||
|
||||
if r.Method != "POST" {
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
if err := httputils.CheckForJSON(r); err != nil {
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
maxBodySize := 4096 // 4KB
|
||||
if r.ContentLength > int64(maxBodySize) {
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
|
||||
body := r.Body
|
||||
bufReader := bufio.NewReaderSize(body, maxBodySize)
|
||||
r.Body = ioutils.NewReadCloserWrapper(bufReader, func() error { return body.Close() })
|
||||
|
||||
b, err := bufReader.Peek(maxBodySize)
|
||||
if err != io.EOF {
|
||||
// either there was an error reading, or the buffer is full (in which case the request is too large)
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
|
||||
var postForm map[string]interface{}
|
||||
if err := json.Unmarshal(b, &postForm); err == nil {
|
||||
if _, exists := postForm["password"]; exists {
|
||||
postForm["password"] = "*****"
|
||||
}
|
||||
formStr, errMarshal := json.Marshal(postForm)
|
||||
if errMarshal == nil {
|
||||
logrus.Debugf("form data: %s", string(formStr))
|
||||
} else {
|
||||
logrus.Debugf("form data: %q", postForm)
|
||||
}
|
||||
}
|
||||
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
}
|
||||
|
||||
// authorizationMiddleware perform authorization on the request.
|
||||
func (s *Server) authorizationMiddleware(handler httputils.APIFunc) httputils.APIFunc {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
// FIXME: fill when authN gets in
|
||||
// User and UserAuthNMethod are taken from AuthN plugins
|
||||
// Currently tracked in https://github.com/hyperhq/hypercli/pull/13994
|
||||
user := ""
|
||||
userAuthNMethod := ""
|
||||
authCtx := authorization.NewCtx(s.authZPlugins, user, userAuthNMethod, r.Method, r.RequestURI)
|
||||
|
||||
if err := authCtx.AuthZRequest(w, r); err != nil {
|
||||
logrus.Errorf("AuthZRequest for %s %s returned error: %s", r.Method, r.RequestURI, err)
|
||||
return err
|
||||
}
|
||||
|
||||
rw := authorization.NewResponseModifier(w)
|
||||
|
||||
if err := handler(ctx, rw, r, vars); err != nil {
|
||||
logrus.Errorf("Handler for %s %s returned error: %s", r.Method, r.RequestURI, err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := authCtx.AuthZResponse(rw, r); err != nil {
|
||||
logrus.Errorf("AuthZResponse for %s %s returned error: %s", r.Method, r.RequestURI, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// userAgentMiddleware checks the User-Agent header looking for a valid docker client spec.
|
||||
func (s *Server) userAgentMiddleware(handler httputils.APIFunc) httputils.APIFunc {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if strings.Contains(r.Header.Get("User-Agent"), "Docker-Client/") {
|
||||
dockerVersion := version.Version(s.cfg.Version)
|
||||
|
||||
userAgent := strings.Split(r.Header.Get("User-Agent"), "/")
|
||||
|
||||
// v1.20 onwards includes the GOOS of the client after the version
|
||||
// such as Docker/1.7.0 (linux)
|
||||
if len(userAgent) == 2 && strings.Contains(userAgent[1], " ") {
|
||||
userAgent[1] = strings.Split(userAgent[1], " ")[0]
|
||||
}
|
||||
|
||||
if len(userAgent) == 2 && !dockerVersion.Equal(version.Version(userAgent[1])) {
|
||||
logrus.Warnf("Warning: client and server don't have the same version (client: %s, server: %s)", userAgent[1], dockerVersion)
|
||||
}
|
||||
}
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
}
|
||||
|
||||
// corsMiddleware sets the CORS header expectations in the server.
|
||||
func (s *Server) corsMiddleware(handler httputils.APIFunc) httputils.APIFunc {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
// If "api-cors-header" is not given, but "api-enable-cors" is true, we set cors to "*"
|
||||
// otherwise, all head values will be passed to HTTP handler
|
||||
corsHeaders := s.cfg.CorsHeaders
|
||||
if corsHeaders == "" && s.cfg.EnableCors {
|
||||
corsHeaders = "*"
|
||||
}
|
||||
|
||||
if corsHeaders != "" {
|
||||
writeCorsHeaders(w, r, corsHeaders)
|
||||
}
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
}
|
||||
|
||||
// versionMiddleware checks the api version requirements before passing the request to the server handler.
|
||||
func versionMiddleware(handler httputils.APIFunc) httputils.APIFunc {
|
||||
return func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
apiVersion := version.Version(vars["version"])
|
||||
if apiVersion == "" {
|
||||
apiVersion = api.DefaultVersion
|
||||
}
|
||||
|
||||
if apiVersion.GreaterThan(api.DefaultVersion) {
|
||||
return errors.ErrorCodeNewerClientVersion.WithArgs(apiVersion, api.DefaultVersion)
|
||||
}
|
||||
if apiVersion.LessThan(api.MinVersion) {
|
||||
return errors.ErrorCodeOldClientVersion.WithArgs(apiVersion, api.MinVersion)
|
||||
}
|
||||
|
||||
w.Header().Set("Server", "Docker/"+dockerversion.Version+" ("+runtime.GOOS+")")
|
||||
ctx = context.WithValue(ctx, httputils.APIVersionKey, apiVersion)
|
||||
return handler(ctx, w, r, vars)
|
||||
}
|
||||
}
|
||||
|
||||
// handleWithGlobalMiddlwares wraps the handler function for a request with
|
||||
// the server's global middlewares. The order of the middlewares is backwards,
|
||||
// meaning that the first in the list will be evaluated last.
|
||||
//
|
||||
// Example: handleWithGlobalMiddlewares(s.getContainersName)
|
||||
//
|
||||
// s.loggingMiddleware(
|
||||
// s.userAgentMiddleware(
|
||||
// s.corsMiddleware(
|
||||
// versionMiddleware(s.getContainersName)
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
func (s *Server) handleWithGlobalMiddlewares(handler httputils.APIFunc) httputils.APIFunc {
|
||||
middlewares := []middleware{
|
||||
versionMiddleware,
|
||||
s.corsMiddleware,
|
||||
s.userAgentMiddleware,
|
||||
}
|
||||
|
||||
// Only want this on debug level
|
||||
if s.cfg.Logging && logrus.GetLevel() == logrus.DebugLevel {
|
||||
middlewares = append(middlewares, debugRequestMiddleware)
|
||||
}
|
||||
|
||||
if len(s.cfg.AuthorizationPluginNames) > 0 {
|
||||
s.authZPlugins = authorization.NewPlugins(s.cfg.AuthorizationPluginNames)
|
||||
middlewares = append(middlewares, s.authorizationMiddleware)
|
||||
}
|
||||
|
||||
h := handler
|
||||
for _, m := range middlewares {
|
||||
h = m(h)
|
||||
}
|
||||
return h
|
||||
}
|
||||
57
vendor/github.com/hyperhq/hypercli/api/server/middleware_test.go
generated
vendored
57
vendor/github.com/hyperhq/hypercli/api/server/middleware_test.go
generated
vendored
@@ -1,57 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
"github.com/hyperhq/hypercli/api/server/httputils"
|
||||
"github.com/hyperhq/hypercli/errors"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestVersionMiddleware(t *testing.T) {
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if httputils.VersionFromContext(ctx) == "" {
|
||||
t.Fatalf("Expected version, got empty string")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
h := versionMiddleware(handler)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/containers/json", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
ctx := context.Background()
|
||||
if err := h(ctx, resp, req, map[string]string{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionMiddlewareWithErrors(t *testing.T) {
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||
if httputils.VersionFromContext(ctx) == "" {
|
||||
t.Fatalf("Expected version, got empty string")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
h := versionMiddleware(handler)
|
||||
|
||||
req, _ := http.NewRequest("GET", "/containers/json", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
ctx := context.Background()
|
||||
|
||||
vars := map[string]string{"version": "0.1"}
|
||||
err := h(ctx, resp, req, vars)
|
||||
if derr, ok := err.(errcode.Error); !ok || derr.ErrorCode() != errors.ErrorCodeOldClientVersion {
|
||||
t.Fatalf("Expected ErrorCodeOldClientVersion, got %v", err)
|
||||
}
|
||||
|
||||
vars["version"] = "100000"
|
||||
err = h(ctx, resp, req, vars)
|
||||
if derr, ok := err.(errcode.Error); !ok || derr.ErrorCode() != errors.ErrorCodeNewerClientVersion {
|
||||
t.Fatalf("Expected ErrorCodeNewerClientVersion, got %v", err)
|
||||
}
|
||||
}
|
||||
38
vendor/github.com/hyperhq/hypercli/api/server/profiler.go
generated
vendored
38
vendor/github.com/hyperhq/hypercli/api/server/profiler.go
generated
vendored
@@ -1,38 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"expvar"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func profilerSetup(mainRouter *mux.Router, path string) {
|
||||
var r = mainRouter.PathPrefix(path).Subrouter()
|
||||
r.HandleFunc("/vars", expVars)
|
||||
r.HandleFunc("/pprof/", pprof.Index)
|
||||
r.HandleFunc("/pprof/cmdline", pprof.Cmdline)
|
||||
r.HandleFunc("/pprof/profile", pprof.Profile)
|
||||
r.HandleFunc("/pprof/symbol", pprof.Symbol)
|
||||
r.HandleFunc("/pprof/block", pprof.Handler("block").ServeHTTP)
|
||||
r.HandleFunc("/pprof/heap", pprof.Handler("heap").ServeHTTP)
|
||||
r.HandleFunc("/pprof/goroutine", pprof.Handler("goroutine").ServeHTTP)
|
||||
r.HandleFunc("/pprof/threadcreate", pprof.Handler("threadcreate").ServeHTTP)
|
||||
}
|
||||
|
||||
// Replicated from expvar.go as not public.
|
||||
func expVars(w http.ResponseWriter, r *http.Request) {
|
||||
first := true
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
fmt.Fprintf(w, "{\n")
|
||||
expvar.Do(func(kv expvar.KeyValue) {
|
||||
if !first {
|
||||
fmt.Fprintf(w, ",\n")
|
||||
}
|
||||
first = false
|
||||
fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
|
||||
})
|
||||
fmt.Fprintf(w, "\n}\n")
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user