Compare commits
339 Commits
Author | SHA1 | Date |
---|---|---|
Antonio Murdaca | 54e76afc03 | |
Daniel J Walsh | 4fee97abe3 | |
Kei Sawada | a50f352eb4 | |
Mrunal Patel | ed40d645cd | |
W. Trevor King | 8dbc2d1fff | |
Mrunal Patel | ddb14b7303 | |
Mrunal Patel | 924821e4bf | |
W. Trevor King | 080b84dfcd | |
Mrunal Patel | 214096b7ed | |
Antonio Murdaca | 8c87b6104f | |
Mrunal Patel | b7995aa526 | |
W. Trevor King | 822a6516cf | |
W. Trevor King | 523326b7ba | |
W. Trevor King | 826298483a | |
Mrunal Patel | 7851115693 | |
Antonio Murdaca | 77561e95cf | |
Antonio Murdaca | cbfdda868a | |
W. Trevor King | 282b900433 | |
Mrunal Patel | 1bb5846d7d | |
W. Trevor King | 15d839ea0d | |
W. Trevor King | bf8a99c085 | |
W. Trevor King | 2bf750c871 | |
Mrunal Patel | ba2b4a03d0 | |
W. Trevor King | 8c7c70c2db | |
W. Trevor King | e124834b0d | |
Antonio Murdaca | cb8033cd19 | |
Antonio Murdaca | 8c190a683c | |
Mrunal Patel | d0e0303921 | |
Antonio Murdaca | 8d2a572ead | |
Daniel J Walsh | 22e25158ca | |
Vincent Batts | 27c2eda635 | |
Daniel J Walsh | 23d20c9db5 | |
Mrunal Patel | 41aaf4e3d8 | |
Giuseppe Scrivano | 2cb22eba49 | |
Giuseppe Scrivano | 6bb1b7e17d | |
Giuseppe Scrivano | b1b380d67b | |
Antonio Murdaca | 6f4d7c1ae0 | |
Mrunal Patel | c351bc81e1 | |
Giuseppe Scrivano | b5167d4e8f | |
Giuseppe Scrivano | 1f75ec82e1 | |
Giuseppe Scrivano | 3881f375b9 | |
Mrunal Patel | ad46c581fa | |
Daniel J Walsh | 3c1c6d047e | |
Mrunal Patel | a34038350c | |
Aaron Crickenberger | a28eb8374e | |
Mrunal Patel | 295a11eb17 | |
Mrunal Patel | 28976738de | |
Haoran Wang | 88b13dfddf | |
Jianyong Wu | 8b1fefad71 | |
Mrunal Patel | 6b91df3da7 | |
Antonio Murdaca | de0be63495 | |
Daniel J Walsh | a85f3127d8 | |
Daniel J Walsh | 6c0b79b706 | |
Mrunal Patel | aee7dea272 | |
Antonio Murdaca | e344ad105a | |
Antonio Murdaca | 43119a7b13 | |
Antonio Murdaca | ecc572e7cf | |
Antonio Murdaca | 455245e65b | |
Antonio Murdaca | 7d2bde110a | |
Nalin Dahyabhai | fa90249c59 | |
Nalin Dahyabhai | 72442d0957 | |
Nalin Dahyabhai | 0ab8c507f4 | |
Nalin Dahyabhai | 492f758176 | |
Nalin Dahyabhai | 893aa4e8c7 | |
Nalin Dahyabhai | 6a456d1502 | |
Nalin Dahyabhai | 5ea050fc12 | |
Nalin Dahyabhai | ff7bbb4f0d | |
Nalin Dahyabhai | f3b7065bd8 | |
Nalin Dahyabhai | 553979e1fc | |
Nalin Dahyabhai | 0651d3a8de | |
Mrunal Patel | 2fa1f3f74a | |
Antonio Murdaca | d91df68638 | |
Mrunal Patel | da50e6ca11 | |
Mrunal Patel | ebc249cad8 | |
Antonio Murdaca | f317ffce5b | |
Mrunal Patel | a85ea609db | |
Antonio Murdaca | afeab27a36 | |
Mrunal Patel | 1f3fbdc987 | |
Nicolas Lacasse | 1138af9e59 | |
Antonio Murdaca | 06904d4dbb | |
Mrunal Patel | 85f303f3ff | |
Mrunal Patel | 989d275e76 | |
Antonio Murdaca | d168fc5fec | |
Daniel J Walsh | b9ffd277b9 | |
Antonio Murdaca | 910cfab6e9 | |
Samuel Ortiz | a2e08d5dc4 | |
Antonio Murdaca | 0eaa52c356 | |
Antonio Murdaca | 0ab5e80c38 | |
Mrunal Patel | 2cae11ba35 | |
Mrunal Patel | 40da5c2c16 | |
Antonio Murdaca | b8bba70f99 | |
Mrunal Patel | 32d2c2d57c | |
Antonio Murdaca | c8aad704dd | |
Antonio Murdaca | ea0bf448fe | |
Antonio Murdaca | 902acca4af | |
Antonio Murdaca | b59f31a2d5 | |
Antonio Murdaca | c6f68f1bf1 | |
Oleksandr Stepanov | a71948e9e7 | |
Mrunal Patel | 6faef13293 | |
Mrunal Patel | b2a78eba2b | |
Antonio Murdaca | bae4d2241f | |
Wei Wei | 3006a2159a | |
Antonio Murdaca | 5f5a7a3648 | |
Liu Chang | c0ad5277e6 | |
Mrunal Patel | d10490bccf | |
Mrunal Patel | 4cf4137be0 | |
Mrunal Patel | 4a32d0ff33 | |
Antonio Murdaca | 87f1ae214f | |
Mrunal Patel | 63371009ae | |
Antonio Murdaca | 03fb727f2b | |
Antonio Murdaca | 851759c73b | |
Daniel J Walsh | 8518e06e81 | |
Liu Chang | 42800cc96b | |
Liu Chang | bf515de94d | |
Mrunal Patel | 070b8bfdc5 | |
Mrunal Patel | 7508cdeace | |
Antonio Murdaca | 67e2d28c86 | |
Antonio Murdaca | 2f344c7533 | |
Antonio Murdaca | a75362dca0 | |
z00280905 | 2fbbf49541 | |
Mrunal Patel | 73c1a9823f | |
Antonio Murdaca | 6da7193ff5 | |
Antonio Murdaca | b3f59f31ad | |
Wei Wei | 25dfde9044 | |
Daniel J Walsh | 6c8ab88e9e | |
Mrunal Patel | 946307e5c2 | |
Daniel J Walsh | e23723d62e | |
Mrunal Patel | d68da8929a | |
Chris Evich | bbd9a6528c | |
Wei Wei | 702ab3ee3a | |
Mrunal Patel | 7b837b5a1e | |
Daniel J Walsh | 31111ba651 | |
Wei Wei | b0b6611bdf | |
Antonio Murdaca | 429a687ced | |
Mrunal Patel | 3596aa0155 | |
Mrunal Patel | 8fe6dd36a4 | |
Daniel J Walsh | e7471600f8 | |
Antonio Murdaca | 21252ed22d | |
Antonio Murdaca | 692af73b0b | |
DeShuai Ma | e90e0c7062 | |
Mrunal Patel | a447b2985c | |
Mrunal Patel | 6ed8fbeea2 | |
Antonio Murdaca | 7a675ccd92 | |
Mrunal Patel | 7076c73172 | |
Antonio Murdaca | 8ae0aee7e5 | |
Álex González | c3f86cd016 | |
Mrunal Patel | 25ac83196f | |
Antonio Murdaca | 586eda8245 | |
Daniel J Walsh | edf2300205 | |
Antonio Murdaca | 4d1e77ff9d | |
Antonio Murdaca | 80f54bc14d | |
Antonio Murdaca | 99e8676967 | |
Antonio Murdaca | e99a78edff | |
Antonio Murdaca | 33f699bad4 | |
Antonio Murdaca | befd719812 | |
Antonio Murdaca | 98f7591d5f | |
CuiHaozhi | a7f919f071 | |
Mrunal Patel | 56eb473aaa | |
Daniel J Walsh | e9200aacba | |
Antonio Murdaca | 4f4e228274 | |
Daniel J Walsh | 4fb52c2b12 | |
Daniel J Walsh | 71d2131c8c | |
Antonio Murdaca | 8611c2dfef | |
Antonio Murdaca | 190650ecca | |
Antonio Murdaca | b959f8996d | |
Nalin Dahyabhai | 7d9a89e3a7 | |
Antonio Murdaca | 9d3c442b7b | |
Chris Evich | d49fb788da | |
Antonio Murdaca | f4883dd27a | |
Daniel J Walsh | c9b3d3df28 | |
Ed Santiago | b7697672f0 | |
Daniel J Walsh | 6b6d634cfc | |
Mrunal Patel | 3f9e539bde | |
Shijiang Wei | d5ffe34758 | |
Matthew Heon | c37d369259 | |
Matthew Heon | 1bf6d20309 | |
Antonio Murdaca | 140f85df72 | |
Antonio Murdaca | 19d90e7c23 | |
Mrunal Patel | 70201fdf96 | |
Mrunal Patel | c44c712a42 | |
Mrunal Patel | fa1ad4f54e | |
Mrunal Patel | 6a43d07bae | |
Antonio Murdaca | 4dce8e12a0 | |
Mrunal Patel | 4e2c6911ad | |
Mrunal Patel | 815bb7652b | |
Antonio Murdaca | c25530ac0b | |
Antonio Murdaca | 7d7024999b | |
Antonio Murdaca | c70198617f | |
Antonio Murdaca | e41ba62b19 | |
Antonio Murdaca | 91d9b4fc29 | |
Antonio Murdaca | d6e819133d | |
Daniel J Walsh | 2453222695 | |
Antonio Murdaca | ed9f4c094a | |
Mrunal Patel | 87192d0c8c | |
Antonio Murdaca | 0478365d95 | |
Daniel J Walsh | fe69289566 | |
Mrunal Patel | 62b157c324 | |
baude | b85fe5ab90 | |
Aaron Crickenberger | 46742e1216 | |
Mrunal Patel | c23e8fc78f | |
Daniel J Walsh | 37fff3cff3 | |
Daniel J Walsh | 699fc11edf | |
Daniel J Walsh | dce6f3c2ef | |
Daniel J Walsh | 063b25cef5 | |
Mrunal Patel | 87e7280f5a | |
baude | c6cc205b78 | |
Mrunal Patel | 4c06116c18 | |
baude | 7f7ccc375f | |
baude | 484a26d540 | |
Daniel J Walsh | 409a228a73 | |
Nalin Dahyabhai | 2e5e92730a | |
Nalin Dahyabhai | 3f2bc09231 | |
Nalin Dahyabhai | beef44840e | |
Nalin Dahyabhai | 9dab0eee24 | |
Nalin Dahyabhai | 88deb3934f | |
Nalin Dahyabhai | 1346755565 | |
Daniel J Walsh | c5e73ba65f | |
Daniel J Walsh | 051cafbd62 | |
Daniel J Walsh | dbaf500c0b | |
Antonio Murdaca | 63b1706de8 | |
Daniel J Walsh | f6555bd868 | |
Jason Brooks | fad19c8082 | |
TomSweeneyRedHat | cbb380c974 | |
Daniel J Walsh | e22a3c9aea | |
Antonio Murdaca | 158d53e62a | |
Antonio Murdaca | 15afc4d3de | |
Antonio Murdaca | 3ae3c41256 | |
Mrunal Patel | 03f9350a15 | |
Daniel J Walsh | c269bf7b99 | |
Mrunal Patel | c54658cb7b | |
Lokesh Mandvekar | 74f744dc34 | |
Matthew Heon | 90b44cbf34 | |
Daniel J Walsh | 596a97119b | |
Mrunal Patel | 1442bb7ed7 | |
Matthew Heon | 97ad00b708 | |
Antonio Murdaca | 584a256388 | |
Mrunal Patel | b416ee13a0 | |
umohnani8 | f9992d71a3 | |
Matthew Heon | 1ef3e96974 | |
Matthew Heon | 3b60d38769 | |
Matthew Heon | 9b563f7970 | |
Matthew Heon | 88e2acdc4f | |
Matthew Heon | 3262565d61 | |
Matthew Heon | 872c59da8f | |
Matthew Heon | 241653e152 | |
Daniel J Walsh | 8d78e3cfac | |
Daniel J Walsh | e92aec8b97 | |
Daniel J Walsh | fb804f5602 | |
Daniel J Walsh | 17ad51011e | |
Daniel J Walsh | 14f111bd8d | |
Daniel J Walsh | a3cd7c422c | |
Daniel J Walsh | c9f837aca1 | |
Daniel J Walsh | 2e26e9b2ec | |
Daniel J Walsh | 2f43183c35 | |
Mrunal Patel | e6d2d60e4d | |
Mrunal Patel | cd04b45540 | |
Mrunal Patel | 5a4ffef9d3 | |
Daniel J Walsh | c2c148f18d | |
Nalin Dahyabhai | 9d0d48b2ce | |
Nalin Dahyabhai | a467615423 | |
Nalin Dahyabhai | 499b2fa180 | |
Nalin Dahyabhai | a5fb2b4b11 | |
Mrunal Patel | 863e137bde | |
Matthew Heon | e66da6046d | |
Masatoshi Hayashi | 9191a994fc | |
Nalin Dahyabhai | 4af9ae4bc2 | |
Antonio Murdaca | c316e5d8cf | |
umohnani8 | d855e2c8ad | |
Antonio Murdaca | 0914a7a667 | |
Matthew Heon | 042f31fe68 | |
Matthew Heon | ae5fc471ea | |
Antonio Murdaca | e95f75e8f2 | |
Antonio Murdaca | 26ca82b23d | |
Chris Evich | 61c643330e | |
Mrunal Patel | 56cda43444 | |
Mrunal Patel | 9ec09fa3ae | |
Antonio Murdaca | 7ab9c55a12 | |
Mrunal Patel | d7d2ce7ce2 | |
Daniel J Walsh | fd43871187 | |
Daniel J Walsh | c46b875fe7 | |
Antonio Murdaca | da725f3e5f | |
Daniel J Walsh | 655b47fdc4 | |
Daniel J Walsh | 6835afaa54 | |
Mrunal Patel | b0e9f0eba8 | |
Mrunal Patel | 3be3936d7d | |
Antonio Murdaca | d91877dbb2 | |
Antonio Murdaca | 12ce3ba3ed | |
Daniel J Walsh | c2b7f37bd3 | |
Chris Evich | b198c57cfb | |
Daniel J Walsh | b3ceb2a450 | |
Mrunal Patel | c04f585a53 | |
Mrunal Patel | 542994ff2a | |
Mrunal Patel | 761e73c82e | |
Mrunal Patel | eafb7f7105 | |
Mrunal Patel | f237cdb2a5 | |
Mrunal Patel | f2c4ed765b | |
Mrunal Patel | 43ae97e43c | |
Daniel J Walsh | fa23808bd6 | |
Andrew Williams | 67db54ea54 | |
umohnani8 | a11b1f953d | |
Ed Santiago | e24cfb90c0 | |
Ed Santiago | 0852f5c188 | |
Ed Santiago | c476706271 | |
Antonio Murdaca | e07ba4b2d1 | |
Antonio Murdaca | c6f5a290d8 | |
Nalin Dahyabhai | e19811238f | |
baude | 179a3f9c0e | |
Daniel J Walsh | 04951dcc6e | |
Antonio Murdaca | ab68c553d8 | |
Daniel J Walsh | 24f131584b | |
Daniel J Walsh | 70b1661e10 | |
Daniel J Walsh | 774d44589c | |
Daniel J Walsh | 4de3964686 | |
Daniel J Walsh | 7b9a5c259e | |
TomSweeneyRedHat | 54a043bfcd | |
Mrunal Patel | cd1bac5ee0 | |
Daniel J Walsh | 9888bc3ed6 | |
Mrunal Patel | 0908ad16d7 | |
Mrunal Patel | a636972c3e | |
Daniel J Walsh | 4e126d7798 | |
Mrunal Patel | 5b62041194 | |
Mrunal Patel | 38c2a34b46 | |
baude | fc2cae39ef | |
Antonio Murdaca | ab2a4839d7 | |
Daniel J Walsh | c4f7506896 | |
Samuel Ortiz | 29121c8c0c | |
Nalin Dahyabhai | ddb8fb30cc | |
Nalin Dahyabhai | a88f6840d8 | |
Mrunal Patel | 436194290a | |
umohnani8 | d1aea31786 | |
Daniel J Walsh | 5b41729b6c | |
Daniel J Walsh | a8224f8be1 | |
umohnani8 | d5b5028cb9 | |
Mrunal Patel | bb4b2e9fea | |
Daniel J Walsh | d7cbdfce76 | |
baude | 3907e0d346 | |
Daniel J Walsh | 3363064622 | |
Matthew Heon | 92def27645 | |
Mrunal Patel | 7c2c9a8c85 |
|
@ -0,0 +1,7 @@
|
|||
# GitHub code owners
|
||||
# See https://help.github.com/articles/about-codeowners/
|
||||
#
|
||||
# KEEP THIS FILE SORTED. Order is important. Last match takes precedence.
|
||||
|
||||
* @mrunalp @runcom
|
||||
pkg/storage/** @nalind @runcom @rhatdan
|
|
@ -0,0 +1,58 @@
|
|||
<!--
|
||||
If you are reporting a new issue, make sure that we do not have any duplicates
|
||||
already open. You can ensure this by searching the issue list for this
|
||||
repository. If there is a duplicate, please close your issue and add a comment
|
||||
to the existing issue instead.
|
||||
|
||||
If you suspect your issue is a bug, please edit your issue description to
|
||||
include the BUG REPORT INFORMATION shown below. If you fail to provide this
|
||||
information within 7 days, we cannot debug your issue and will close it. We
|
||||
will, however, reopen it if you later provide the information.
|
||||
|
||||
For more information about reporting issues, see
|
||||
https://github.com/kubernetes-incubator/cri-o/blob/master/CONTRIBUTING.md#reporting-issues
|
||||
|
||||
---------------------------------------------------
|
||||
GENERAL SUPPORT INFORMATION
|
||||
---------------------------------------------------
|
||||
|
||||
The GitHub issue tracker is for bug reports and feature requests.
|
||||
General support for **CRI-O** can be found at the following locations:
|
||||
|
||||
- IRC - #cri-o channel on irc.freenode.org
|
||||
- Slack - kubernetes.slack.com #sig-node channel
|
||||
- Post a question on StackOverflow, using the CRI-O tag
|
||||
|
||||
---------------------------------------------------
|
||||
BUG REPORT INFORMATION
|
||||
---------------------------------------------------
|
||||
Use the commands below to provide key information from your environment:
|
||||
You do NOT have to include this information if this is a FEATURE REQUEST
|
||||
-->
|
||||
|
||||
**Description**
|
||||
|
||||
<!--
|
||||
Briefly describe the problem you are having in a few paragraphs.
|
||||
-->
|
||||
|
||||
**Steps to reproduce the issue:**
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
**Describe the results you received:**
|
||||
|
||||
|
||||
**Describe the results you expected:**
|
||||
|
||||
|
||||
**Additional information you deem important (e.g. issue happens only occasionally):**
|
||||
|
||||
**Output of `crio --version`:**
|
||||
|
||||
```
|
||||
(paste your output here)
|
||||
```
|
||||
|
||||
**Additional environment details (AWS, VirtualBox, physical, etc.):**
|
|
@ -0,0 +1,23 @@
|
|||
<!--
|
||||
Please make sure you've read and understood our contributing guidelines;
|
||||
https://github.com/kubernetes-incubator/cri-o/blob/master/CONTRIBUTING.md
|
||||
|
||||
** Make sure all your commits include a signature generated with `git commit -s` **
|
||||
|
||||
If this is a bug fix, make sure your description includes "fixes #xxxx", or
|
||||
"closes #xxxx"
|
||||
|
||||
Please provide the following information:
|
||||
-->
|
||||
|
||||
**- What I did**
|
||||
|
||||
**- How I did it**
|
||||
|
||||
**- How to verify it**
|
||||
|
||||
**- Description for the changelog**
|
||||
<!--
|
||||
Write a short (one line) summary that describes the changes in this
|
||||
pull request for inclusion in the changelog:
|
||||
-->
|
|
@ -1,17 +1,18 @@
|
|||
/.artifacts/
|
||||
/_output/
|
||||
/conmon/conmon
|
||||
/conmon/conmon.o
|
||||
/docs/*.[158]
|
||||
/docs/*.[158].gz
|
||||
/kpod
|
||||
/crioctl
|
||||
/crio
|
||||
/crio.conf
|
||||
*.o
|
||||
*.orig
|
||||
/pause/pause
|
||||
/pause/pause.o
|
||||
/bin/
|
||||
/test/bin2img/bin2img
|
||||
/test/checkseccomp/checkseccomp
|
||||
/test/copyimg/copyimg
|
||||
|
||||
Vagrantfile
|
||||
.vagrant/
|
||||
|
||||
.vscode/
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
Aleksa Sarai <asarai@suse.de> <asarai@suse.com>
|
||||
Antonio Murdaca <runcom@redhat.com> <runcom@users.noreply.github.com>
|
||||
CuiHaozhi <cuihaozhi@chinacloud.com.cn> <cuihz@wise2c.com>
|
||||
Daniel J Walsh <dwalsh@redhat.com>
|
||||
Haiyan Meng <hmeng@redhat.com> <haiyanalady@gmail.com>
|
||||
Lorenzo Fontana <lo@linux.com> <fontanalorenz@gmail.com>
|
||||
Mrunal Patel <mrunalp@gmail.com> <mpatel@redhat.com>
|
||||
Mrunal Patel <mrunalp@gmail.com> <mrunal@me.com>
|
||||
Pengfei Ni <feiskyer@gmail.com> <feiskyer@users.noreply.github.com>
|
||||
Tobias Klauser <tklauser@distanz.ch> <tobias.klauser@gmail.com>
|
|
@ -47,8 +47,6 @@ jobs:
|
|||
go: 1.9.x
|
||||
- script:
|
||||
- make .gitvalidation
|
||||
- make gofmt
|
||||
- make lint
|
||||
- make testunit
|
||||
- make docs
|
||||
- make
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
# Contributing to CRI-O
|
||||
|
||||
We'd love to have you join the community! Below summarizes the processes
|
||||
that we follow.
|
||||
|
||||
## Topics
|
||||
|
||||
* [Reporting Issues](#reporting-issues)
|
||||
* [Submitting Pull Requests](#submitting-pull-requests)
|
||||
* [Communications](#communications)
|
||||
* [Becoming a Maintainer](#becoming-a-maintainer)
|
||||
|
||||
## Reporting Issues
|
||||
|
||||
Before reporting an issue, check our backlog of
|
||||
[open issues](https://github.com/kubernetes-incubator/cri-o/issues)
|
||||
to see if someone else has already reported it. If so, feel free to add
|
||||
your scenario, or additional information, to the discussion. Or simply
|
||||
"subscribe" to it to be notified when it is updated.
|
||||
|
||||
If you find a new issue with the project we'd love to hear about it! The most
|
||||
important aspect of a bug report is that it includes enough information for
|
||||
us to reproduce it. So, please include as much detail as possible and try
|
||||
to remove the extra stuff that doesn't really relate to the issue itself.
|
||||
The easier it is for us to reproduce it, the faster it'll be fixed!
|
||||
|
||||
Please don't include any private/sensitive information in your issue!
|
||||
|
||||
## Submitting Pull Requests
|
||||
|
||||
No Pull Request (PR) is too small! Typos, additional comments in the code,
|
||||
new testcases, bug fixes, new features, more documentation, ... it's all
|
||||
welcome!
|
||||
|
||||
While bug fixes can first be identified via an "issue", that is not required.
|
||||
It's ok to just open up a PR with the fix, but make sure you include the same
|
||||
information you would have included in an issue - like how to reproduce it.
|
||||
|
||||
PRs for new features should include some background on what use cases the
|
||||
new code is trying to address. When possible and when it makes sense, try to break-up
|
||||
larger PRs into smaller ones - it's easier to review smaller
|
||||
code changes. But only if those smaller ones make sense as stand-alone PRs.
|
||||
|
||||
Regardless of the type of PR, all PRs should include:
|
||||
* well documented code changes
|
||||
* additional testcases. Ideally, they should fail w/o your code change applied
|
||||
* documentation changes
|
||||
|
||||
Squash your commits into logical pieces of work that might want to be reviewed
|
||||
separate from the rest of the PRs. But, squashing down to just one commit is ok
|
||||
too since in the end the entire PR will be reviewed anyway. When in doubt,
|
||||
squash.
|
||||
|
||||
PRs that fix issues should include a reference like `Closes #XXXX` in the
|
||||
commit message so that github will automatically close the referenced issue
|
||||
when the PR is merged.
|
||||
|
||||
<!--
|
||||
All PRs require at least two LGTMs (Looks Good To Me) from maintainers.
|
||||
-->
|
||||
|
||||
### Sign your PRs
|
||||
|
||||
The sign-off is a 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 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`.
|
||||
|
||||
## Communications
|
||||
|
||||
For general questions, or discussions, please use the
|
||||
IRC group on `irc.freenode.net` called `cri-o`
|
||||
that has been setup.
|
||||
|
||||
For discussions around issues/bugs and features, you can use the github
|
||||
[issues](https://github.com/kubernetes-incubator/cri-o/issues)
|
||||
and
|
||||
[PRs](https://github.com/kubernetes-incubator/cri-o/pulls)
|
||||
tracking system.
|
||||
|
||||
<!--
|
||||
## Becoming a Maintainer
|
||||
|
||||
To become a maintainer you must first be nominated by an existing maintainer.
|
||||
If a majority (>50%) of maintainers agree then the proposal is adopted and
|
||||
you will be added to the list.
|
||||
|
||||
Removing a maintainer requires at least 75% of the remaining maintainers
|
||||
approval, or if the person requests to be removed then it is automatic.
|
||||
Normally, a maintainer will only be removed if they are considered to be
|
||||
inactive for a long period of time or are viewed as disruptive to the community.
|
||||
|
||||
The current list of maintainers can be found in the
|
||||
[MAINTAINERS](MAINTAINERS) file.
|
||||
-->
|
|
@ -38,6 +38,7 @@ RUN apt-get update && apt-get install -y \
|
|||
netcat \
|
||||
socat \
|
||||
--no-install-recommends \
|
||||
bsdmainutils \
|
||||
&& apt-get clean
|
||||
|
||||
# install bats
|
||||
|
@ -56,7 +57,7 @@ RUN mkdir -p /usr/src/criu \
|
|||
&& rm -rf /usr/src/criu
|
||||
|
||||
# Install runc
|
||||
ENV RUNC_COMMIT 84a082bfef6f932de921437815355186db37aeb1
|
||||
ENV RUNC_COMMIT c6e4a1ebeb1a72b529c6f1b6ee2b1ae5b868b14f
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/opencontainers/runc.git "$GOPATH/src/github.com/opencontainers/runc" \
|
||||
|
@ -64,7 +65,7 @@ RUN set -x \
|
|||
&& git fetch origin --tags \
|
||||
&& git checkout -q "$RUNC_COMMIT" \
|
||||
&& make static BUILDTAGS="seccomp selinux" \
|
||||
&& cp runc /usr/local/bin/runc \
|
||||
&& cp runc /usr/bin/runc \
|
||||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Install CNI plugins
|
||||
|
@ -97,7 +98,7 @@ RUN set -x \
|
|||
&& rm -rf "$GOPATH"
|
||||
|
||||
# Install crictl
|
||||
ENV CRICTL_COMMIT 16e6fe4d7199c5689db4630a9330e6a8a12cecd1
|
||||
ENV CRICTL_COMMIT b42fc3f364dd48f649d55926c34492beeb9b2e99
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/kubernetes-incubator/cri-tools.git "$GOPATH/src/github.com/kubernetes-incubator/cri-tools" \
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
0.1
|
64
Makefile
64
Makefile
|
@ -11,7 +11,9 @@ LIBEXECDIR ?= ${PREFIX}/libexec
|
|||
MANDIR ?= ${PREFIX}/share/man
|
||||
ETCDIR ?= ${DESTDIR}/etc
|
||||
ETCDIR_CRIO ?= ${ETCDIR}/crio
|
||||
BUILDTAGS ?= selinux seccomp $(shell hack/btrfs_tag.sh) $(shell hack/libdm_tag.sh) $(shell hack/btrfs_installed_tag.sh)
|
||||
BUILDTAGS ?= seccomp $(shell hack/btrfs_tag.sh) $(shell hack/libdm_installed.sh) $(shell hack/libdm_no_deferred_remove_tag.sh) $(shell hack/btrfs_installed_tag.sh) $(shell hack/ostree_tag.sh) $(shell hack/selinux_tag.sh)
|
||||
CRICTL_CONFIG_DIR=${DESTDIR}/etc
|
||||
|
||||
BASHINSTALLDIR=${PREFIX}/share/bash-completion/completions
|
||||
OCIUMOUNTINSTALLDIR=$(PREFIX)/share/oci-umount/oci-umount.d
|
||||
|
||||
|
@ -22,9 +24,6 @@ COMMIT_NO := $(shell git rev-parse HEAD 2> /dev/null || true)
|
|||
GIT_COMMIT := $(if $(shell git status --porcelain --untracked-files=no),"${COMMIT_NO}-dirty","${COMMIT_NO}")
|
||||
BUILD_INFO := $(shell date +%s)
|
||||
|
||||
VERSION := ${shell cat ./VERSION}
|
||||
KPOD_VERSION := ${shell cat ./KPOD_VERSION}
|
||||
|
||||
# If GOPATH not specified, use one in the local directory
|
||||
ifeq ($(GOPATH),)
|
||||
export GOPATH := $(CURDIR)/_output
|
||||
|
@ -35,8 +34,9 @@ GOPKGBASEDIR := $(shell dirname "$(GOPKGDIR)")
|
|||
|
||||
# Update VPATH so make finds .gopathok
|
||||
VPATH := $(VPATH):$(GOPATH)
|
||||
|
||||
LDFLAGS := -ldflags '-X main.gitCommit=${GIT_COMMIT} -X main.buildInfo=${BUILD_INFO} -X main.version=${VERSION} -X main.kpodVersion=${KPOD_VERSION}'
|
||||
SHRINKFLAGS := -s -w
|
||||
BASE_LDFLAGS := ${SHRINKFLAGS} -X main.gitCommit=${GIT_COMMIT} -X main.buildInfo=${BUILD_INFO}
|
||||
LDFLAGS := -ldflags '${BASE_LDFLAGS}'
|
||||
|
||||
all: binaries crio.conf docs
|
||||
|
||||
|
@ -46,7 +46,7 @@ help:
|
|||
@echo "Usage: make <target>"
|
||||
@echo
|
||||
@echo " * 'install' - Install binaries to system locations"
|
||||
@echo " * 'binaries' - Build crio, conmon and crioctl"
|
||||
@echo " * 'binaries' - Build crio, conmon and pause"
|
||||
@echo " * 'integration' - Execute integration tests"
|
||||
@echo " * 'clean' - Clean artifacts"
|
||||
@echo " * 'lint' - Execute the source code linter"
|
||||
|
@ -64,7 +64,8 @@ lint: .gopathok
|
|||
@./.tool/lint
|
||||
|
||||
gofmt:
|
||||
@./hack/verify-gofmt.sh
|
||||
find . -name '*.go' ! -path './vendor/*' -exec gofmt -s -w {} \+
|
||||
git diff --exit-code
|
||||
|
||||
conmon:
|
||||
$(MAKE) -C $@
|
||||
|
@ -73,36 +74,30 @@ pause:
|
|||
$(MAKE) -C $@
|
||||
|
||||
test/bin2img/bin2img: .gopathok $(wildcard test/bin2img/*.go)
|
||||
$(GO) build $(LDFLAGS) -tags "$(BUILDTAGS)" -o $@ $(PROJECT)/test/bin2img
|
||||
$(GO) build -i $(LDFLAGS) -tags "$(BUILDTAGS) containers_image_ostree_stub" -o $@ $(PROJECT)/test/bin2img
|
||||
|
||||
test/copyimg/copyimg: .gopathok $(wildcard test/copyimg/*.go)
|
||||
$(GO) build $(LDFLAGS) -tags "$(BUILDTAGS)" -o $@ $(PROJECT)/test/copyimg
|
||||
$(GO) build -i $(LDFLAGS) -tags "$(BUILDTAGS) containers_image_ostree_stub" -o $@ $(PROJECT)/test/copyimg
|
||||
|
||||
test/checkseccomp/checkseccomp: .gopathok $(wildcard test/checkseccomp/*.go)
|
||||
$(GO) build $(LDFLAGS) -tags "$(BUILDTAGS)" -o $@ $(PROJECT)/test/checkseccomp
|
||||
$(GO) build -i $(LDFLAGS) -tags "$(BUILDTAGS) containers_image_ostree_stub" -o $@ $(PROJECT)/test/checkseccomp
|
||||
|
||||
crio: .gopathok $(shell hack/find-godeps.sh $(GOPKGDIR) cmd/crio $(PROJECT))
|
||||
$(GO) build $(LDFLAGS) -tags "$(BUILDTAGS)" -o $@ $(PROJECT)/cmd/crio
|
||||
|
||||
crioctl: .gopathok $(shell hack/find-godeps.sh $(GOPKGDIR) cmd/crioctl $(PROJECT))
|
||||
$(GO) build $(LDFLAGS) -tags "$(BUILDTAGS)" -o $@ $(PROJECT)/cmd/crioctl
|
||||
|
||||
kpod: .gopathok $(shell hack/find-godeps.sh $(GOPKGDIR) cmd/kpod $(PROJECT))
|
||||
$(GO) build $(LDFLAGS) -tags "$(BUILDTAGS)" -o $@ $(PROJECT)/cmd/kpod
|
||||
$(GO) build -i $(LDFLAGS) -tags "$(BUILDTAGS) containers_image_ostree_stub" -o bin/$@ $(PROJECT)/cmd/crio
|
||||
|
||||
crio.conf: crio
|
||||
./crio --config="" config --default > crio.conf
|
||||
./bin/crio --config="" config --default > crio.conf
|
||||
|
||||
clean:
|
||||
ifneq ($(GOPATH),)
|
||||
rm -f "$(GOPATH)/.gopathok"
|
||||
endif
|
||||
rm -rf _output
|
||||
rm -f docs/*.1 docs/*.5 docs/*.8
|
||||
rm -f docs/*.5 docs/*.8
|
||||
rm -fr test/testdata/redis-image
|
||||
find . -name \*~ -delete
|
||||
find . -name \#\* -delete
|
||||
rm -f crioctl crio kpod
|
||||
rm -f bin/crio
|
||||
make -C conmon clean
|
||||
make -C pause clean
|
||||
rm -f test/bin2img/bin2img
|
||||
|
@ -113,25 +108,23 @@ crioimage:
|
|||
docker build -t ${CRIO_IMAGE} .
|
||||
|
||||
dbuild: crioimage
|
||||
docker run --name=${CRIO_INSTANCE} --privileged ${CRIO_IMAGE} -v ${PWD}:/go/src/${PROJECT} --rm make binaries
|
||||
docker run --name=${CRIO_INSTANCE} -e BUILDTAGS --privileged -v ${PWD}:/go/src/${PROJECT} --rm ${CRIO_IMAGE} make binaries
|
||||
|
||||
integration: crioimage
|
||||
docker run -e STORAGE_OPTS="--storage-driver=vfs" -e TESTFLAGS -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${CRIO_IMAGE} make localintegration
|
||||
docker run -e STORAGE_OPTIONS="--storage-driver=vfs" -e TESTFLAGS -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${CRIO_IMAGE} make localintegration
|
||||
|
||||
testunit:
|
||||
$(GO) test -tags "$(BUILDTAGS)" -cover $(PACKAGES)
|
||||
|
||||
localintegration: clean binaries
|
||||
localintegration: clean binaries test-binaries
|
||||
./test/test_runner.sh ${TESTFLAGS}
|
||||
|
||||
binaries: crio crioctl kpod conmon pause test/bin2img/bin2img test/copyimg/copyimg test/checkseccomp/checkseccomp
|
||||
binaries: crio conmon pause
|
||||
test-binaries: test/bin2img/bin2img test/copyimg/copyimg test/checkseccomp/checkseccomp
|
||||
|
||||
MANPAGES_MD := $(wildcard docs/*.md)
|
||||
MANPAGES := $(MANPAGES_MD:%.md=%)
|
||||
|
||||
docs/%.1: docs/%.1.md .gopathok
|
||||
(go-md2man -in $< -out $@.tmp && touch $@.tmp && mv $@.tmp $@) || ($(GOPATH)/bin/go-md2man -in $< -out $@.tmp && touch $@.tmp && mv $@.tmp $@)
|
||||
|
||||
docs/%.5: docs/%.5.md .gopathok
|
||||
(go-md2man -in $< -out $@.tmp && touch $@.tmp && mv $@.tmp $@) || ($(GOPATH)/bin/go-md2man -in $< -out $@.tmp && touch $@.tmp && mv $@.tmp $@)
|
||||
|
||||
|
@ -143,28 +136,24 @@ docs: $(MANPAGES)
|
|||
install: .gopathok install.bin install.man
|
||||
|
||||
install.bin:
|
||||
install ${SELINUXOPT} -D -m 755 crio $(BINDIR)/crio
|
||||
install ${SELINUXOPT} -D -m 755 crioctl $(BINDIR)/crioctl
|
||||
install ${SELINUXOPT} -D -m 755 kpod $(BINDIR)/kpod
|
||||
install ${SELINUXOPT} -D -m 755 conmon/conmon $(LIBEXECDIR)/crio/conmon
|
||||
install ${SELINUXOPT} -D -m 755 pause/pause $(LIBEXECDIR)/crio/pause
|
||||
install ${SELINUXOPT} -D -m 755 bin/crio $(BINDIR)/crio
|
||||
install ${SELINUXOPT} -D -m 755 bin/conmon $(LIBEXECDIR)/crio/conmon
|
||||
install ${SELINUXOPT} -D -m 755 bin/pause $(LIBEXECDIR)/crio/pause
|
||||
|
||||
install.man:
|
||||
install ${SELINUXOPT} -d -m 755 $(MANDIR)/man1
|
||||
install ${SELINUXOPT} -d -m 755 $(MANDIR)/man5
|
||||
install ${SELINUXOPT} -d -m 755 $(MANDIR)/man8
|
||||
install ${SELINUXOPT} -m 644 $(filter %.1,$(MANPAGES)) -t $(MANDIR)/man1
|
||||
install ${SELINUXOPT} -m 644 $(filter %.5,$(MANPAGES)) -t $(MANDIR)/man5
|
||||
install ${SELINUXOPT} -m 644 $(filter %.8,$(MANPAGES)) -t $(MANDIR)/man8
|
||||
|
||||
install.config:
|
||||
install.config: crio.conf
|
||||
install ${SELINUXOPT} -D -m 644 crio.conf $(ETCDIR_CRIO)/crio.conf
|
||||
install ${SELINUXOPT} -D -m 644 seccomp.json $(ETCDIR_CRIO)/seccomp.json
|
||||
install ${SELINUXOPT} -D -m 644 crio-umount.conf $(OCIUMOUNTINSTALLDIR)/crio-umount.conf
|
||||
install ${SELINUXOPT} -D -m 644 crictl.yaml $(CRICTL_CONFIG_DIR)
|
||||
|
||||
install.completions:
|
||||
install ${SELINUXOPT} -d -m 755 ${BASHINSTALLDIR}
|
||||
install ${SELINUXOPT} -m 644 -D completions/bash/kpod ${BASHINSTALLDIR}
|
||||
|
||||
install.systemd:
|
||||
install ${SELINUXOPT} -D -m 644 contrib/systemd/crio.service $(PREFIX)/lib/systemd/system/crio.service
|
||||
|
@ -173,7 +162,6 @@ install.systemd:
|
|||
|
||||
uninstall:
|
||||
rm -f $(BINDIR)/crio
|
||||
rm -f $(BINDIR)/crioctl
|
||||
rm -f $(LIBEXECDIR)/crio/conmon
|
||||
rm -f $(LIBEXECDIR)/crio/pause
|
||||
for i in $(filter %.1,$(MANPAGES)); do \
|
||||
|
|
90
README.md
90
README.md
|
@ -1,18 +1,32 @@
|
|||
![cri-o logo](https://cdn.rawgit.com/kubernetes-incubator/cri-o/master/logo/crio-logo.svg)
|
||||
# cri-o - OCI-based implementation of Kubernetes Container Runtime Interface
|
||||
![CRI-O logo](https://cdn.rawgit.com/kubernetes-incubator/cri-o/master/logo/crio-logo.svg)
|
||||
# CRI-O - OCI-based implementation of Kubernetes Container Runtime Interface
|
||||
|
||||
[![Build Status](https://img.shields.io/travis/kubernetes-incubator/cri-o.svg?maxAge=2592000&style=flat-square)](https://travis-ci.org/kubernetes-incubator/cri-o)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/kubernetes-incubator/cri-o?style=flat-square)](https://goreportcard.com/report/github.com/kubernetes-incubator/cri-o)
|
||||
|
||||
### Status: Release Candidate 3
|
||||
### Status: Stable
|
||||
|
||||
## Compatibility matrix: CRI-O <-> Kubernetes clusters
|
||||
|
||||
| Version - Branch | Kubernetes branch/version | Maintenance status |
|
||||
|----------------------------|-------------------------------|--------------------|
|
||||
| CRI-O 1.0.x - release-1.0 | Kubernetes 1.7 branch, v1.7.x | = |
|
||||
| CRI-O 1.8.x - release-1.8 | Kubernetes 1.8 branch, v1.8.x | = |
|
||||
| CRI-O 1.9.x - release-1.9 | Kubernetes 1.9 branch, v1.9.x | = |
|
||||
| CRI-O HEAD - master | Kubernetes master branch | ✓ |
|
||||
|
||||
Key:
|
||||
|
||||
* `✓` Changes in main Kubernetes repo about CRI are actively implemented in CRI-O
|
||||
* `=` Maintenance is manual, only bugs will be patched.
|
||||
|
||||
## What is the scope of this project?
|
||||
|
||||
cri-o is meant to provide an integration path between OCI conformant runtimes and the kubelet.
|
||||
CRI-O is meant to provide an integration path between OCI conformant runtimes and the kubelet.
|
||||
Specifically, it implements the Kubelet [Container Runtime Interface (CRI)](https://github.com/kubernetes/community/blob/master/contributors/devel/container-runtime-interface.md) using OCI conformant runtimes.
|
||||
The scope of cri-o is tied to the scope of the CRI.
|
||||
The scope of CRI-O is tied to the scope of the CRI.
|
||||
|
||||
At a high level, we expect the scope of cri-o to be restricted to the following functionalities:
|
||||
At a high level, we expect the scope of CRI-O to be restricted to the following functionalities:
|
||||
|
||||
* Support multiple image formats including the existing Docker image format
|
||||
* Support for multiple means to download images including trust & image verification
|
||||
|
@ -24,7 +38,7 @@ At a high level, we expect the scope of cri-o to be restricted to the following
|
|||
## What is not in scope for this project?
|
||||
|
||||
* Building, signing and pushing images to various image storages
|
||||
* A CLI utility for interacting with cri-o. Any CLIs built as part of this project are only meant for testing this project and there will be no guarantees on the backward compatibility with it.
|
||||
* A CLI utility for interacting with CRI-O. Any CLIs built as part of this project are only meant for testing this project and there will be no guarantees on the backward compatibility with it.
|
||||
|
||||
This is an implementation of the Kubernetes Container Runtime Interface (CRI) that will allow Kubernetes to directly launch and manage Open Container Initiative (OCI) containers.
|
||||
|
||||
|
@ -40,36 +54,8 @@ It is currently in active development in the Kubernetes community through the [d
|
|||
| Command | Description | Demo|
|
||||
| ---------------------------------------------------- | --------------------------------------------------------------------------|-----|
|
||||
| [crio(8)](/docs/crio.8.md) | OCI Kubernetes Container Runtime daemon ||
|
||||
| [kpod(1)](/docs/kpod.1.md) | Simple management tool for pods and images ||
|
||||
| [kpod-attach(1)](/docs/kpod-attach.1.md) | Instead of providing a `kpod attach` command, the man page `kpod-attach` describes how to use the `kpod logs` and `kpod exec` commands to achieve the same goals as `kpod attach`.||
|
||||
| [kpod-cp(1)](/docs/kpod-cp.1.md) | Instead of providing a `kpod cp` command, the man page `kpod-cp` describes how to use the `kpod mount` command to have even more flexibility and functionality.||
|
||||
| [kpod-diff(1)](/docs/kpod-diff.1.md) | Inspect changes on a container or image's filesystem ||
|
||||
| [kpod-export(1)](/docs/kpod-export.1.md) | Export container's filesystem contents as a tar archive |[![...](/docs/play.png)](https://asciinema.org/a/913lBIRAg5hK8asyIhhkQVLtV)|
|
||||
| [kpod-history(1)](/docs/kpod-history.1.md) | Shows the history of an image |[![...](/docs/play.png)](https://asciinema.org/a/bCvUQJ6DkxInMELZdc5DinNSx)|
|
||||
| [kpod-images(1)](/docs/kpod-images.1.md) | List images in local storage |[![...](/docs/play.png)](https://asciinema.org/a/133649)|
|
||||
| [kpod-info(1)](/docs/kpod-info.1.md) | Display system information ||
|
||||
| [kpod-inspect(1)](/docs/kpod-inspect.1.md) | Display the configuration of a container or image |[![...](/docs/play.png)](https://asciinema.org/a/133418)|
|
||||
| [kpod-kill(1)](/docs/kpod-kill.1.md) | Kill the main process in one or more running containers |[![...](/docs/play.png)](https://asciinema.org/a/3jNos0A5yzO4hChu7ddKkUPw7)|
|
||||
| [kpod-load(1)](/docs/kpod-load.1.md) | Load an image from docker archive or oci |[![...](/docs/play.png)](https://asciinema.org/a/kp8kOaexEhEa20P1KLZ3L5X4g)|
|
||||
| [kpod-login(1)](/docs/kpod-login.1.md) | Login to a container registry ||
|
||||
| [kpod-logout(1)](/docs/kpod-logout.1.md) | Logout of a container registry ||
|
||||
| [kpod-logs(1)](/docs/kpod-logs.1.md) | Display the logs of a container ||
|
||||
| [kpod-mount(1)](/docs/kpod-mount.1.md) | Mount a working container's root filesystem ||
|
||||
| [kpod-pause(1)](/docs/kpod-pause.1.md) | Pause one or more running containers |[![...](/docs/play.png)](https://asciinema.org/a/141292)|
|
||||
| [kpod-ps(1)](/docs/kpod-ps.1.md) | Prints out information about containers |[![...](/docs/play.png)](https://asciinema.org/a/bbT41kac6CwZ5giESmZLIaTLR)|
|
||||
| [kpod-pull(1)](/docs/kpod-pull.1.md) | Pull an image from a registry |[![...](/docs/play.png)](https://asciinema.org/a/lr4zfoynHJOUNu1KaXa1dwG2X)|
|
||||
| [kpod-push(1)](/docs/kpod-push.1.md) | Push an image to a specified destination |[![...](/docs/play.png)](https://asciinema.org/a/133276)|
|
||||
| [kpod-rename(1)](/docs/kpod-rename.1.md) | Rename a container ||
|
||||
| [kpod-rm(1)](/docs/kpod-rm.1.md) | Removes one or more containers |[![...](/docs/play.png)](https://asciinema.org/a/7EMk22WrfGtKWmgHJX9Nze1Qp)|
|
||||
| [kpod-rmi(1)](/docs/kpod-rmi.1.md) | Removes one or more images |[![...](/docs/play.png)](https://asciinema.org/a/133799)|
|
||||
| [kpod-save(1)](/docs/kpod-save.1.md) | Saves an image to an archive |[![...](/docs/play.png)](https://asciinema.org/a/kp8kOaexEhEa20P1KLZ3L5X4g)|
|
||||
| [kpod-stats(1)](/docs/kpod-stats.1.md) | Display a live stream of one or more containers' resource usage statistics||
|
||||
| [kpod-stop(1)](/docs/kpod-stop.1.md) | Stops one or more running containers ||
|
||||
| [kpod-tag(1)](/docs/kpod-tag.1.md) | Add an additional name to a local image |[![...](/docs/play.png)](https://asciinema.org/a/133803)|
|
||||
| [kpod-umount(1)](/docs/kpod-umount.1.md) | Unmount a working container's root filesystem ||
|
||||
| [kpod-unpause(1)](/docs/kpod-unpause.1.md) | Unpause one or more running containers |[![...](/docs/play.png)](https://asciinema.org/a/141292)|
|
||||
| [kpod-version(1)](/docs/kpod-version.1.md) | Display the version information |[![...](/docs/play.png)](https://asciinema.org/a/mfrn61pjZT9Fc8L4NbfdSqfgu)|
|
||||
| [kpod-wait(1)](/docs/kpod-wait.1.md) | Wait on one or more containers to stop and print their exit codes||
|
||||
|
||||
Note that kpod and its container management and debugging commands have moved to a separate repository, located [here](https://github.com/projectatomic/libpod).
|
||||
|
||||
## Configuration
|
||||
| File | Description |
|
||||
|
@ -80,21 +66,26 @@ It is currently in active development in the Kubernetes community through the [d
|
|||
|
||||
[CRI-O configures OCI Hooks to run when launching a container](./hooks.md)
|
||||
|
||||
## cri-o Usage Transfer
|
||||
## CRI-O Usage Transfer
|
||||
|
||||
[Useful information for ops and dev transfer as it relates to infrastructure that utilizes cri-o](/transfer.md)
|
||||
[Useful information for ops and dev transfer as it relates to infrastructure that utilizes CRI-O](/transfer.md)
|
||||
|
||||
## Communication
|
||||
|
||||
For async communication and long running discussions please use issues and pull requests on the github repo. This will be the best place to discuss design and implementation.
|
||||
|
||||
For sync communication we have an IRC channel #cri-o, on chat.freenode.net, that everyone is welcome to join and chat about development.
|
||||
For sync communication we have an IRC channel #CRI-O, on chat.freenode.net, that everyone is welcome to join and chat about development.
|
||||
|
||||
## Getting started
|
||||
|
||||
### Prerequisites
|
||||
### Runtime dependencies
|
||||
|
||||
Latest version of `runc` is expected to be installed on the system. It is picked up as the default runtime by crio.
|
||||
- runc, Clear Containers runtime, or any other OCI compatible runtime
|
||||
- socat
|
||||
- iproute
|
||||
- iptables
|
||||
|
||||
Latest version of `runc` is expected to be installed on the system. It is picked up as the default runtime by CRI-O.
|
||||
|
||||
### Build and Run Dependencies
|
||||
|
||||
|
@ -111,6 +102,7 @@ yum install -y \
|
|||
glibc-devel \
|
||||
glibc-static \
|
||||
go \
|
||||
golang-github-cpuguy83-go-md2man \
|
||||
gpgme-devel \
|
||||
libassuan-devel \
|
||||
libgpg-error-devel \
|
||||
|
@ -138,6 +130,7 @@ apt-get install -y \
|
|||
libseccomp-dev \
|
||||
libselinux1-dev \
|
||||
pkg-config \
|
||||
go-md2man \
|
||||
runc \
|
||||
skopeo-containers
|
||||
```
|
||||
|
@ -165,7 +158,7 @@ apt-get install -y \
|
|||
|
||||
### Get Source Code
|
||||
|
||||
As with other Go projects, cri-o must be cloned into a directory structure like:
|
||||
As with other Go projects, CRI-O must be cloned into a directory structure like:
|
||||
|
||||
```
|
||||
GOPATH
|
||||
|
@ -199,7 +192,7 @@ make
|
|||
sudo make install
|
||||
```
|
||||
|
||||
Otherwise, if you do not want to build `cri-o` with seccomp support you can add `BUILDTAGS=""` when running make.
|
||||
Otherwise, if you do not want to build `CRI-O` with seccomp support you can add `BUILDTAGS=""` when running make.
|
||||
|
||||
```bash
|
||||
make BUILDTAGS=""
|
||||
|
@ -208,7 +201,7 @@ sudo make install
|
|||
|
||||
#### Build Tags
|
||||
|
||||
`cri-o` supports optional build tags for compiling support of various features.
|
||||
`CRI-O` supports optional build tags for compiling support of various features.
|
||||
To add build tags to the make option the `BUILDTAGS` variable must be set.
|
||||
|
||||
```bash
|
||||
|
@ -234,15 +227,15 @@ your system.
|
|||
|
||||
### Running with kubernetes
|
||||
|
||||
You can run a local version of kubernetes with cri-o using `local-up-cluster.sh`:
|
||||
You can run a local version of kubernetes with CRI-O using `local-up-cluster.sh`:
|
||||
|
||||
1. Clone the [kubernetes repository](https://github.com/kubernetes/kubernetes)
|
||||
1. Start the cri-o daemon (`crio`)
|
||||
1. Start the CRI-O daemon (`crio`)
|
||||
1. From the kubernetes project directory, run:
|
||||
```shell
|
||||
CGROUP_DRIVER=systemd \
|
||||
CONTAINER_RUNTIME=remote \
|
||||
CONTAINER_RUNTIME_ENDPOINT='/var/run/crio.sock --runtime-request-timeout=15m' \
|
||||
CONTAINER_RUNTIME_ENDPOINT='/var/run/crio/crio.sock --runtime-request-timeout=15m' \
|
||||
./hack/local-up-cluster.sh
|
||||
```
|
||||
|
||||
|
@ -256,5 +249,4 @@ To run a full cluster, see [the instructions](kubernetes.md).
|
|||
1. Support for log management, networking integration using CNI, pluggable image/storage management (done)
|
||||
1. Support for exec/attach (done)
|
||||
1. Target fully automated kubernetes testing without failures [e2e status](https://github.com/kubernetes-incubator/cri-o/issues/533)
|
||||
1. Release 1.0
|
||||
1. Track upstream k8s releases
|
||||
|
|
|
@ -28,8 +28,7 @@ storage_driver = "{{ .Storage }}"
|
|||
storage_option = [
|
||||
{{ range $opt := .StorageOptions }}{{ printf "\t%q,\n" $opt }}{{ end }}]
|
||||
|
||||
# The "crio.api" table contains settings for the kubelet/gRPC
|
||||
# interface (which is also used by crioctl).
|
||||
# The "crio.api" table contains settings for the kubelet/gRPC interface.
|
||||
[crio.api]
|
||||
|
||||
# listen is the path to the AF_LOCAL socket on which crio will listen.
|
||||
|
@ -108,9 +107,16 @@ cgroup_manager = "{{ .CgroupManager }}"
|
|||
# hooks_dir_path is the oci hooks directory for automatically executed hooks
|
||||
hooks_dir_path = "{{ .HooksDirPath }}"
|
||||
|
||||
# default_mounts is the mounts list to be mounted for the container when created
|
||||
default_mounts = [
|
||||
{{ range $mount := .DefaultMounts }}{{ printf "\t%q, \n" $mount }}{{ end }}]
|
||||
|
||||
# pids_limit is the number of processes allowed in a container
|
||||
pids_limit = {{ .PidsLimit }}
|
||||
|
||||
# enable using a shared PID namespace for containers in a pod
|
||||
enable_shared_pid_namespace = {{ .EnableSharedPIDNamespace }}
|
||||
|
||||
# log_size_max is the max limit for the container log size in bytes.
|
||||
# Negative values indicate that no limit is imposed.
|
||||
log_size_max = {{ .LogSizeMax }}
|
||||
|
|
|
@ -8,12 +8,15 @@ import (
|
|||
_ "net/http/pprof"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containers/storage/pkg/reexec"
|
||||
"github.com/kubernetes-incubator/cri-o/libkpod"
|
||||
"github.com/kubernetes-incubator/cri-o/lib"
|
||||
"github.com/kubernetes-incubator/cri-o/server"
|
||||
"github.com/kubernetes-incubator/cri-o/version"
|
||||
"github.com/opencontainers/selinux/go-selinux"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/soheilhy/cmux"
|
||||
|
@ -23,19 +26,15 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
// This is populated by the Makefile from the VERSION file
|
||||
// in the repository
|
||||
var version = ""
|
||||
|
||||
// gitCommit is the commit that the binary is being built from.
|
||||
// It will be populated by the Makefile.
|
||||
var gitCommit = ""
|
||||
|
||||
func validateConfig(config *server.Config) error {
|
||||
switch config.ImageVolumes {
|
||||
case libkpod.ImageVolumesMkdir:
|
||||
case libkpod.ImageVolumesIgnore:
|
||||
case libkpod.ImageVolumesBind:
|
||||
case lib.ImageVolumesMkdir:
|
||||
case lib.ImageVolumesIgnore:
|
||||
case lib.ImageVolumesBind:
|
||||
default:
|
||||
return fmt.Errorf("Unrecognized image volume type specified")
|
||||
|
||||
|
@ -127,9 +126,15 @@ func mergeConfig(config *server.Config, ctx *cli.Context) error {
|
|||
if ctx.GlobalIsSet("hooks-dir-path") {
|
||||
config.HooksDirPath = ctx.GlobalString("hooks-dir-path")
|
||||
}
|
||||
if ctx.GlobalIsSet("default-mounts") {
|
||||
config.DefaultMounts = ctx.GlobalStringSlice("default-mounts")
|
||||
}
|
||||
if ctx.GlobalIsSet("pids-limit") {
|
||||
config.PidsLimit = ctx.GlobalInt64("pids-limit")
|
||||
}
|
||||
if ctx.GlobalIsSet("enable-shared-pid-namespace") {
|
||||
config.EnableSharedPIDNamespace = ctx.GlobalBool("enable-shared-pid-namespace")
|
||||
}
|
||||
if ctx.GlobalIsSet("log-size-max") {
|
||||
config.LogSizeMax = ctx.GlobalInt64("log-size-max")
|
||||
}
|
||||
|
@ -140,7 +145,7 @@ func mergeConfig(config *server.Config, ctx *cli.Context) error {
|
|||
config.PluginDir = ctx.GlobalString("cni-plugin-dir")
|
||||
}
|
||||
if ctx.GlobalIsSet("image-volumes") {
|
||||
config.ImageVolumes = libkpod.ImageVolumesType(ctx.GlobalString("image-volumes"))
|
||||
config.ImageVolumes = lib.ImageVolumesType(ctx.GlobalString("image-volumes"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -161,8 +166,7 @@ func catchShutdown(gserver *grpc.Server, sserver *server.Server, hserver *http.S
|
|||
*signalled = true
|
||||
gserver.GracefulStop()
|
||||
hserver.Shutdown(context.Background())
|
||||
// TODO(runcom): enable this after https://github.com/kubernetes/kubernetes/pull/51377
|
||||
//sserver.StopStreamServer()
|
||||
sserver.StopStreamServer()
|
||||
sserver.StopExitMonitor()
|
||||
if err := sserver.Shutdown(); err != nil {
|
||||
logrus.Warnf("error shutting down main service %v", err)
|
||||
|
@ -179,9 +183,7 @@ func main() {
|
|||
app := cli.NewApp()
|
||||
|
||||
var v []string
|
||||
if version != "" {
|
||||
v = append(v, version)
|
||||
}
|
||||
v = append(v, version.Version)
|
||||
if gitCommit != "" {
|
||||
v = append(v, fmt.Sprintf("commit: %s", gitCommit))
|
||||
}
|
||||
|
@ -295,12 +297,16 @@ func main() {
|
|||
},
|
||||
cli.Int64Flag{
|
||||
Name: "pids-limit",
|
||||
Value: libkpod.DefaultPidsLimit,
|
||||
Value: lib.DefaultPidsLimit,
|
||||
Usage: "maximum number of processes allowed in a container",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "enable-shared-pid-namespace",
|
||||
Usage: "enable using a shared PID namespace for containers in a pod",
|
||||
},
|
||||
cli.Int64Flag{
|
||||
Name: "log-size-max",
|
||||
Value: libkpod.DefaultLogSizeMax,
|
||||
Value: lib.DefaultLogSizeMax,
|
||||
Usage: "maximum log size in bytes for a container",
|
||||
},
|
||||
cli.StringFlag{
|
||||
|
@ -313,13 +319,18 @@ func main() {
|
|||
},
|
||||
cli.StringFlag{
|
||||
Name: "image-volumes",
|
||||
Value: string(libkpod.ImageVolumesMkdir),
|
||||
Value: string(lib.ImageVolumesMkdir),
|
||||
Usage: "image volume handling ('mkdir', 'bind', or 'ignore')",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "hooks-dir-path",
|
||||
Usage: "set the OCI hooks directory path",
|
||||
Value: libkpod.DefaultHooksDirPath,
|
||||
Value: lib.DefaultHooksDirPath,
|
||||
Hidden: true,
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "default-mounts",
|
||||
Usage: "add one or more default mount paths in the form host:container",
|
||||
Hidden: true,
|
||||
},
|
||||
cli.BoolFlag{
|
||||
|
@ -405,6 +416,16 @@ func main() {
|
|||
}()
|
||||
}
|
||||
|
||||
args := c.Args()
|
||||
if len(args) > 0 {
|
||||
for _, command := range app.Commands {
|
||||
if args[0] == command.Name {
|
||||
break
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("command %q not supported", args[0])
|
||||
}
|
||||
|
||||
config := c.App.Metadata["config"].(*server.Config)
|
||||
|
||||
if !config.SELinux {
|
||||
|
@ -416,6 +437,10 @@ func main() {
|
|||
return fmt.Errorf("invalid --runtime value %q", err)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(config.Listen), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove the socket if it already exists
|
||||
if _, err := os.Stat(config.Listen); err == nil {
|
||||
if err := os.Remove(config.Listen); err != nil {
|
||||
|
@ -467,7 +492,8 @@ func main() {
|
|||
|
||||
infoMux := service.GetInfoMux()
|
||||
srv := &http.Server{
|
||||
Handler: infoMux,
|
||||
Handler: infoMux,
|
||||
ReadTimeout: 5 * time.Second,
|
||||
}
|
||||
|
||||
graceful := false
|
||||
|
@ -483,26 +509,23 @@ func main() {
|
|||
if graceful && strings.Contains(strings.ToLower(err.Error()), "use of closed network connection") {
|
||||
err = nil
|
||||
} else {
|
||||
logrus.Errorf("Failed to serve grpc grpc request: %v", err)
|
||||
logrus.Errorf("Failed to serve grpc request: %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// TODO(runcom): enable this after https://github.com/kubernetes/kubernetes/pull/51377
|
||||
//streamServerCloseCh := service.StreamingServerCloseChan()
|
||||
streamServerCloseCh := service.StreamingServerCloseChan()
|
||||
serverExitMonitorCh := service.ExitMonitorCloseChan()
|
||||
select {
|
||||
// TODO(runcom): enable this after https://github.com/kubernetes/kubernetes/pull/51377
|
||||
//case <-streamServerCloseCh:
|
||||
case <-streamServerCloseCh:
|
||||
case <-serverExitMonitorCh:
|
||||
case <-serverCloseCh:
|
||||
}
|
||||
|
||||
service.Shutdown()
|
||||
|
||||
// TODO(runcom): enable this after https://github.com/kubernetes/kubernetes/pull/51377
|
||||
//<-streamServerCloseCh
|
||||
//logrus.Debug("closed stream server")
|
||||
<-streamServerCloseCh
|
||||
logrus.Debug("closed stream server")
|
||||
<-serverExitMonitorCh
|
||||
logrus.Debug("closed exit monitor")
|
||||
<-serverCloseCh
|
||||
|
|
|
@ -1,656 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/kubernetes-incubator/cri-o/client"
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/net/context"
|
||||
remocommandconsts "k8s.io/apimachinery/pkg/util/remotecommand"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
var containerCommand = cli.Command{
|
||||
Name: "container",
|
||||
Aliases: []string{"ctr"},
|
||||
Subcommands: []cli.Command{
|
||||
createContainerCommand,
|
||||
inspectContainerCommand,
|
||||
startContainerCommand,
|
||||
stopContainerCommand,
|
||||
removeContainerCommand,
|
||||
containerStatusCommand,
|
||||
listContainersCommand,
|
||||
execSyncCommand,
|
||||
execCommand,
|
||||
},
|
||||
}
|
||||
|
||||
type createOptions struct {
|
||||
// configPath is path to the config for container
|
||||
configPath string
|
||||
// name sets the container name
|
||||
name string
|
||||
// podID of the container
|
||||
podID string
|
||||
// labels for the container
|
||||
labels map[string]string
|
||||
}
|
||||
|
||||
var createContainerCommand = cli.Command{
|
||||
Name: "create",
|
||||
Usage: "create a container",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "pod",
|
||||
Usage: "the id of the pod sandbox to which the container belongs",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "config",
|
||||
Value: "config.json",
|
||||
Usage: "the path of a container config file",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "",
|
||||
Usage: "the name of the container",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "label",
|
||||
Usage: "add key=value labels to the container",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
if !context.IsSet("pod") {
|
||||
return fmt.Errorf("Please specify the id of the pod sandbox to which the container belongs via the --pod option")
|
||||
}
|
||||
|
||||
opts := createOptions{
|
||||
configPath: context.String("config"),
|
||||
name: context.String("name"),
|
||||
podID: context.String("pod"),
|
||||
labels: make(map[string]string),
|
||||
}
|
||||
|
||||
for _, l := range context.StringSlice("label") {
|
||||
pair := strings.Split(l, "=")
|
||||
if len(pair) != 2 {
|
||||
return fmt.Errorf("incorrectly specified label: %v", l)
|
||||
}
|
||||
opts.labels[pair[0]] = pair[1]
|
||||
}
|
||||
|
||||
// Test RuntimeServiceClient.CreateContainer
|
||||
err = CreateContainer(client, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Creating container failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var startContainerCommand = cli.Command{
|
||||
Name: "start",
|
||||
Usage: "start a container",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the container",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = StartContainer(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Starting the container failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var stopContainerCommand = cli.Command{
|
||||
Name: "stop",
|
||||
Usage: "stop a container",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the container",
|
||||
},
|
||||
cli.Int64Flag{
|
||||
Name: "timeout",
|
||||
Value: 10,
|
||||
Usage: "seconds to wait to kill the container after a graceful stop is requested",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = StopContainer(client, context.String("id"), context.Int64("timeout"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Stopping the container failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var removeContainerCommand = cli.Command{
|
||||
Name: "remove",
|
||||
Usage: "remove a container",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the container",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = RemoveContainer(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Removing the container failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var containerStatusCommand = cli.Command{
|
||||
Name: "status",
|
||||
Usage: "get the status of a container",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the container",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = ContainerStatus(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Getting the status of the container failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var execSyncCommand = cli.Command{
|
||||
Name: "execsync",
|
||||
Usage: "exec a command synchronously in a container",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the container",
|
||||
},
|
||||
cli.Int64Flag{
|
||||
Name: "timeout",
|
||||
Value: 0,
|
||||
Usage: "timeout for the command",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = ExecSync(client, context.String("id"), context.Args(), context.Int64("timeout"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("execing command in container failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var execCommand = cli.Command{
|
||||
Name: "exec",
|
||||
Usage: "prepare a streaming endpoint to execute a command in the container",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the container",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "tty",
|
||||
Usage: "whether to use tty",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "stdin",
|
||||
Usage: "whether to stream to stdin",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "url",
|
||||
Usage: "do not exec command, just prepare streaming endpoint",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = Exec(client, context.String("id"), context.Bool("tty"), context.Bool("stdin"), context.Bool("url"), context.Args())
|
||||
if err != nil {
|
||||
return fmt.Errorf("execing command in container failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
type listOptions struct {
|
||||
// id of the container
|
||||
id string
|
||||
// podID of the container
|
||||
podID string
|
||||
// state of the container
|
||||
state string
|
||||
// quiet is for listing just container IDs
|
||||
quiet bool
|
||||
// labels are selectors for the container
|
||||
labels map[string]string
|
||||
}
|
||||
|
||||
var listContainersCommand = cli.Command{
|
||||
Name: "list",
|
||||
Usage: "list containers",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "quiet",
|
||||
Usage: "list only container IDs",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "filter by container id",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "pod",
|
||||
Value: "",
|
||||
Usage: "filter by container pod id",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "state",
|
||||
Value: "",
|
||||
Usage: "filter by container state",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "label",
|
||||
Usage: "filter by key=value label",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
opts := listOptions{
|
||||
id: context.String("id"),
|
||||
podID: context.String("pod"),
|
||||
state: context.String("state"),
|
||||
quiet: context.Bool("quiet"),
|
||||
labels: make(map[string]string),
|
||||
}
|
||||
|
||||
for _, l := range context.StringSlice("label") {
|
||||
pair := strings.Split(l, "=")
|
||||
if len(pair) != 2 {
|
||||
return fmt.Errorf("incorrectly specified label: %v", l)
|
||||
}
|
||||
opts.labels[pair[0]] = pair[1]
|
||||
}
|
||||
|
||||
err = ListContainers(client, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("listing containers failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// CreateContainer sends a CreateContainerRequest to the server, and parses
|
||||
// the returned CreateContainerResponse.
|
||||
func CreateContainer(client pb.RuntimeServiceClient, opts createOptions) error {
|
||||
config, err := loadContainerConfig(opts.configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Override the name by the one specified through CLI
|
||||
if opts.name != "" {
|
||||
config.Metadata.Name = opts.name
|
||||
}
|
||||
|
||||
for k, v := range opts.labels {
|
||||
config.Labels[k] = v
|
||||
}
|
||||
|
||||
r, err := client.CreateContainer(context.Background(), &pb.CreateContainerRequest{
|
||||
PodSandboxId: opts.podID,
|
||||
Config: config,
|
||||
// TODO(runcom): this is missing PodSandboxConfig!!!
|
||||
// we should/could find a way to retrieve it from the fs and set it here
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(r.ContainerId)
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartContainer sends a StartContainerRequest to the server, and parses
|
||||
// the returned StartContainerResponse.
|
||||
func StartContainer(client pb.RuntimeServiceClient, ID string) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
_, err := client.StartContainer(context.Background(), &pb.StartContainerRequest{
|
||||
ContainerId: ID,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// StopContainer sends a StopContainerRequest to the server, and parses
|
||||
// the returned StopContainerResponse.
|
||||
func StopContainer(client pb.RuntimeServiceClient, ID string, timeout int64) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
_, err := client.StopContainer(context.Background(), &pb.StopContainerRequest{
|
||||
ContainerId: ID,
|
||||
Timeout: timeout,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveContainer sends a RemoveContainerRequest to the server, and parses
|
||||
// the returned RemoveContainerResponse.
|
||||
func RemoveContainer(client pb.RuntimeServiceClient, ID string) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
_, err := client.RemoveContainer(context.Background(), &pb.RemoveContainerRequest{
|
||||
ContainerId: ID,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ContainerStatus sends a ContainerStatusRequest to the server, and parses
|
||||
// the returned ContainerStatusResponse.
|
||||
func ContainerStatus(client pb.RuntimeServiceClient, ID string) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
r, err := client.ContainerStatus(context.Background(), &pb.ContainerStatusRequest{
|
||||
ContainerId: ID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("ID: %s\n", r.Status.Id)
|
||||
if r.Status.Metadata != nil {
|
||||
if r.Status.Metadata.Name != "" {
|
||||
fmt.Printf("Name: %s\n", r.Status.Metadata.Name)
|
||||
}
|
||||
fmt.Printf("Attempt: %v\n", r.Status.Metadata.Attempt)
|
||||
}
|
||||
// TODO(mzylowski): print it prettier
|
||||
fmt.Printf("Status: %s\n", r.Status.State)
|
||||
ctm := time.Unix(0, r.Status.CreatedAt)
|
||||
fmt.Printf("Created: %v\n", ctm)
|
||||
stm := time.Unix(0, r.Status.StartedAt)
|
||||
fmt.Printf("Started: %v\n", stm)
|
||||
ftm := time.Unix(0, r.Status.FinishedAt)
|
||||
fmt.Printf("Finished: %v\n", ftm)
|
||||
fmt.Printf("Exit Code: %v\n", r.Status.ExitCode)
|
||||
fmt.Printf("Reason: %v\n", r.Status.Reason)
|
||||
if r.Status.Image != nil {
|
||||
fmt.Printf("Image: %v\n", r.Status.Image.Image)
|
||||
}
|
||||
//
|
||||
// TODO: https://github.com/kubernetes-incubator/cri-o/issues/531
|
||||
//
|
||||
//fmt.Printf("ImageRef: %v\n", r.Status.ImageRef)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExecSync sends an ExecSyncRequest to the server, and parses
|
||||
// the returned ExecSyncResponse.
|
||||
func ExecSync(client pb.RuntimeServiceClient, ID string, cmd []string, timeout int64) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
r, err := client.ExecSync(context.Background(), &pb.ExecSyncRequest{
|
||||
ContainerId: ID,
|
||||
Cmd: cmd,
|
||||
Timeout: timeout,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Stdout:")
|
||||
fmt.Println(string(r.Stdout))
|
||||
fmt.Println("Stderr:")
|
||||
fmt.Println(string(r.Stderr))
|
||||
fmt.Printf("Exit code: %v\n", r.ExitCode)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Exec sends an ExecRequest to the server, and parses
|
||||
// the returned ExecResponse.
|
||||
func Exec(client pb.RuntimeServiceClient, ID string, tty bool, stdin bool, urlOnly bool, cmd []string) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
r, err := client.Exec(context.Background(), &pb.ExecRequest{
|
||||
ContainerId: ID,
|
||||
Cmd: cmd,
|
||||
Tty: tty,
|
||||
Stdin: stdin,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if urlOnly {
|
||||
fmt.Println("URL:")
|
||||
fmt.Println(r.Url)
|
||||
return nil
|
||||
}
|
||||
|
||||
execURL, err := url.Parse(r.Url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
streamExec, err := remotecommand.NewExecutor(&restclient.Config{}, "GET", execURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
options := remotecommand.StreamOptions{
|
||||
SupportedProtocols: remocommandconsts.SupportedStreamingProtocols,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
Tty: tty,
|
||||
}
|
||||
|
||||
if stdin {
|
||||
options.Stdin = os.Stdin
|
||||
}
|
||||
|
||||
return streamExec.Stream(options)
|
||||
}
|
||||
|
||||
// ListContainers sends a ListContainerRequest to the server, and parses
|
||||
// the returned ListContainerResponse.
|
||||
func ListContainers(client pb.RuntimeServiceClient, opts listOptions) error {
|
||||
filter := &pb.ContainerFilter{}
|
||||
if opts.id != "" {
|
||||
filter.Id = opts.id
|
||||
}
|
||||
if opts.podID != "" {
|
||||
filter.PodSandboxId = opts.podID
|
||||
}
|
||||
if opts.state != "" {
|
||||
st := &pb.ContainerStateValue{}
|
||||
st.State = pb.ContainerState_CONTAINER_UNKNOWN
|
||||
switch opts.state {
|
||||
case "created":
|
||||
st.State = pb.ContainerState_CONTAINER_CREATED
|
||||
filter.State = st
|
||||
case "running":
|
||||
st.State = pb.ContainerState_CONTAINER_RUNNING
|
||||
filter.State = st
|
||||
case "stopped":
|
||||
st.State = pb.ContainerState_CONTAINER_EXITED
|
||||
filter.State = st
|
||||
default:
|
||||
log.Fatalf("--state should be one of created, running or stopped")
|
||||
}
|
||||
}
|
||||
if opts.labels != nil {
|
||||
filter.LabelSelector = opts.labels
|
||||
}
|
||||
r, err := client.ListContainers(context.Background(), &pb.ListContainersRequest{
|
||||
Filter: filter,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, c := range r.GetContainers() {
|
||||
if opts.quiet {
|
||||
fmt.Println(c.Id)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("ID: %s\n", c.Id)
|
||||
fmt.Printf("Pod: %s\n", c.PodSandboxId)
|
||||
if c.Metadata != nil {
|
||||
if c.Metadata.Name != "" {
|
||||
fmt.Printf("Name: %s\n", c.Metadata.Name)
|
||||
}
|
||||
fmt.Printf("Attempt: %v\n", c.Metadata.Attempt)
|
||||
}
|
||||
fmt.Printf("Status: %s\n", c.State)
|
||||
if c.Image != nil {
|
||||
fmt.Printf("Image: %s\n", c.Image.Image)
|
||||
}
|
||||
ctm := time.Unix(0, c.CreatedAt)
|
||||
fmt.Printf("Created: %v\n", ctm)
|
||||
if c.Labels != nil {
|
||||
fmt.Println("Labels:")
|
||||
for _, k := range getSortedKeys(c.Labels) {
|
||||
fmt.Printf("\t%s -> %s\n", k, c.Labels[k])
|
||||
}
|
||||
}
|
||||
if c.Annotations != nil {
|
||||
fmt.Println("Annotations:")
|
||||
for _, k := range getSortedKeys(c.Annotations) {
|
||||
fmt.Printf("\t%s -> %s\n", k, c.Annotations[k])
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var inspectContainerCommand = cli.Command{
|
||||
Name: "inspect",
|
||||
Usage: "get container info from crio daemon",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the container",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
ID := context.String("id")
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
c, err := client.New(context.GlobalString("connect"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cInfo, err := c.ContainerInfo(ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonBytes, err := json.MarshalIndent(cInfo, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(jsonBytes))
|
||||
return nil
|
||||
},
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/net/context"
|
||||
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
var imageCommand = cli.Command{
|
||||
Name: "image",
|
||||
Subcommands: []cli.Command{
|
||||
pullImageCommand,
|
||||
listImageCommand,
|
||||
imageStatusCommand,
|
||||
removeImageCommand,
|
||||
},
|
||||
}
|
||||
|
||||
var pullImageCommand = cli.Command{
|
||||
Name: "pull",
|
||||
Usage: "pull an image",
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewImageServiceClient(conn)
|
||||
|
||||
_, err = PullImage(client, context.Args().Get(0))
|
||||
if err != nil {
|
||||
return fmt.Errorf("pulling image failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var listImageCommand = cli.Command{
|
||||
Name: "list",
|
||||
Usage: "list images",
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "quiet",
|
||||
Usage: "list only image IDs",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewImageServiceClient(conn)
|
||||
|
||||
r, err := ListImages(client, context.Args().Get(0))
|
||||
if err != nil {
|
||||
return fmt.Errorf("listing images failed: %v", err)
|
||||
}
|
||||
quiet := context.Bool("quiet")
|
||||
for _, image := range r.Images {
|
||||
if quiet {
|
||||
fmt.Printf("%s\n", image.Id)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("ID: %s\n", image.Id)
|
||||
for _, tag := range image.RepoTags {
|
||||
fmt.Printf("Tag: %s\n", tag)
|
||||
}
|
||||
for _, digest := range image.RepoDigests {
|
||||
fmt.Printf("Digest: %s\n", digest)
|
||||
}
|
||||
if image.Size_ != 0 {
|
||||
fmt.Printf("Size: %d\n", image.Size_)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var imageStatusCommand = cli.Command{
|
||||
Name: "status",
|
||||
Usage: "return the status of an image",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Usage: "id of the image",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewImageServiceClient(conn)
|
||||
|
||||
r, err := ImageStatus(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("image status request failed: %v", err)
|
||||
}
|
||||
image := r.Image
|
||||
if image == nil {
|
||||
return fmt.Errorf("no such image present")
|
||||
}
|
||||
fmt.Printf("ID: %s\n", image.Id)
|
||||
for _, tag := range image.RepoTags {
|
||||
fmt.Printf("Tag: %s\n", tag)
|
||||
}
|
||||
for _, digest := range image.RepoDigests {
|
||||
fmt.Printf("Digest: %s\n", digest)
|
||||
}
|
||||
fmt.Printf("Size: %d\n", image.Size_)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
var removeImageCommand = cli.Command{
|
||||
Name: "remove",
|
||||
Usage: "remove an image",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the image",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewImageServiceClient(conn)
|
||||
|
||||
_, err = RemoveImage(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("removing the image failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// PullImage sends a PullImageRequest to the server, and parses
|
||||
// the returned PullImageResponse.
|
||||
func PullImage(client pb.ImageServiceClient, image string) (*pb.PullImageResponse, error) {
|
||||
return client.PullImage(context.Background(), &pb.PullImageRequest{Image: &pb.ImageSpec{Image: image}})
|
||||
}
|
||||
|
||||
// ListImages sends a ListImagesRequest to the server, and parses
|
||||
// the returned ListImagesResponse.
|
||||
func ListImages(client pb.ImageServiceClient, image string) (*pb.ListImagesResponse, error) {
|
||||
return client.ListImages(context.Background(), &pb.ListImagesRequest{Filter: &pb.ImageFilter{Image: &pb.ImageSpec{Image: image}}})
|
||||
}
|
||||
|
||||
// ImageStatus sends an ImageStatusRequest to the server, and parses
|
||||
// the returned ImageStatusResponse.
|
||||
func ImageStatus(client pb.ImageServiceClient, image string) (*pb.ImageStatusResponse, error) {
|
||||
return client.ImageStatus(context.Background(), &pb.ImageStatusRequest{Image: &pb.ImageSpec{Image: image}})
|
||||
}
|
||||
|
||||
// RemoveImage sends a RemoveImageRequest to the server, and parses
|
||||
// the returned RemoveImageResponse.
|
||||
func RemoveImage(client pb.ImageServiceClient, image string) (*pb.RemoveImageResponse, error) {
|
||||
if image == "" {
|
||||
return nil, fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
return client.RemoveImage(context.Background(), &pb.RemoveImageRequest{Image: &pb.ImageSpec{Image: image}})
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/kubernetes-incubator/cri-o/client"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var infoCommand = cli.Command{
|
||||
Name: "info",
|
||||
Usage: "get crio daemon info",
|
||||
Action: func(context *cli.Context) error {
|
||||
c, err := client.New(context.GlobalString("connect"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
di, err := c.DaemonInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonBytes, err := json.MarshalIndent(di, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(jsonBytes))
|
||||
return nil
|
||||
},
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
"google.golang.org/grpc"
|
||||
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
// This is populated by the Makefile from the VERSION file
|
||||
// in the repository
|
||||
var version = ""
|
||||
|
||||
// gitCommit is the commit that the binary is being built from.
|
||||
// It will be populated by the Makefile.
|
||||
var gitCommit = ""
|
||||
|
||||
func getClientConnection(context *cli.Context) (*grpc.ClientConn, error) {
|
||||
conn, err := grpc.Dial(context.GlobalString("connect"), grpc.WithInsecure(), grpc.WithTimeout(context.GlobalDuration("timeout")),
|
||||
grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
|
||||
return net.DialTimeout("unix", addr, timeout)
|
||||
}))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func openFile(path string) (*os.File, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("config at %s not found", path)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func loadPodSandboxConfig(path string) (*pb.PodSandboxConfig, error) {
|
||||
f, err := openFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var config pb.PodSandboxConfig
|
||||
if err := json.NewDecoder(f).Decode(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
func loadContainerConfig(path string) (*pb.ContainerConfig, error) {
|
||||
f, err := openFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var config pb.ContainerConfig
|
||||
if err := json.NewDecoder(f).Decode(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
var v []string
|
||||
if version != "" {
|
||||
v = append(v, version)
|
||||
}
|
||||
if gitCommit != "" {
|
||||
v = append(v, fmt.Sprintf("commit: %s", gitCommit))
|
||||
}
|
||||
|
||||
app.Name = "crioctl"
|
||||
app.Usage = "client for crio"
|
||||
app.Version = strings.Join(v, "\n")
|
||||
|
||||
app.Commands = []cli.Command{
|
||||
podSandboxCommand,
|
||||
containerCommand,
|
||||
runtimeVersionCommand,
|
||||
imageCommand,
|
||||
infoCommand,
|
||||
}
|
||||
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "connect",
|
||||
Value: "/var/run/crio.sock",
|
||||
Usage: "Socket to connect to",
|
||||
},
|
||||
cli.DurationFlag{
|
||||
Name: "timeout",
|
||||
Value: 10 * time.Second,
|
||||
Usage: "Timeout of connecting to server",
|
||||
},
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
}
|
|
@ -1,386 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/net/context"
|
||||
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
var podSandboxCommand = cli.Command{
|
||||
Name: "pod",
|
||||
Subcommands: []cli.Command{
|
||||
runPodSandboxCommand,
|
||||
stopPodSandboxCommand,
|
||||
removePodSandboxCommand,
|
||||
podSandboxStatusCommand,
|
||||
listPodSandboxCommand,
|
||||
},
|
||||
}
|
||||
|
||||
var runPodSandboxCommand = cli.Command{
|
||||
Name: "run",
|
||||
Usage: "run a pod",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "config",
|
||||
Value: "",
|
||||
Usage: "the path of a pod sandbox config file",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "",
|
||||
Usage: "the name of the pod sandbox",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "label",
|
||||
Usage: "add key=value labels to the container",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
opts := createOptions{
|
||||
configPath: context.String("config"),
|
||||
name: context.String("name"),
|
||||
labels: make(map[string]string),
|
||||
}
|
||||
|
||||
for _, l := range context.StringSlice("label") {
|
||||
pair := strings.Split(l, "=")
|
||||
if len(pair) != 2 {
|
||||
return fmt.Errorf("incorrectly specified label: %v", l)
|
||||
}
|
||||
opts.labels[pair[0]] = pair[1]
|
||||
}
|
||||
|
||||
// Test RuntimeServiceClient.RunPodSandbox
|
||||
err = RunPodSandbox(client, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Creating the pod sandbox failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var stopPodSandboxCommand = cli.Command{
|
||||
Name: "stop",
|
||||
Usage: "stop a pod sandbox",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the pod sandbox",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = StopPodSandbox(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("stopping the pod sandbox failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var removePodSandboxCommand = cli.Command{
|
||||
Name: "remove",
|
||||
Usage: "remove a pod sandbox",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the pod sandbox",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = RemovePodSandbox(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("removing the pod sandbox failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var podSandboxStatusCommand = cli.Command{
|
||||
Name: "status",
|
||||
Usage: "return the status of a pod",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "id of the pod",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
err = PodSandboxStatus(client, context.String("id"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting the pod sandbox status failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var listPodSandboxCommand = cli.Command{
|
||||
Name: "list",
|
||||
Usage: "list pod sandboxes",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "id",
|
||||
Value: "",
|
||||
Usage: "filter by pod sandbox id",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "state",
|
||||
Value: "",
|
||||
Usage: "filter by pod sandbox state",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "label",
|
||||
Usage: "filter by key=value label",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "quiet",
|
||||
Usage: "list only pod IDs",
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
opts := listOptions{
|
||||
id: context.String("id"),
|
||||
state: context.String("state"),
|
||||
quiet: context.Bool("quiet"),
|
||||
labels: make(map[string]string),
|
||||
}
|
||||
|
||||
for _, l := range context.StringSlice("label") {
|
||||
pair := strings.Split(l, "=")
|
||||
if len(pair) != 2 {
|
||||
return fmt.Errorf("incorrectly specified label: %v", l)
|
||||
}
|
||||
opts.labels[pair[0]] = pair[1]
|
||||
}
|
||||
|
||||
err = ListPodSandboxes(client, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("listing pod sandboxes failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// RunPodSandbox sends a RunPodSandboxRequest to the server, and parses
|
||||
// the returned RunPodSandboxResponse.
|
||||
func RunPodSandbox(client pb.RuntimeServiceClient, opts createOptions) error {
|
||||
config, err := loadPodSandboxConfig(opts.configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Override the name by the one specified through CLI
|
||||
if opts.name != "" {
|
||||
config.Metadata.Name = opts.name
|
||||
}
|
||||
|
||||
for k, v := range opts.labels {
|
||||
config.Labels[k] = v
|
||||
}
|
||||
|
||||
r, err := client.RunPodSandbox(context.Background(), &pb.RunPodSandboxRequest{Config: config})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(r.PodSandboxId)
|
||||
return nil
|
||||
}
|
||||
|
||||
// StopPodSandbox sends a StopPodSandboxRequest to the server, and parses
|
||||
// the returned StopPodSandboxResponse.
|
||||
func StopPodSandbox(client pb.RuntimeServiceClient, ID string) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
_, err := client.StopPodSandbox(context.Background(), &pb.StopPodSandboxRequest{PodSandboxId: ID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemovePodSandbox sends a RemovePodSandboxRequest to the server, and parses
|
||||
// the returned RemovePodSandboxResponse.
|
||||
func RemovePodSandbox(client pb.RuntimeServiceClient, ID string) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
_, err := client.RemovePodSandbox(context.Background(), &pb.RemovePodSandboxRequest{PodSandboxId: ID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// PodSandboxStatus sends a PodSandboxStatusRequest to the server, and parses
|
||||
// the returned PodSandboxStatusResponse.
|
||||
func PodSandboxStatus(client pb.RuntimeServiceClient, ID string) error {
|
||||
if ID == "" {
|
||||
return fmt.Errorf("ID cannot be empty")
|
||||
}
|
||||
r, err := client.PodSandboxStatus(context.Background(), &pb.PodSandboxStatusRequest{PodSandboxId: ID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("ID: %s\n", r.Status.Id)
|
||||
if r.Status.Metadata != nil {
|
||||
if r.Status.Metadata.Name != "" {
|
||||
fmt.Printf("Name: %s\n", r.Status.Metadata.Name)
|
||||
}
|
||||
if r.Status.Metadata.Uid != "" {
|
||||
fmt.Printf("UID: %s\n", r.Status.Metadata.Uid)
|
||||
}
|
||||
if r.Status.Metadata.Namespace != "" {
|
||||
fmt.Printf("Namespace: %s\n", r.Status.Metadata.Namespace)
|
||||
}
|
||||
fmt.Printf("Attempt: %v\n", r.Status.Metadata.Attempt)
|
||||
}
|
||||
fmt.Printf("Status: %s\n", r.Status.State)
|
||||
ctm := time.Unix(0, r.Status.CreatedAt)
|
||||
fmt.Printf("Created: %v\n", ctm)
|
||||
if r.Status.Network != nil {
|
||||
fmt.Printf("IP Address: %v\n", r.Status.Network.Ip)
|
||||
}
|
||||
if r.Status.Labels != nil {
|
||||
fmt.Println("Labels:")
|
||||
for _, k := range getSortedKeys(r.Status.Labels) {
|
||||
fmt.Printf("\t%s -> %s\n", k, r.Status.Labels[k])
|
||||
}
|
||||
}
|
||||
if r.Status.Annotations != nil {
|
||||
fmt.Println("Annotations:")
|
||||
for _, k := range getSortedKeys(r.Status.Annotations) {
|
||||
fmt.Printf("\t%s -> %s\n", k, r.Status.Annotations[k])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListPodSandboxes sends a ListPodSandboxRequest to the server, and parses
|
||||
// the returned ListPodSandboxResponse.
|
||||
func ListPodSandboxes(client pb.RuntimeServiceClient, opts listOptions) error {
|
||||
filter := &pb.PodSandboxFilter{}
|
||||
if opts.id != "" {
|
||||
filter.Id = opts.id
|
||||
}
|
||||
if opts.state != "" {
|
||||
st := &pb.PodSandboxStateValue{}
|
||||
st.State = pb.PodSandboxState_SANDBOX_NOTREADY
|
||||
switch opts.state {
|
||||
case "ready":
|
||||
st.State = pb.PodSandboxState_SANDBOX_READY
|
||||
filter.State = st
|
||||
case "notready":
|
||||
st.State = pb.PodSandboxState_SANDBOX_NOTREADY
|
||||
filter.State = st
|
||||
default:
|
||||
log.Fatalf("--state should be ready or notready")
|
||||
}
|
||||
}
|
||||
if opts.labels != nil {
|
||||
filter.LabelSelector = opts.labels
|
||||
}
|
||||
r, err := client.ListPodSandbox(context.Background(), &pb.ListPodSandboxRequest{
|
||||
Filter: filter,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, pod := range r.Items {
|
||||
if opts.quiet {
|
||||
fmt.Println(pod.Id)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("ID: %s\n", pod.Id)
|
||||
if pod.Metadata != nil {
|
||||
if pod.Metadata.Name != "" {
|
||||
fmt.Printf("Name: %s\n", pod.Metadata.Name)
|
||||
}
|
||||
if pod.Metadata.Uid != "" {
|
||||
fmt.Printf("UID: %s\n", pod.Metadata.Uid)
|
||||
}
|
||||
if pod.Metadata.Namespace != "" {
|
||||
fmt.Printf("Namespace: %s\n", pod.Metadata.Namespace)
|
||||
}
|
||||
fmt.Printf("Attempt: %v\n", pod.Metadata.Attempt)
|
||||
}
|
||||
fmt.Printf("Status: %s\n", pod.State)
|
||||
ctm := time.Unix(0, pod.CreatedAt)
|
||||
fmt.Printf("Created: %v\n", ctm)
|
||||
if pod.Labels != nil {
|
||||
fmt.Println("Labels:")
|
||||
for _, k := range getSortedKeys(pod.Labels) {
|
||||
fmt.Printf("\t%s -> %s\n", k, pod.Labels[k])
|
||||
}
|
||||
}
|
||||
if pod.Annotations != nil {
|
||||
fmt.Println("Annotations:")
|
||||
for _, k := range getSortedKeys(pod.Annotations) {
|
||||
fmt.Printf("\t%s -> %s\n", k, pod.Annotations[k])
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getSortedKeys(m map[string]string) []string {
|
||||
var keys []string
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
return keys
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/net/context"
|
||||
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
var runtimeVersionCommand = cli.Command{
|
||||
Name: "runtimeversion",
|
||||
Usage: "get runtime version information",
|
||||
Action: func(context *cli.Context) error {
|
||||
// Set up a connection to the server.
|
||||
conn, err := getClientConnection(context)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
client := pb.NewRuntimeServiceClient(conn)
|
||||
|
||||
// Test RuntimeServiceClient.Version
|
||||
version := "v1alpha1"
|
||||
err = Version(client, version)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Getting the runtime version failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// Version sends a VersionRequest to the server, and parses the returned VersionResponse.
|
||||
func Version(client pb.RuntimeServiceClient, version string) error {
|
||||
r, err := client.Version(context.Background(), &pb.VersionRequest{Version: version})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("VersionResponse: Version: %s, RuntimeName: %s, RuntimeVersion: %s, RuntimeApiVersion: %s\n", r.Version, r.RuntimeName, r.RuntimeVersion, r.RuntimeApiVersion)
|
||||
return nil
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
# kpod - Simple debugging tool for pods and images
|
||||
kpod is a simple client only tool to help with debugging issues when daemons such as CRI runtime and the kubelet are not responding or
|
||||
failing. A shared API layer could be created to share code between the daemon and kpod. kpod does not require any daemon running. kpod
|
||||
utilizes the same underlying components that crio uses i.e. containers/image, container/storage, oci-runtime-tool/generate, runc or
|
||||
any other OCI compatible runtime. kpod shares state with crio and so has the capability to debug pods/images created by crio.
|
||||
|
||||
## Use cases
|
||||
1. List pods.
|
||||
2. Launch simple pods (that require no daemon support).
|
||||
3. Exec commands in a container in a pod.
|
||||
4. Launch additional containers in a pod.
|
||||
5. List images.
|
||||
6. Remove images not in use.
|
||||
7. Pull images.
|
||||
8. Check image size.
|
||||
9. Report pod disk resource usage.
|
|
@ -1,135 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
is "github.com/containers/image/storage"
|
||||
"github.com/containers/storage"
|
||||
"github.com/fatih/camelcase"
|
||||
"github.com/kubernetes-incubator/cri-o/libkpod"
|
||||
"github.com/kubernetes-incubator/cri-o/libpod"
|
||||
"github.com/kubernetes-incubator/cri-o/server"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
stores = make(map[storage.Store]struct{})
|
||||
)
|
||||
|
||||
func getStore(c *libkpod.Config) (storage.Store, error) {
|
||||
options := storage.DefaultStoreOptions
|
||||
options.GraphRoot = c.Root
|
||||
options.RunRoot = c.RunRoot
|
||||
options.GraphDriverName = c.Storage
|
||||
options.GraphDriverOptions = c.StorageOptions
|
||||
|
||||
store, err := storage.GetStore(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
is.Transport.SetStore(store)
|
||||
stores[store] = struct{}{}
|
||||
return store, nil
|
||||
}
|
||||
|
||||
func getRuntime(c *cli.Context) (*libpod.Runtime, error) {
|
||||
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not get config")
|
||||
}
|
||||
|
||||
options := storage.DefaultStoreOptions
|
||||
options.GraphRoot = config.Root
|
||||
options.RunRoot = config.RunRoot
|
||||
options.GraphDriverName = config.Storage
|
||||
options.GraphDriverOptions = config.StorageOptions
|
||||
|
||||
return libpod.NewRuntime(libpod.WithStorageConfig(options))
|
||||
}
|
||||
|
||||
func shutdownStores() {
|
||||
for store := range stores {
|
||||
if _, err := store.Shutdown(false); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getConfig(c *cli.Context) (*libkpod.Config, error) {
|
||||
config := libkpod.DefaultConfig()
|
||||
var configFile string
|
||||
if c.GlobalIsSet("config") {
|
||||
configFile = c.GlobalString("config")
|
||||
} else if _, err := os.Stat(server.CrioConfigPath); err == nil {
|
||||
configFile = server.CrioConfigPath
|
||||
}
|
||||
// load and merge the configfile from the commandline or use
|
||||
// the default crio config file
|
||||
if configFile != "" {
|
||||
err := config.UpdateFromFile(configFile)
|
||||
if err != nil {
|
||||
return config, err
|
||||
}
|
||||
}
|
||||
if c.GlobalIsSet("root") {
|
||||
config.Root = c.GlobalString("root")
|
||||
}
|
||||
if c.GlobalIsSet("runroot") {
|
||||
config.RunRoot = c.GlobalString("runroot")
|
||||
}
|
||||
|
||||
if c.GlobalIsSet("storage-driver") {
|
||||
config.Storage = c.GlobalString("storage-driver")
|
||||
}
|
||||
if c.GlobalIsSet("storage-opt") {
|
||||
opts := c.GlobalStringSlice("storage-opt")
|
||||
if len(opts) > 0 {
|
||||
config.StorageOptions = opts
|
||||
}
|
||||
}
|
||||
if c.GlobalIsSet("runtime") {
|
||||
config.Runtime = c.GlobalString("runtime")
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func splitCamelCase(src string) string {
|
||||
entries := camelcase.Split(src)
|
||||
return strings.Join(entries, " ")
|
||||
}
|
||||
|
||||
// validateFlags searches for StringFlags or StringSlice flags that never had
|
||||
// a value set. This commonly occurs when the CLI mistakenly takes the next
|
||||
// option and uses it as a value.
|
||||
func validateFlags(c *cli.Context, flags []cli.Flag) error {
|
||||
for _, flag := range flags {
|
||||
switch reflect.TypeOf(flag).String() {
|
||||
case "cli.StringSliceFlag":
|
||||
{
|
||||
f := flag.(cli.StringSliceFlag)
|
||||
name := strings.Split(f.Name, ",")
|
||||
val := c.StringSlice(name[0])
|
||||
for _, v := range val {
|
||||
if ok, _ := regexp.MatchString("^-.+", v); ok {
|
||||
return errors.Errorf("option --%s requires a value", name[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
case "cli.StringFlag":
|
||||
{
|
||||
f := flag.(cli.StringFlag)
|
||||
name := strings.Split(f.Name, ",")
|
||||
val := c.String(name[0])
|
||||
if ok, _ := regexp.MatchString("^-.+", val); ok {
|
||||
return errors.Errorf("option --%s requires a value", name[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"testing"
|
||||
|
||||
"flag"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func TestGetStore(t *testing.T) {
|
||||
t.Skip("FIX THIS!")
|
||||
|
||||
//cmd/kpod/common_test.go:27: cannot use c (type *cli.Context) as type *libkpod.Config in argument to getStore
|
||||
|
||||
// Make sure the tests are running as root
|
||||
skipTestIfNotRoot(t)
|
||||
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
globalSet := flag.NewFlagSet("test", 0)
|
||||
globalSet.String("root", "", "path to the root directory in which data, including images, is stored")
|
||||
globalCtx := cli.NewContext(nil, globalSet, nil)
|
||||
command := cli.Command{Name: "imagesCommand"}
|
||||
c := cli.NewContext(nil, set, globalCtx)
|
||||
c.Command = command
|
||||
|
||||
//_, err := getStore(c)
|
||||
//if err != nil {
|
||||
//t.Error(err)
|
||||
//}
|
||||
}
|
||||
|
||||
func skipTestIfNotRoot(t *testing.T) {
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
t.Skip("Could not determine user. Running without root may cause tests to fail")
|
||||
} else if u.Uid != "0" {
|
||||
t.Skip("tests will fail unless run as root")
|
||||
}
|
||||
}
|
||||
|
||||
func pullTestImage(name string) error {
|
||||
cmd := exec.Command("crioctl", "image", "pull", name)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
128
cmd/kpod/diff.go
128
cmd/kpod/diff.go
|
@ -1,128 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/containers/storage/pkg/archive"
|
||||
"github.com/kubernetes-incubator/cri-o/cmd/kpod/formats"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
type diffJSONOutput struct {
|
||||
Changed []string `json:"changed,omitempty"`
|
||||
Added []string `json:"added,omitempty"`
|
||||
Deleted []string `json:"deleted,omitempty"`
|
||||
}
|
||||
|
||||
type diffOutputParams struct {
|
||||
Change archive.ChangeType
|
||||
Path string
|
||||
}
|
||||
|
||||
type stdoutStruct struct {
|
||||
output []diffOutputParams
|
||||
}
|
||||
|
||||
func (so stdoutStruct) Out() error {
|
||||
for _, d := range so.output {
|
||||
fmt.Printf("%s %s\n", d.Change, d.Path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
diffFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "archive",
|
||||
Usage: "Save the diff as a tar archive",
|
||||
Hidden: true,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "format",
|
||||
Usage: "Change the output format.",
|
||||
},
|
||||
}
|
||||
diffDescription = fmt.Sprint(`Displays changes on a container or image's filesystem. The
|
||||
container or image will be compared to its parent layer`)
|
||||
|
||||
diffCommand = cli.Command{
|
||||
Name: "diff",
|
||||
Usage: "Inspect changes on container's file systems",
|
||||
Description: diffDescription,
|
||||
Flags: diffFlags,
|
||||
Action: diffCmd,
|
||||
ArgsUsage: "ID-NAME",
|
||||
}
|
||||
)
|
||||
|
||||
func formatJSON(output []diffOutputParams) (diffJSONOutput, error) {
|
||||
jsonStruct := diffJSONOutput{}
|
||||
for _, output := range output {
|
||||
switch output.Change {
|
||||
case archive.ChangeModify:
|
||||
jsonStruct.Changed = append(jsonStruct.Changed, output.Path)
|
||||
case archive.ChangeAdd:
|
||||
jsonStruct.Added = append(jsonStruct.Added, output.Path)
|
||||
case archive.ChangeDelete:
|
||||
jsonStruct.Deleted = append(jsonStruct.Deleted, output.Path)
|
||||
default:
|
||||
return jsonStruct, errors.Errorf("output kind %q not recognized", output.Change.String())
|
||||
}
|
||||
}
|
||||
return jsonStruct, nil
|
||||
}
|
||||
|
||||
func diffCmd(c *cli.Context) error {
|
||||
if err := validateFlags(c, diffFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(c.Args()) != 1 {
|
||||
return errors.Errorf("container, image, or layer name must be specified: kpod diff [options [...]] ID-NAME")
|
||||
}
|
||||
|
||||
runtime, err := getRuntime(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get runtime")
|
||||
}
|
||||
defer runtime.Shutdown(false)
|
||||
|
||||
to := c.Args().Get(0)
|
||||
changes, err := runtime.GetDiff("", to)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get changes for %q", to)
|
||||
}
|
||||
|
||||
diffOutput := []diffOutputParams{}
|
||||
outputFormat := c.String("format")
|
||||
|
||||
for _, change := range changes {
|
||||
|
||||
params := diffOutputParams{
|
||||
Change: change.Kind,
|
||||
Path: change.Path,
|
||||
}
|
||||
diffOutput = append(diffOutput, params)
|
||||
}
|
||||
|
||||
var out formats.Writer
|
||||
|
||||
if outputFormat != "" {
|
||||
switch outputFormat {
|
||||
case formats.JSONString:
|
||||
data, err := formatJSON(diffOutput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out = formats.JSONStruct{Output: data}
|
||||
default:
|
||||
return errors.New("only valid format for diff is 'json'")
|
||||
}
|
||||
} else {
|
||||
out = stdoutStruct{output: diffOutput}
|
||||
}
|
||||
formats.Writer(out).Out()
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,271 +0,0 @@
|
|||
package docker
|
||||
|
||||
//
|
||||
// Types extracted from Docker
|
||||
//
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/containers/image/pkg/strslice"
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
// TypeLayers github.com/docker/docker/image/rootfs.go
|
||||
const TypeLayers = "layers"
|
||||
|
||||
// V2S2MediaTypeManifest github.com/docker/distribution/manifest/schema2/manifest.go
|
||||
const V2S2MediaTypeManifest = "application/vnd.docker.distribution.manifest.v2+json"
|
||||
|
||||
// V2S2MediaTypeImageConfig github.com/docker/distribution/manifest/schema2/manifest.go
|
||||
const V2S2MediaTypeImageConfig = "application/vnd.docker.container.image.v1+json"
|
||||
|
||||
// V2S2MediaTypeLayer github.com/docker/distribution/manifest/schema2/manifest.go
|
||||
const V2S2MediaTypeLayer = "application/vnd.docker.image.rootfs.diff.tar.gzip"
|
||||
|
||||
// V2S2MediaTypeUncompressedLayer github.com/docker/distribution/manifest/schema2/manifest.go
|
||||
const V2S2MediaTypeUncompressedLayer = "application/vnd.docker.image.rootfs.diff.tar"
|
||||
|
||||
// V2S2RootFS describes images root filesystem
|
||||
// This is currently a placeholder that only supports layers. In the future
|
||||
// this can be made into an interface that supports different implementations.
|
||||
// github.com/docker/docker/image/rootfs.go
|
||||
type V2S2RootFS struct {
|
||||
Type string `json:"type"`
|
||||
DiffIDs []digest.Digest `json:"diff_ids,omitempty"`
|
||||
}
|
||||
|
||||
// V2S2History stores build commands that were used to create an image
|
||||
// github.com/docker/docker/image/image.go
|
||||
type V2S2History struct {
|
||||
// Created is the timestamp at which the image was created
|
||||
Created time.Time `json:"created"`
|
||||
// Author is the name of the author that was specified when committing the image
|
||||
Author string `json:"author,omitempty"`
|
||||
// CreatedBy keeps the Dockerfile command used while building the image
|
||||
CreatedBy string `json:"created_by,omitempty"`
|
||||
// Comment is the commit message that was set when committing the image
|
||||
Comment string `json:"comment,omitempty"`
|
||||
// EmptyLayer is set to true if this history item did not generate a
|
||||
// layer. Otherwise, the history item is associated with the next
|
||||
// layer in the RootFS section.
|
||||
EmptyLayer bool `json:"empty_layer,omitempty"`
|
||||
}
|
||||
|
||||
// ID is the content-addressable ID of an image.
|
||||
// github.com/docker/docker/image/image.go
|
||||
type ID digest.Digest
|
||||
|
||||
// HealthConfig holds configuration settings for the HEALTHCHECK feature.
|
||||
// github.com/docker/docker/api/types/container/config.go
|
||||
type HealthConfig struct {
|
||||
// Test is the test to perform to check that the container is healthy.
|
||||
// An empty slice means to inherit the default.
|
||||
// The options are:
|
||||
// {} : inherit healthcheck
|
||||
// {"NONE"} : disable healthcheck
|
||||
// {"CMD", args...} : exec arguments directly
|
||||
// {"CMD-SHELL", command} : run command with system's default shell
|
||||
Test []string `json:",omitempty"`
|
||||
|
||||
// Zero means to inherit. Durations are expressed as integer nanoseconds.
|
||||
Interval time.Duration `json:",omitempty"` // Interval is the time to wait between checks.
|
||||
Timeout time.Duration `json:",omitempty"` // Timeout is the time to wait before considering the check to have hung.
|
||||
|
||||
// Retries is the number of consecutive failures needed to consider a container as unhealthy.
|
||||
// Zero means inherit.
|
||||
Retries int `json:",omitempty"`
|
||||
}
|
||||
|
||||
// PortSet is a collection of structs indexed by Port
|
||||
// github.com/docker/go-connections/nat/nat.go
|
||||
type PortSet map[Port]struct{}
|
||||
|
||||
// Port is a string containing port number and protocol in the format "80/tcp"
|
||||
// github.com/docker/go-connections/nat/nat.go
|
||||
type Port string
|
||||
|
||||
// Config contains the configuration data about a container.
|
||||
// It should hold only portable information about the container.
|
||||
// Here, "portable" means "independent from the host we are running on".
|
||||
// Non-portable information *should* appear in HostConfig.
|
||||
// All fields added to this struct must be marked `omitempty` to keep getting
|
||||
// predictable hashes from the old `v1Compatibility` configuration.
|
||||
// github.com/docker/docker/api/types/container/config.go
|
||||
type Config struct {
|
||||
Hostname string // Hostname
|
||||
Domainname string // Domainname
|
||||
User string // User that will run the command(s) inside the container, also support user:group
|
||||
AttachStdin bool // Attach the standard input, makes possible user interaction
|
||||
AttachStdout bool // Attach the standard output
|
||||
AttachStderr bool // Attach the standard error
|
||||
ExposedPorts PortSet `json:",omitempty"` // List of exposed ports
|
||||
Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
|
||||
OpenStdin bool // Open stdin
|
||||
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
|
||||
Env []string // List of environment variable to set in the container
|
||||
Cmd strslice.StrSlice // Command to run when starting the container
|
||||
Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy
|
||||
ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (Windows specific)
|
||||
Image string // Name of the image as it was passed by the operator (e.g. could be symbolic)
|
||||
Volumes map[string]struct{} // List of volumes (mounts) used for the container
|
||||
WorkingDir string // Current directory (PWD) in the command will be launched
|
||||
Entrypoint strslice.StrSlice // Entrypoint to run when starting the container
|
||||
NetworkDisabled bool `json:",omitempty"` // Is network disabled
|
||||
MacAddress string `json:",omitempty"` // Mac Address of the container
|
||||
OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile
|
||||
Labels map[string]string // List of labels set to this container
|
||||
StopSignal string `json:",omitempty"` // Signal to stop a container
|
||||
StopTimeout *int `json:",omitempty"` // Timeout (in seconds) to stop a container
|
||||
Shell strslice.StrSlice `json:",omitempty"` // Shell for shell-form of RUN, CMD, ENTRYPOINT
|
||||
}
|
||||
|
||||
// V1Compatibility - For non-top-level layers, create fake V1Compatibility
|
||||
// strings that fit the format and don't collide with anything else, but
|
||||
// don't result in runnable images on their own.
|
||||
// github.com/docker/distribution/manifest/schema1/config_builder.go
|
||||
type V1Compatibility struct {
|
||||
ID string `json:"id"`
|
||||
Parent string `json:"parent,omitempty"`
|
||||
Comment string `json:"comment,omitempty"`
|
||||
Created time.Time `json:"created"`
|
||||
ContainerConfig struct {
|
||||
Cmd []string
|
||||
} `json:"container_config,omitempty"`
|
||||
Author string `json:"author,omitempty"`
|
||||
ThrowAway bool `json:"throwaway,omitempty"`
|
||||
}
|
||||
|
||||
// V1Image stores the V1 image configuration.
|
||||
// github.com/docker/docker/image/image.go
|
||||
type V1Image struct {
|
||||
// ID is a unique 64 character identifier of the image
|
||||
ID string `json:"id,omitempty"`
|
||||
// Parent is the ID of the parent image
|
||||
Parent string `json:"parent,omitempty"`
|
||||
// Comment is the commit message that was set when committing the image
|
||||
Comment string `json:"comment,omitempty"`
|
||||
// Created is the timestamp at which the image was created
|
||||
Created time.Time `json:"created"`
|
||||
// Container is the id of the container used to commit
|
||||
Container string `json:"container,omitempty"`
|
||||
// ContainerConfig is the configuration of the container that is committed into the image
|
||||
ContainerConfig Config `json:"container_config,omitempty"`
|
||||
// DockerVersion specifies the version of Docker that was used to build the image
|
||||
DockerVersion string `json:"docker_version,omitempty"`
|
||||
// Author is the name of the author that was specified when committing the image
|
||||
Author string `json:"author,omitempty"`
|
||||
// Config is the configuration of the container received from the client
|
||||
Config *Config `json:"config,omitempty"`
|
||||
// Architecture is the hardware that the image is build and runs on
|
||||
Architecture string `json:"architecture,omitempty"`
|
||||
// OS is the operating system used to build and run the image
|
||||
OS string `json:"os,omitempty"`
|
||||
// Size is the total size of the image including all layers it is composed of
|
||||
Size int64 `json:",omitempty"`
|
||||
}
|
||||
|
||||
// V2Image stores the image configuration
|
||||
// github.com/docker/docker/image/image.go
|
||||
type V2Image struct {
|
||||
V1Image
|
||||
Parent ID `json:"parent,omitempty"`
|
||||
RootFS *V2S2RootFS `json:"rootfs,omitempty"`
|
||||
History []V2S2History `json:"history,omitempty"`
|
||||
OSVersion string `json:"os.version,omitempty"`
|
||||
OSFeatures []string `json:"os.features,omitempty"`
|
||||
|
||||
// rawJSON caches the immutable JSON associated with this image.
|
||||
//rawJSON []byte
|
||||
|
||||
// computedID is the ID computed from the hash of the image config.
|
||||
// Not to be confused with the legacy V1 ID in V1Image.
|
||||
//computedID ID
|
||||
}
|
||||
|
||||
// V2Versioned provides a struct with the manifest schemaVersion and mediaType.
|
||||
// Incoming content with unknown schema version can be decoded against this
|
||||
// struct to check the version.
|
||||
// github.com/docker/distribution/manifest/versioned.go
|
||||
type V2Versioned struct {
|
||||
// SchemaVersion is the image manifest schema that this image follows
|
||||
SchemaVersion int `json:"schemaVersion"`
|
||||
|
||||
// MediaType is the media type of this schema.
|
||||
MediaType string `json:"mediaType,omitempty"`
|
||||
}
|
||||
|
||||
// V2S1FSLayer is a container struct for BlobSums defined in an image manifest
|
||||
// github.com/docker/distribution/manifest/schema1/manifest.go
|
||||
type V2S1FSLayer struct {
|
||||
// BlobSum is the tarsum of the referenced filesystem image layer
|
||||
BlobSum digest.Digest `json:"blobSum"`
|
||||
}
|
||||
|
||||
// V2S1History stores unstructured v1 compatibility information
|
||||
// github.com/docker/distribution/manifest/schema1/manifest.go
|
||||
type V2S1History struct {
|
||||
// V1Compatibility is the raw v1 compatibility information
|
||||
V1Compatibility string `json:"v1Compatibility"`
|
||||
}
|
||||
|
||||
// V2S1Manifest provides the base accessible fields for working with V2 image
|
||||
// format in the registry.
|
||||
// github.com/docker/distribution/manifest/schema1/manifest.go
|
||||
type V2S1Manifest struct {
|
||||
V2Versioned
|
||||
|
||||
// Name is the name of the image's repository
|
||||
Name string `json:"name"`
|
||||
|
||||
// Tag is the tag of the image specified by this manifest
|
||||
Tag string `json:"tag"`
|
||||
|
||||
// Architecture is the host architecture on which this image is intended to
|
||||
// run
|
||||
Architecture string `json:"architecture"`
|
||||
|
||||
// FSLayers is a list of filesystem layer blobSums contained in this image
|
||||
FSLayers []V2S1FSLayer `json:"fsLayers"`
|
||||
|
||||
// History is a list of unstructured historical data for v1 compatibility
|
||||
History []V2S1History `json:"history"`
|
||||
}
|
||||
|
||||
// V2S2Descriptor describes targeted content. Used in conjunction with a blob
|
||||
// store, a descriptor can be used to fetch, store and target any kind of
|
||||
// blob. The struct also describes the wire protocol format. Fields should
|
||||
// only be added but never changed.
|
||||
// github.com/docker/distribution/blobs.go
|
||||
type V2S2Descriptor struct {
|
||||
// MediaType describe the type of the content. All text based formats are
|
||||
// encoded as utf-8.
|
||||
MediaType string `json:"mediaType,omitempty"`
|
||||
|
||||
// Size in bytes of content.
|
||||
Size int64 `json:"size,omitempty"`
|
||||
|
||||
// Digest uniquely identifies the content. A byte stream can be verified
|
||||
// against against this digest.
|
||||
Digest digest.Digest `json:"digest,omitempty"`
|
||||
|
||||
// URLs contains the source URLs of this content.
|
||||
URLs []string `json:"urls,omitempty"`
|
||||
|
||||
// NOTE: Before adding a field here, please ensure that all
|
||||
// other options have been exhausted. Much of the type relationships
|
||||
// depend on the simplicity of this type.
|
||||
}
|
||||
|
||||
// V2S2Manifest defines a schema2 manifest.
|
||||
// github.com/docker/distribution/manifest/schema2/manifest.go
|
||||
type V2S2Manifest struct {
|
||||
V2Versioned
|
||||
|
||||
// Config references the image configuration as a blob.
|
||||
Config V2S2Descriptor `json:"config"`
|
||||
|
||||
// Layers lists descriptors for the layers referenced by the
|
||||
// configuration.
|
||||
Layers []V2S2Descriptor `json:"layers"`
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"fmt"
|
||||
|
||||
"github.com/containers/storage"
|
||||
"github.com/containers/storage/pkg/archive"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
type exportOptions struct {
|
||||
output string
|
||||
container string
|
||||
}
|
||||
|
||||
var (
|
||||
exportFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "output, o",
|
||||
Usage: "Write to a file, default is STDOUT",
|
||||
Value: "/dev/stdout",
|
||||
},
|
||||
}
|
||||
exportDescription = "Exports container's filesystem contents as a tar archive" +
|
||||
" and saves it on the local machine."
|
||||
exportCommand = cli.Command{
|
||||
Name: "export",
|
||||
Usage: "Export container's filesystem contents as a tar archive",
|
||||
Description: exportDescription,
|
||||
Flags: exportFlags,
|
||||
Action: exportCmd,
|
||||
ArgsUsage: "CONTAINER",
|
||||
}
|
||||
)
|
||||
|
||||
// exportCmd saves a container to a tarball on disk
|
||||
func exportCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if len(args) == 0 {
|
||||
return errors.Errorf("container id must be specified")
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return errors.Errorf("too many arguments given, need 1 at most.")
|
||||
}
|
||||
container := args[0]
|
||||
if err := validateFlags(c, exportFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get config")
|
||||
}
|
||||
store, err := getStore(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
output := c.String("output")
|
||||
if output == "/dev/stdout" {
|
||||
file := os.Stdout
|
||||
if logrus.IsTerminal(file) {
|
||||
return errors.Errorf("refusing to export to terminal. Use -o flag or redirect")
|
||||
}
|
||||
}
|
||||
|
||||
opts := exportOptions{
|
||||
output: output,
|
||||
container: container,
|
||||
}
|
||||
|
||||
return exportContainer(store, opts)
|
||||
}
|
||||
|
||||
// exportContainer exports the contents of a container and saves it as
|
||||
// a tarball on disk
|
||||
func exportContainer(store storage.Store, opts exportOptions) error {
|
||||
mountPoint, err := store.Mount(opts.container, "")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error finding container %q", opts.container)
|
||||
}
|
||||
defer func() {
|
||||
if err := store.Unmount(opts.container); err != nil {
|
||||
fmt.Printf("error unmounting container %q: %v\n", opts.container, err)
|
||||
}
|
||||
}()
|
||||
|
||||
input, err := archive.Tar(mountPoint, archive.Uncompressed)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error reading container directory %q", opts.container)
|
||||
}
|
||||
|
||||
outFile, err := os.Create(opts.output)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error creating file %q", opts.output)
|
||||
}
|
||||
defer outFile.Close()
|
||||
|
||||
_, err = io.Copy(outFile, input)
|
||||
return err
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
package formats
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// JSONString const to save on duplicate variable names
|
||||
JSONString = "json"
|
||||
// IDString const to save on duplicates for Go templates
|
||||
IDString = "{{.ID}}"
|
||||
)
|
||||
|
||||
// Writer interface for outputs
|
||||
type Writer interface {
|
||||
Out() error
|
||||
}
|
||||
|
||||
// JSONStructArray for JSON output
|
||||
type JSONStructArray struct {
|
||||
Output []interface{}
|
||||
}
|
||||
|
||||
// StdoutTemplateArray for Go template output
|
||||
type StdoutTemplateArray struct {
|
||||
Output []interface{}
|
||||
Template string
|
||||
Fields map[string]string
|
||||
}
|
||||
|
||||
// JSONStruct for JSON output
|
||||
type JSONStruct struct {
|
||||
Output interface{}
|
||||
}
|
||||
|
||||
// StdoutTemplate for Go template output
|
||||
type StdoutTemplate struct {
|
||||
Output interface{}
|
||||
Template string
|
||||
Fields map[string]string
|
||||
}
|
||||
|
||||
// YAMLStruct for YAML output
|
||||
type YAMLStruct struct {
|
||||
Output interface{}
|
||||
}
|
||||
|
||||
// Out method for JSON Arrays
|
||||
func (j JSONStructArray) Out() error {
|
||||
data, err := json.MarshalIndent(j.Output, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s\n", data)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Out method for Go templates
|
||||
func (t StdoutTemplateArray) Out() error {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
|
||||
if strings.HasPrefix(t.Template, "table") {
|
||||
// replace any spaces with tabs in template so that tabwriter can align it
|
||||
t.Template = strings.Replace(strings.TrimSpace(t.Template[5:]), " ", "\t", -1)
|
||||
headerTmpl, err := template.New("header").Funcs(headerFunctions).Parse(t.Template)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Template parsing error")
|
||||
}
|
||||
err = headerTmpl.Execute(w, t.Fields)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(w, "")
|
||||
}
|
||||
t.Template = strings.Replace(t.Template, " ", "\t", -1)
|
||||
tmpl, err := template.New("image").Funcs(basicFunctions).Parse(t.Template)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Template parsing error")
|
||||
}
|
||||
for _, img := range t.Output {
|
||||
basicTmpl := tmpl.Funcs(basicFunctions)
|
||||
err = basicTmpl.Execute(w, img)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintln(w, "")
|
||||
}
|
||||
return w.Flush()
|
||||
}
|
||||
|
||||
// Out method for JSON struct
|
||||
func (j JSONStruct) Out() error {
|
||||
data, err := json.MarshalIndent(j.Output, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s\n", data)
|
||||
return nil
|
||||
}
|
||||
|
||||
//Out method for Go templates
|
||||
func (t StdoutTemplate) Out() error {
|
||||
tmpl, err := template.New("image").Parse(t.Template)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "template parsing error")
|
||||
}
|
||||
err = tmpl.Execute(os.Stdout, t.Output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Out method for YAML
|
||||
func (y YAMLStruct) Out() error {
|
||||
var buf []byte
|
||||
var err error
|
||||
buf, err = yaml.Marshal(y.Output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(buf))
|
||||
return nil
|
||||
}
|
|
@ -1,243 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containers/image/types"
|
||||
units "github.com/docker/go-units"
|
||||
"github.com/kubernetes-incubator/cri-o/cmd/kpod/formats"
|
||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
const (
|
||||
createdByTruncLength = 45
|
||||
idTruncLength = 13
|
||||
)
|
||||
|
||||
// historyTemplateParams stores info about each layer
|
||||
type historyTemplateParams struct {
|
||||
ID string
|
||||
Created string
|
||||
CreatedBy string
|
||||
Size string
|
||||
Comment string
|
||||
}
|
||||
|
||||
// historyJSONParams is only used when the JSON format is specified,
|
||||
// and is better for data processing from JSON.
|
||||
// historyJSONParams will be populated by data from v1.History and types.BlobInfo,
|
||||
// the members of the struct are the sama data types as their sources.
|
||||
type historyJSONParams struct {
|
||||
ID string `json:"id"`
|
||||
Created *time.Time `json:"created"`
|
||||
CreatedBy string `json:"createdBy"`
|
||||
Size int64 `json:"size"`
|
||||
Comment string `json:"comment"`
|
||||
}
|
||||
|
||||
// historyOptions stores cli flag values
|
||||
type historyOptions struct {
|
||||
human bool
|
||||
noTrunc bool
|
||||
quiet bool
|
||||
format string
|
||||
}
|
||||
|
||||
var (
|
||||
historyFlags = []cli.Flag{
|
||||
cli.BoolTFlag{
|
||||
Name: "human, H",
|
||||
Usage: "Display sizes and dates in human readable format",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "no-trunc, notruncate",
|
||||
Usage: "Do not truncate the output",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "quiet, q",
|
||||
Usage: "Display the numeric IDs only",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "format",
|
||||
Usage: "Change the output to JSON or a Go template",
|
||||
},
|
||||
}
|
||||
|
||||
historyDescription = "Displays the history of an image. The information can be printed out in an easy to read, " +
|
||||
"or user specified format, and can be truncated."
|
||||
historyCommand = cli.Command{
|
||||
Name: "history",
|
||||
Usage: "Show history of a specified image",
|
||||
Description: historyDescription,
|
||||
Flags: historyFlags,
|
||||
Action: historyCmd,
|
||||
ArgsUsage: "",
|
||||
}
|
||||
)
|
||||
|
||||
func historyCmd(c *cli.Context) error {
|
||||
if err := validateFlags(c, historyFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtime, err := getRuntime(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not get config")
|
||||
}
|
||||
defer runtime.Shutdown(false)
|
||||
|
||||
format := genHistoryFormat(c.Bool("quiet"))
|
||||
if c.IsSet("format") {
|
||||
format = c.String("format")
|
||||
}
|
||||
|
||||
args := c.Args()
|
||||
if len(args) == 0 {
|
||||
return errors.Errorf("an image name must be specified")
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return errors.Errorf("Kpod history takes at most 1 argument")
|
||||
}
|
||||
imgName := args[0]
|
||||
|
||||
opts := historyOptions{
|
||||
human: c.BoolT("human"),
|
||||
noTrunc: c.Bool("no-trunc"),
|
||||
quiet: c.Bool("quiet"),
|
||||
format: format,
|
||||
}
|
||||
|
||||
history, layers, imageID, err := runtime.GetHistory(imgName)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error getting history of image %q", imgName)
|
||||
}
|
||||
|
||||
return generateHistoryOutput(history, layers, imageID, opts)
|
||||
}
|
||||
|
||||
func genHistoryFormat(quiet bool) (format string) {
|
||||
if quiet {
|
||||
return formats.IDString
|
||||
}
|
||||
return "table {{.ID}}\t{{.Created}}\t{{.CreatedBy}}\t{{.Size}}\t{{.Comment}}\t"
|
||||
}
|
||||
|
||||
// historyToGeneric makes an empty array of interfaces for output
|
||||
func historyToGeneric(templParams []historyTemplateParams, JSONParams []historyJSONParams) (genericParams []interface{}) {
|
||||
if len(templParams) > 0 {
|
||||
for _, v := range templParams {
|
||||
genericParams = append(genericParams, interface{}(v))
|
||||
}
|
||||
return
|
||||
}
|
||||
for _, v := range JSONParams {
|
||||
genericParams = append(genericParams, interface{}(v))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// generate the header based on the template provided
|
||||
func (h *historyTemplateParams) headerMap() map[string]string {
|
||||
v := reflect.Indirect(reflect.ValueOf(h))
|
||||
values := make(map[string]string)
|
||||
for h := 0; h < v.NumField(); h++ {
|
||||
key := v.Type().Field(h).Name
|
||||
value := key
|
||||
values[key] = strings.ToUpper(splitCamelCase(value))
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
// getHistorytemplateOutput gets the modified history information to be printed in human readable format
|
||||
func getHistoryTemplateOutput(history []v1.History, layers []types.BlobInfo, imageID string, opts historyOptions) (historyOutput []historyTemplateParams) {
|
||||
var (
|
||||
outputSize string
|
||||
createdTime string
|
||||
createdBy string
|
||||
count = 1
|
||||
)
|
||||
for i := len(history) - 1; i >= 0; i-- {
|
||||
if i != len(history)-1 {
|
||||
imageID = "<missing>"
|
||||
}
|
||||
if !opts.noTrunc && i == len(history)-1 {
|
||||
imageID = imageID[:idTruncLength]
|
||||
}
|
||||
|
||||
var size int64
|
||||
if !history[i].EmptyLayer {
|
||||
size = layers[len(layers)-count].Size
|
||||
count++
|
||||
}
|
||||
|
||||
if opts.human {
|
||||
createdTime = units.HumanDuration(time.Since((*history[i].Created))) + " ago"
|
||||
outputSize = units.HumanSize(float64(size))
|
||||
} else {
|
||||
createdTime = (history[i].Created).Format(time.RFC3339)
|
||||
outputSize = strconv.FormatInt(size, 10)
|
||||
}
|
||||
|
||||
createdBy = strings.Join(strings.Fields(history[i].CreatedBy), " ")
|
||||
if !opts.noTrunc && len(createdBy) > createdByTruncLength {
|
||||
createdBy = createdBy[:createdByTruncLength-3] + "..."
|
||||
}
|
||||
|
||||
params := historyTemplateParams{
|
||||
ID: imageID,
|
||||
Created: createdTime,
|
||||
CreatedBy: createdBy,
|
||||
Size: outputSize,
|
||||
Comment: history[i].Comment,
|
||||
}
|
||||
historyOutput = append(historyOutput, params)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// getHistoryJSONOutput returns the history information in its raw form
|
||||
func getHistoryJSONOutput(history []v1.History, layers []types.BlobInfo, imageID string) (historyOutput []historyJSONParams) {
|
||||
count := 1
|
||||
for i := len(history) - 1; i >= 0; i-- {
|
||||
var size int64
|
||||
if !history[i].EmptyLayer {
|
||||
size = layers[len(layers)-count].Size
|
||||
count++
|
||||
}
|
||||
|
||||
params := historyJSONParams{
|
||||
ID: imageID,
|
||||
Created: history[i].Created,
|
||||
CreatedBy: history[i].CreatedBy,
|
||||
Size: size,
|
||||
Comment: history[i].Comment,
|
||||
}
|
||||
historyOutput = append(historyOutput, params)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// generateHistoryOutput generates the history based on the format given
|
||||
func generateHistoryOutput(history []v1.History, layers []types.BlobInfo, imageID string, opts historyOptions) error {
|
||||
if len(history) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var out formats.Writer
|
||||
|
||||
switch opts.format {
|
||||
case formats.JSONString:
|
||||
historyOutput := getHistoryJSONOutput(history, layers, imageID)
|
||||
out = formats.JSONStructArray{Output: historyToGeneric([]historyTemplateParams{}, historyOutput)}
|
||||
default:
|
||||
historyOutput := getHistoryTemplateOutput(history, layers, imageID, opts)
|
||||
out = formats.StdoutTemplateArray{Output: historyToGeneric(historyOutput, []historyJSONParams{}), Template: opts.format, Fields: historyOutput[0].headerMap()}
|
||||
}
|
||||
|
||||
return formats.Writer(out).Out()
|
||||
}
|
|
@ -1,330 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/containers/image/types"
|
||||
"github.com/containers/storage"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/kubernetes-incubator/cri-o/cmd/kpod/formats"
|
||||
"github.com/kubernetes-incubator/cri-o/libpod"
|
||||
"github.com/kubernetes-incubator/cri-o/libpod/common"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
type imagesTemplateParams struct {
|
||||
ID string
|
||||
Name string
|
||||
Digest digest.Digest
|
||||
CreatedAt string
|
||||
Size string
|
||||
}
|
||||
|
||||
type imagesJSONParams struct {
|
||||
ID string `json:"id"`
|
||||
Name []string `json:"names"`
|
||||
Digest digest.Digest `json:"digest"`
|
||||
CreatedAt time.Time `json:"created"`
|
||||
Size int64 `json:"size"`
|
||||
}
|
||||
|
||||
type imagesOptions struct {
|
||||
quiet bool
|
||||
noHeading bool
|
||||
noTrunc bool
|
||||
digests bool
|
||||
format string
|
||||
}
|
||||
|
||||
var (
|
||||
imagesFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "quiet, q",
|
||||
Usage: "display only image IDs",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "noheading, n",
|
||||
Usage: "do not print column headings",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "no-trunc, notruncate",
|
||||
Usage: "do not truncate output",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "digests",
|
||||
Usage: "show digests",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "format",
|
||||
Usage: "Change the output format to JSON or a Go template",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "filter, f",
|
||||
Usage: "filter output based on conditions provided (default [])",
|
||||
},
|
||||
}
|
||||
|
||||
imagesDescription = "lists locally stored images."
|
||||
imagesCommand = cli.Command{
|
||||
Name: "images",
|
||||
Usage: "list images in local storage",
|
||||
Description: imagesDescription,
|
||||
Flags: imagesFlags,
|
||||
Action: imagesCmd,
|
||||
ArgsUsage: "",
|
||||
}
|
||||
)
|
||||
|
||||
func imagesCmd(c *cli.Context) error {
|
||||
if err := validateFlags(c, imagesFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtime, err := getRuntime(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not get runtime")
|
||||
}
|
||||
defer runtime.Shutdown(false)
|
||||
|
||||
var format string
|
||||
if c.IsSet("format") {
|
||||
format = c.String("format")
|
||||
} else {
|
||||
format = genImagesFormat(c.Bool("quiet"), c.Bool("noheading"), c.Bool("digests"))
|
||||
}
|
||||
|
||||
opts := imagesOptions{
|
||||
quiet: c.Bool("quiet"),
|
||||
noHeading: c.Bool("noheading"),
|
||||
noTrunc: c.Bool("no-trunc"),
|
||||
digests: c.Bool("digests"),
|
||||
format: format,
|
||||
}
|
||||
|
||||
var imageInput string
|
||||
if len(c.Args()) == 1 {
|
||||
imageInput = c.Args().Get(0)
|
||||
}
|
||||
if len(c.Args()) > 1 {
|
||||
return errors.New("'kpod images' requires at most 1 argument")
|
||||
}
|
||||
|
||||
params, err := runtime.ParseImageFilter(imageInput, c.String("filter"))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error parsing filter")
|
||||
}
|
||||
|
||||
// generate the different filters
|
||||
labelFilter := generateImagesFilter(params, "label")
|
||||
beforeImageFilter := generateImagesFilter(params, "before-image")
|
||||
sinceImageFilter := generateImagesFilter(params, "since-image")
|
||||
danglingFilter := generateImagesFilter(params, "dangling")
|
||||
referenceFilter := generateImagesFilter(params, "reference")
|
||||
imageInputFilter := generateImagesFilter(params, "image-input")
|
||||
|
||||
images, err := runtime.GetImages(params, labelFilter, beforeImageFilter, sinceImageFilter, danglingFilter, referenceFilter, imageInputFilter)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get list of images matching filter")
|
||||
}
|
||||
|
||||
return generateImagesOutput(runtime, images, opts)
|
||||
}
|
||||
|
||||
func genImagesFormat(quiet, noHeading, digests bool) (format string) {
|
||||
if quiet {
|
||||
return formats.IDString
|
||||
}
|
||||
format = "table {{.ID}}\t{{.Name}}\t"
|
||||
if noHeading {
|
||||
format = "{{.ID}}\t{{.Name}}\t"
|
||||
}
|
||||
if digests {
|
||||
format += "{{.Digest}}\t"
|
||||
}
|
||||
format += "{{.CreatedAt}}\t{{.Size}}\t"
|
||||
return
|
||||
}
|
||||
|
||||
// imagesToGeneric creates an empty array of interfaces for output
|
||||
func imagesToGeneric(templParams []imagesTemplateParams, JSONParams []imagesJSONParams) (genericParams []interface{}) {
|
||||
if len(templParams) > 0 {
|
||||
for _, v := range templParams {
|
||||
genericParams = append(genericParams, interface{}(v))
|
||||
}
|
||||
return
|
||||
}
|
||||
for _, v := range JSONParams {
|
||||
genericParams = append(genericParams, interface{}(v))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// generate the header based on the template provided
|
||||
func (i *imagesTemplateParams) headerMap() map[string]string {
|
||||
v := reflect.Indirect(reflect.ValueOf(i))
|
||||
values := make(map[string]string)
|
||||
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
key := v.Type().Field(i).Name
|
||||
value := key
|
||||
if value == "ID" || value == "Name" {
|
||||
value = "Image" + value
|
||||
}
|
||||
values[key] = strings.ToUpper(splitCamelCase(value))
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
// getImagesTemplateOutput returns the images information to be printed in human readable format
|
||||
func getImagesTemplateOutput(runtime *libpod.Runtime, images []*storage.Image, opts imagesOptions) (imagesOutput []imagesTemplateParams) {
|
||||
var (
|
||||
lastID string
|
||||
)
|
||||
for _, img := range images {
|
||||
if opts.quiet && lastID == img.ID {
|
||||
continue // quiet should not show the same ID multiple times
|
||||
}
|
||||
createdTime := img.Created
|
||||
|
||||
imageID := img.ID
|
||||
if !opts.noTrunc {
|
||||
imageID = imageID[:idTruncLength]
|
||||
}
|
||||
|
||||
imageName := "<none>"
|
||||
if len(img.Names) > 0 {
|
||||
imageName = img.Names[0]
|
||||
}
|
||||
|
||||
info, imageDigest, size, _ := runtime.InfoAndDigestAndSize(*img)
|
||||
if info != nil {
|
||||
createdTime = info.Created
|
||||
}
|
||||
|
||||
params := imagesTemplateParams{
|
||||
ID: imageID,
|
||||
Name: imageName,
|
||||
Digest: imageDigest,
|
||||
CreatedAt: units.HumanDuration(time.Since((createdTime))) + " ago",
|
||||
Size: units.HumanSize(float64(size)),
|
||||
}
|
||||
imagesOutput = append(imagesOutput, params)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// getImagesJSONOutput returns the images information in its raw form
|
||||
func getImagesJSONOutput(runtime *libpod.Runtime, images []*storage.Image) (imagesOutput []imagesJSONParams) {
|
||||
for _, img := range images {
|
||||
createdTime := img.Created
|
||||
|
||||
info, imageDigest, size, _ := runtime.InfoAndDigestAndSize(*img)
|
||||
if info != nil {
|
||||
createdTime = info.Created
|
||||
}
|
||||
|
||||
params := imagesJSONParams{
|
||||
ID: img.ID,
|
||||
Name: img.Names,
|
||||
Digest: imageDigest,
|
||||
CreatedAt: createdTime,
|
||||
Size: size,
|
||||
}
|
||||
imagesOutput = append(imagesOutput, params)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// generateImagesOutput generates the images based on the format provided
|
||||
func generateImagesOutput(runtime *libpod.Runtime, images []*storage.Image, opts imagesOptions) error {
|
||||
if len(images) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var out formats.Writer
|
||||
|
||||
switch opts.format {
|
||||
case formats.JSONString:
|
||||
imagesOutput := getImagesJSONOutput(runtime, images)
|
||||
out = formats.JSONStructArray{Output: imagesToGeneric([]imagesTemplateParams{}, imagesOutput)}
|
||||
default:
|
||||
imagesOutput := getImagesTemplateOutput(runtime, images, opts)
|
||||
out = formats.StdoutTemplateArray{Output: imagesToGeneric(imagesOutput, []imagesJSONParams{}), Template: opts.format, Fields: imagesOutput[0].headerMap()}
|
||||
|
||||
}
|
||||
|
||||
return formats.Writer(out).Out()
|
||||
}
|
||||
|
||||
// generateImagesFilter returns an ImageFilter based on filterType
|
||||
// to add more filters, define a new case and write what the ImageFilter function should do
|
||||
func generateImagesFilter(params *libpod.ImageFilterParams, filterType string) libpod.ImageFilter {
|
||||
switch filterType {
|
||||
case "label":
|
||||
return func(image *storage.Image, info *types.ImageInspectInfo) bool {
|
||||
if params == nil || params.Label == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
pair := strings.SplitN(params.Label, "=", 2)
|
||||
if val, ok := info.Labels[pair[0]]; ok {
|
||||
if len(pair) == 2 && val == pair[1] {
|
||||
return true
|
||||
}
|
||||
if len(pair) == 1 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
case "before-image":
|
||||
return func(image *storage.Image, info *types.ImageInspectInfo) bool {
|
||||
if params == nil || params.BeforeImage.IsZero() {
|
||||
return true
|
||||
}
|
||||
return info.Created.Before(params.BeforeImage)
|
||||
}
|
||||
case "since-image":
|
||||
return func(image *storage.Image, info *types.ImageInspectInfo) bool {
|
||||
if params == nil || params.SinceImage.IsZero() {
|
||||
return true
|
||||
}
|
||||
return info.Created.After(params.SinceImage)
|
||||
}
|
||||
case "dangling":
|
||||
return func(image *storage.Image, info *types.ImageInspectInfo) bool {
|
||||
if params == nil || params.Dangling == "" {
|
||||
return true
|
||||
}
|
||||
if common.IsFalse(params.Dangling) && params.ImageName != "<none>" {
|
||||
return true
|
||||
}
|
||||
if common.IsTrue(params.Dangling) && params.ImageName == "<none>" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
case "reference":
|
||||
return func(image *storage.Image, info *types.ImageInspectInfo) bool {
|
||||
if params == nil || params.ReferencePattern == "" {
|
||||
return true
|
||||
}
|
||||
return libpod.MatchesReference(params.ImageName, params.ReferencePattern)
|
||||
}
|
||||
case "image-input":
|
||||
return func(image *storage.Image, info *types.ImageInspectInfo) bool {
|
||||
if params == nil || params.ImageInput == "" {
|
||||
return true
|
||||
}
|
||||
return libpod.MatchesReference(params.ImageName, params.ImageInput)
|
||||
}
|
||||
default:
|
||||
fmt.Println("invalid filter type", filterType)
|
||||
return nil
|
||||
}
|
||||
}
|
200
cmd/kpod/info.go
200
cmd/kpod/info.go
|
@ -1,200 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/kubernetes-incubator/cri-o/cmd/kpod/formats"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
infoDescription = "display system information"
|
||||
infoCommand = cli.Command{
|
||||
Name: "info",
|
||||
Usage: infoDescription,
|
||||
Description: `Information display here pertain to the host, current storage stats, and build of kpod. Useful for the user and when reporting issues.`,
|
||||
Flags: infoFlags,
|
||||
Action: infoCmd,
|
||||
ArgsUsage: "",
|
||||
}
|
||||
infoFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "debug, D",
|
||||
Usage: "display additional debug information",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "format",
|
||||
Usage: "Change the output format to JSON or a Go template",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func infoCmd(c *cli.Context) error {
|
||||
if err := validateFlags(c, infoFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
info := map[string]interface{}{}
|
||||
|
||||
infoGivers := []infoGiverFunc{
|
||||
storeInfo,
|
||||
hostInfo,
|
||||
}
|
||||
|
||||
if c.Bool("debug") {
|
||||
infoGivers = append(infoGivers, debugInfo)
|
||||
}
|
||||
|
||||
for _, giver := range infoGivers {
|
||||
thisName, thisInfo, err := giver(c)
|
||||
if err != nil {
|
||||
info[thisName] = infoErr(err)
|
||||
continue
|
||||
}
|
||||
info[thisName] = thisInfo
|
||||
}
|
||||
|
||||
var out formats.Writer
|
||||
infoOutputFormat := c.String("format")
|
||||
switch infoOutputFormat {
|
||||
case formats.JSONString:
|
||||
out = formats.JSONStruct{Output: info}
|
||||
case "":
|
||||
out = formats.YAMLStruct{Output: info}
|
||||
default:
|
||||
out = formats.StdoutTemplate{Output: info, Template: infoOutputFormat}
|
||||
}
|
||||
|
||||
formats.Writer(out).Out()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func infoErr(err error) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
type infoGiverFunc func(c *cli.Context) (name string, info map[string]interface{}, err error)
|
||||
|
||||
// top-level "debug" info
|
||||
func debugInfo(c *cli.Context) (string, map[string]interface{}, error) {
|
||||
info := map[string]interface{}{}
|
||||
info["compiler"] = runtime.Compiler
|
||||
info["go version"] = runtime.Version()
|
||||
info["kpod version"] = c.App.Version
|
||||
info["git commit"] = gitCommit
|
||||
return "debug", info, nil
|
||||
}
|
||||
|
||||
// top-level "host" info
|
||||
func hostInfo(c *cli.Context) (string, map[string]interface{}, error) {
|
||||
// lets say OS, arch, number of cpus, amount of memory, maybe os distribution/version, hostname, kernel version, uptime
|
||||
info := map[string]interface{}{}
|
||||
info["os"] = runtime.GOOS
|
||||
info["arch"] = runtime.GOARCH
|
||||
info["cpus"] = runtime.NumCPU()
|
||||
mi, err := system.ReadMemInfo()
|
||||
if err != nil {
|
||||
info["meminfo"] = infoErr(err)
|
||||
} else {
|
||||
// TODO this might be a place for github.com/dustin/go-humanize
|
||||
info["MemTotal"] = mi.MemTotal
|
||||
info["MemFree"] = mi.MemFree
|
||||
info["SwapTotal"] = mi.SwapTotal
|
||||
info["SwapFree"] = mi.SwapFree
|
||||
}
|
||||
if kv, err := readKernelVersion(); err != nil {
|
||||
info["kernel"] = infoErr(err)
|
||||
} else {
|
||||
info["kernel"] = kv
|
||||
}
|
||||
|
||||
if up, err := readUptime(); err != nil {
|
||||
info["uptime"] = infoErr(err)
|
||||
} else {
|
||||
info["uptime"] = up
|
||||
}
|
||||
if host, err := os.Hostname(); err != nil {
|
||||
info["hostname"] = infoErr(err)
|
||||
} else {
|
||||
info["hostname"] = host
|
||||
}
|
||||
return "host", info, nil
|
||||
}
|
||||
|
||||
// top-level "store" info
|
||||
func storeInfo(c *cli.Context) (string, map[string]interface{}, error) {
|
||||
storeStr := "store"
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return storeStr, nil, errors.Wrapf(err, "Could not get config")
|
||||
}
|
||||
store, err := getStore(config)
|
||||
if err != nil {
|
||||
return storeStr, nil, err
|
||||
}
|
||||
|
||||
// lets say storage driver in use, number of images, number of containers
|
||||
info := map[string]interface{}{}
|
||||
info["GraphRoot"] = store.GraphRoot()
|
||||
info["RunRoot"] = store.RunRoot()
|
||||
info["GraphDriverName"] = store.GraphDriverName()
|
||||
info["GraphOptions"] = store.GraphOptions()
|
||||
statusPairs, err := store.Status()
|
||||
if err != nil {
|
||||
return storeStr, nil, err
|
||||
}
|
||||
status := map[string]string{}
|
||||
for _, pair := range statusPairs {
|
||||
status[pair[0]] = pair[1]
|
||||
}
|
||||
info["GraphStatus"] = status
|
||||
images, err := store.Images()
|
||||
if err != nil {
|
||||
info["ImageStore"] = infoErr(err)
|
||||
} else {
|
||||
info["ImageStore"] = map[string]interface{}{
|
||||
"number": len(images),
|
||||
}
|
||||
}
|
||||
containers, err := store.Containers()
|
||||
if err != nil {
|
||||
info["ContainerStore"] = infoErr(err)
|
||||
} else {
|
||||
info["ContainerStore"] = map[string]interface{}{
|
||||
"number": len(containers),
|
||||
}
|
||||
}
|
||||
return storeStr, info, nil
|
||||
}
|
||||
|
||||
func readKernelVersion() (string, error) {
|
||||
buf, err := ioutil.ReadFile("/proc/version")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
f := bytes.Fields(buf)
|
||||
if len(f) < 2 {
|
||||
return string(bytes.TrimSpace(buf)), nil
|
||||
}
|
||||
return string(f[2]), nil
|
||||
}
|
||||
|
||||
func readUptime() (string, error) {
|
||||
buf, err := ioutil.ReadFile("/proc/uptime")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
f := bytes.Fields(buf)
|
||||
if len(f) < 1 {
|
||||
return "", fmt.Errorf("invalid uptime")
|
||||
}
|
||||
return string(f[0]), nil
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/kubernetes-incubator/cri-o/cmd/kpod/formats"
|
||||
"github.com/kubernetes-incubator/cri-o/libkpod"
|
||||
"github.com/kubernetes-incubator/cri-o/libpod/images"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
const (
|
||||
inspectTypeContainer = "container"
|
||||
inspectTypeImage = "image"
|
||||
inspectAll = "all"
|
||||
)
|
||||
|
||||
var (
|
||||
inspectFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "type, t",
|
||||
Value: inspectAll,
|
||||
Usage: "Return JSON for specified type, (e.g image, container or task)",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "format, f",
|
||||
Usage: "Change the output format to a Go template",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "size",
|
||||
Usage: "Display total file size if the type is container",
|
||||
},
|
||||
}
|
||||
inspectDescription = "This displays the low-level information on containers and images identified by name or ID. By default, this will render all results in a JSON array. If the container and image have the same name, this will return container JSON for unspecified type."
|
||||
inspectCommand = cli.Command{
|
||||
Name: "inspect",
|
||||
Usage: "Displays the configuration of a container or image",
|
||||
Description: inspectDescription,
|
||||
Flags: inspectFlags,
|
||||
Action: inspectCmd,
|
||||
ArgsUsage: "CONTAINER-OR-IMAGE",
|
||||
}
|
||||
)
|
||||
|
||||
func inspectCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if len(args) == 0 {
|
||||
return errors.Errorf("container or image name must be specified: kpod inspect [options [...]] name")
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return errors.Errorf("too many arguments specified")
|
||||
}
|
||||
if err := validateFlags(c, inspectFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
itemType := c.String("type")
|
||||
size := c.Bool("size")
|
||||
|
||||
switch itemType {
|
||||
case inspectTypeContainer:
|
||||
case inspectTypeImage:
|
||||
case inspectAll:
|
||||
default:
|
||||
return errors.Errorf("the only recognized types are %q, %q, and %q", inspectTypeContainer, inspectTypeImage, inspectAll)
|
||||
}
|
||||
|
||||
name := args[0]
|
||||
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not get config")
|
||||
}
|
||||
server, err := libkpod.New(config)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get container server")
|
||||
}
|
||||
defer server.Shutdown()
|
||||
if err = server.Update(); err != nil {
|
||||
return errors.Wrapf(err, "could not update list of containers")
|
||||
}
|
||||
|
||||
outputFormat := c.String("format")
|
||||
var data interface{}
|
||||
switch itemType {
|
||||
case inspectTypeContainer:
|
||||
data, err = server.GetContainerData(name, size)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error parsing container data")
|
||||
}
|
||||
case inspectTypeImage:
|
||||
data, err = images.GetData(server.Store(), name)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error parsing image data")
|
||||
}
|
||||
case inspectAll:
|
||||
ctrData, err := server.GetContainerData(name, size)
|
||||
if err != nil {
|
||||
imgData, err := images.GetData(server.Store(), name)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error parsing container or image data")
|
||||
}
|
||||
data = imgData
|
||||
|
||||
} else {
|
||||
data = ctrData
|
||||
}
|
||||
}
|
||||
|
||||
var out formats.Writer
|
||||
if outputFormat != "" && outputFormat != formats.JSONString {
|
||||
//template
|
||||
out = formats.StdoutTemplate{Output: data, Template: outputFormat}
|
||||
} else {
|
||||
// default is json output
|
||||
out = formats.JSONStruct{Output: data}
|
||||
}
|
||||
|
||||
formats.Writer(out).Out()
|
||||
return nil
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
"github.com/kubernetes-incubator/cri-o/libkpod"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
killFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "signal, s",
|
||||
Usage: "Signal to send to the container",
|
||||
Value: "KILL",
|
||||
},
|
||||
}
|
||||
killDescription = "The main process inside each container specified will be sent SIGKILL, or any signal specified with option --signal."
|
||||
killCommand = cli.Command{
|
||||
Name: "kill",
|
||||
Usage: "Kill one or more running containers with a specific signal",
|
||||
Description: killDescription,
|
||||
Flags: killFlags,
|
||||
Action: killCmd,
|
||||
ArgsUsage: "[CONTAINER_NAME_OR_ID]",
|
||||
}
|
||||
)
|
||||
|
||||
// killCmd kills one or more containers with a signal
|
||||
func killCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if len(args) == 0 {
|
||||
return errors.Errorf("specify one or more containers to kill")
|
||||
}
|
||||
if err := validateFlags(c, killFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get config")
|
||||
}
|
||||
server, err := libkpod.New(config)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get container server")
|
||||
}
|
||||
killSignal := c.String("signal")
|
||||
// Check if the signalString provided by the user is valid
|
||||
// Invalid signals will return err
|
||||
sysSignal, err := signal.ParseSignal(killSignal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer server.Shutdown()
|
||||
err = server.Update()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not update list of containers")
|
||||
}
|
||||
var lastError error
|
||||
for _, container := range c.Args() {
|
||||
id, err := server.ContainerKill(container, sysSignal)
|
||||
if err != nil {
|
||||
if lastError != nil {
|
||||
fmt.Fprintln(os.Stderr, lastError)
|
||||
}
|
||||
lastError = errors.Wrapf(err, "unable to kill %v", container)
|
||||
} else {
|
||||
fmt.Println(id)
|
||||
}
|
||||
}
|
||||
return lastError
|
||||
}
|
107
cmd/kpod/load.go
107
cmd/kpod/load.go
|
@ -1,107 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/kubernetes-incubator/cri-o/libpod"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
loadFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "input, i",
|
||||
Usage: "Read from archive file, default is STDIN",
|
||||
Value: "/dev/stdin",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "quiet, q",
|
||||
Usage: "Suppress the output",
|
||||
},
|
||||
}
|
||||
loadDescription = "Loads the image from docker-archive stored on the local machine."
|
||||
loadCommand = cli.Command{
|
||||
Name: "load",
|
||||
Usage: "load an image from docker archive",
|
||||
Description: loadDescription,
|
||||
Flags: loadFlags,
|
||||
Action: loadCmd,
|
||||
ArgsUsage: "",
|
||||
}
|
||||
)
|
||||
|
||||
// loadCmd gets the image/file to be loaded from the command line
|
||||
// and calls loadImage to load the image to containers-storage
|
||||
func loadCmd(c *cli.Context) error {
|
||||
|
||||
args := c.Args()
|
||||
var image string
|
||||
if len(args) == 1 {
|
||||
image = args[0]
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return errors.New("too many arguments. Requires exactly 1")
|
||||
}
|
||||
if err := validateFlags(c, loadFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtime, err := getRuntime(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get runtime")
|
||||
}
|
||||
defer runtime.Shutdown(false)
|
||||
|
||||
input := c.String("input")
|
||||
|
||||
if input == "/dev/stdin" {
|
||||
fi, err := os.Stdin.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// checking if loading from pipe
|
||||
if !fi.Mode().IsRegular() {
|
||||
outFile, err := ioutil.TempFile("/var/tmp", "kpod")
|
||||
if err != nil {
|
||||
return errors.Errorf("error creating file %v", err)
|
||||
}
|
||||
defer outFile.Close()
|
||||
defer os.Remove(outFile.Name())
|
||||
|
||||
inFile, err := os.OpenFile(input, 0, 0666)
|
||||
if err != nil {
|
||||
return errors.Errorf("error reading file %v", err)
|
||||
}
|
||||
defer inFile.Close()
|
||||
|
||||
_, err = io.Copy(outFile, inFile)
|
||||
if err != nil {
|
||||
return errors.Errorf("error copying file %v", err)
|
||||
}
|
||||
|
||||
input = outFile.Name()
|
||||
}
|
||||
}
|
||||
|
||||
var output io.Writer
|
||||
if !c.Bool("quiet") {
|
||||
output = os.Stdout
|
||||
}
|
||||
|
||||
src := libpod.DockerArchive + ":" + input
|
||||
if err := runtime.PullImage(src, false, "", output); err != nil {
|
||||
src = libpod.OCIArchive + ":" + input
|
||||
// generate full src name with specified image:tag
|
||||
if image != "" {
|
||||
src = src + ":" + image
|
||||
}
|
||||
if err := runtime.PullImage(src, false, "", output); err != nil {
|
||||
return errors.Wrapf(err, "error pulling %q", src)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/docker"
|
||||
"github.com/containers/image/pkg/docker/config"
|
||||
"github.com/kubernetes-incubator/cri-o/libpod/common"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
var (
|
||||
loginFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "password, p",
|
||||
Usage: "Password for registry",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "username, u",
|
||||
Usage: "Username for registry",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "authfile",
|
||||
Usage: "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
|
||||
},
|
||||
}
|
||||
loginDescription = "Login to a container registry on a specified server."
|
||||
loginCommand = cli.Command{
|
||||
Name: "login",
|
||||
Usage: "login to a container registry",
|
||||
Description: loginDescription,
|
||||
Flags: loginFlags,
|
||||
Action: loginCmd,
|
||||
ArgsUsage: "REGISTRY",
|
||||
}
|
||||
)
|
||||
|
||||
// loginCmd uses the authentication package to store a user's authenticated credentials
|
||||
// in an auth.json file for future use
|
||||
func loginCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if len(args) > 1 {
|
||||
return errors.Errorf("too many arguments, login takes only 1 argument")
|
||||
}
|
||||
if len(args) == 0 {
|
||||
return errors.Errorf("registry must be given")
|
||||
}
|
||||
var server string
|
||||
if len(args) == 1 {
|
||||
server = args[0]
|
||||
}
|
||||
|
||||
sc := common.GetSystemContext("", c.String("authfile"))
|
||||
|
||||
// username of user logged in to server (if one exists)
|
||||
userFromAuthFile := config.GetUserLoggedIn(sc, server)
|
||||
username, password, err := getUserAndPass(c.String("username"), c.String("password"), userFromAuthFile)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error getting username and password")
|
||||
}
|
||||
|
||||
if err = docker.CheckAuth(context.TODO(), sc, username, password, server); err == nil {
|
||||
if err := config.SetAuthentication(sc, server, username, password); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
switch err {
|
||||
case nil:
|
||||
fmt.Println("Login Succeeded!")
|
||||
return nil
|
||||
case docker.ErrUnauthorizedForCredentials:
|
||||
return errors.Errorf("error logging into %q: invalid username/password\n", server)
|
||||
default:
|
||||
return errors.Wrapf(err, "error authenticating creds for %q", server)
|
||||
}
|
||||
}
|
||||
|
||||
// getUserAndPass gets the username and password from STDIN if not given
|
||||
// using the -u and -p flags
|
||||
func getUserAndPass(username, password, userFromAuthFile string) (string, string, error) {
|
||||
var err error
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
if username == "" {
|
||||
if userFromAuthFile != "" {
|
||||
fmt.Printf("Username (%s): ", userFromAuthFile)
|
||||
} else {
|
||||
fmt.Print("Username: ")
|
||||
}
|
||||
username, err = reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return "", "", errors.Wrapf(err, "error reading username")
|
||||
}
|
||||
}
|
||||
if password == "" {
|
||||
fmt.Print("Password: ")
|
||||
pass, err := terminal.ReadPassword(0)
|
||||
if err != nil {
|
||||
return "", "", errors.Wrapf(err, "error reading password")
|
||||
}
|
||||
password = string(pass)
|
||||
fmt.Println()
|
||||
}
|
||||
return strings.TrimSpace(username), password, err
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/containers/image/pkg/docker/config"
|
||||
"github.com/kubernetes-incubator/cri-o/libpod/common"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
logoutFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "authfile",
|
||||
Usage: "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "all, a",
|
||||
Usage: "Remove the cached credentials for all registries in the auth file",
|
||||
},
|
||||
}
|
||||
logoutDescription = "Remove the cached username and password for the registry."
|
||||
logoutCommand = cli.Command{
|
||||
Name: "logout",
|
||||
Usage: "logout of a container registry",
|
||||
Description: logoutDescription,
|
||||
Flags: logoutFlags,
|
||||
Action: logoutCmd,
|
||||
ArgsUsage: "REGISTRY",
|
||||
}
|
||||
)
|
||||
|
||||
// logoutCmd uses the authentication package to remove the authenticated of a registry
|
||||
// stored in the auth.json file
|
||||
func logoutCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if len(args) > 1 {
|
||||
return errors.Errorf("too many arguments, logout takes only 1 argument")
|
||||
}
|
||||
var server string
|
||||
if len(args) == 1 {
|
||||
server = args[0]
|
||||
}
|
||||
|
||||
sc := common.GetSystemContext("", c.String("authfile"))
|
||||
|
||||
if c.Bool("all") {
|
||||
if err := config.RemoveAllAuthentication(sc); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Remove login credentials for all registries")
|
||||
return nil
|
||||
}
|
||||
|
||||
err := config.RemoveAuthentication(sc, server)
|
||||
switch err {
|
||||
case nil:
|
||||
fmt.Printf("Remove login credentials for %s\n", server)
|
||||
return nil
|
||||
case config.ErrNotLoggedIn:
|
||||
return errors.Errorf("Not logged into %s\n", server)
|
||||
default:
|
||||
return errors.Wrapf(err, "error logging out of %q", server)
|
||||
}
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/kubernetes-incubator/cri-o/libkpod"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
logsFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "details",
|
||||
Usage: "Show extra details provided to the logs",
|
||||
Hidden: true,
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "follow, f",
|
||||
Usage: "Follow log output. The default is false",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "since",
|
||||
Usage: "Show logs since TIMESTAMP",
|
||||
},
|
||||
cli.Uint64Flag{
|
||||
Name: "tail",
|
||||
Usage: "Output the specified number of LINES at the end of the logs. Defaults to 0, which prints all lines",
|
||||
},
|
||||
}
|
||||
logsDescription = "The kpod logs command batch-retrieves whatever logs are present for a container at the time of execution. This does not guarantee execution" +
|
||||
"order when combined with kpod run (i.e. your run may not have generated any logs at the time you execute kpod logs"
|
||||
logsCommand = cli.Command{
|
||||
Name: "logs",
|
||||
Usage: "Fetch the logs of a container",
|
||||
Description: logsDescription,
|
||||
Flags: logsFlags,
|
||||
Action: logsCmd,
|
||||
ArgsUsage: "CONTAINER",
|
||||
}
|
||||
)
|
||||
|
||||
func logsCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if len(args) != 1 {
|
||||
return errors.Errorf("'kpod logs' requires exactly one container name/ID")
|
||||
}
|
||||
if err := validateFlags(c, logsFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
container := c.Args().First()
|
||||
var opts libkpod.LogOptions
|
||||
opts.Details = c.Bool("details")
|
||||
opts.Follow = c.Bool("follow")
|
||||
opts.SinceTime = time.Time{}
|
||||
if c.IsSet("since") {
|
||||
// parse time, error out if something is wrong
|
||||
since, err := time.Parse("2006-01-02T15:04:05.999999999-07:00", c.String("since"))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not parse time: %q", c.String("since"))
|
||||
}
|
||||
opts.SinceTime = since
|
||||
}
|
||||
opts.Tail = c.Uint64("tail")
|
||||
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get config")
|
||||
}
|
||||
server, err := libkpod.New(config)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not create container server")
|
||||
}
|
||||
defer server.Shutdown()
|
||||
err = server.Update()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not update list of containers")
|
||||
}
|
||||
logs := make(chan string)
|
||||
go func() {
|
||||
err = server.GetLogs(container, logs, opts)
|
||||
}()
|
||||
printLogs(logs)
|
||||
return err
|
||||
}
|
||||
|
||||
func printLogs(logs chan string) {
|
||||
for line := range logs {
|
||||
fmt.Println(line)
|
||||
}
|
||||
}
|
129
cmd/kpod/main.go
129
cmd/kpod/main.go
|
@ -1,129 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/containers/storage/pkg/reexec"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// This is populated by the Makefile from the VERSION file
|
||||
// in the repository
|
||||
var kpodVersion = ""
|
||||
|
||||
func main() {
|
||||
debug := false
|
||||
|
||||
if reexec.Init() {
|
||||
return
|
||||
}
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Name = "kpod"
|
||||
app.Usage = "manage pods and images"
|
||||
|
||||
var v string
|
||||
if kpodVersion != "" {
|
||||
v = kpodVersion
|
||||
}
|
||||
app.Version = v
|
||||
|
||||
app.Commands = []cli.Command{
|
||||
diffCommand,
|
||||
exportCommand,
|
||||
historyCommand,
|
||||
imagesCommand,
|
||||
infoCommand,
|
||||
inspectCommand,
|
||||
killCommand,
|
||||
loadCommand,
|
||||
loginCommand,
|
||||
logoutCommand,
|
||||
logsCommand,
|
||||
mountCommand,
|
||||
pauseCommand,
|
||||
psCommand,
|
||||
pullCommand,
|
||||
pushCommand,
|
||||
renameCommand,
|
||||
rmCommand,
|
||||
rmiCommand,
|
||||
saveCommand,
|
||||
statsCommand,
|
||||
stopCommand,
|
||||
tagCommand,
|
||||
umountCommand,
|
||||
unpauseCommand,
|
||||
versionCommand,
|
||||
waitCommand,
|
||||
}
|
||||
app.Before = func(c *cli.Context) error {
|
||||
logLevel := c.GlobalString("log-level")
|
||||
if logLevel != "" {
|
||||
level, err := logrus.ParseLevel(logLevel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logrus.SetLevel(level)
|
||||
}
|
||||
|
||||
if logLevel == "debug" {
|
||||
debug = true
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
app.After = func(*cli.Context) error {
|
||||
// called by Run() when the command handler succeeds
|
||||
shutdownStores()
|
||||
return nil
|
||||
}
|
||||
cli.OsExiter = func(code int) {
|
||||
// called by Run() when the command fails, bypassing After()
|
||||
shutdownStores()
|
||||
os.Exit(code)
|
||||
}
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "config, c",
|
||||
Usage: "path of a config file detailing container server configuration options",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "log-level",
|
||||
Usage: "log messages above specified level: debug, info, warn, error (default), fatal or panic",
|
||||
Value: "error",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "root",
|
||||
Usage: "path to the root directory in which data, including images, is stored",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "runroot",
|
||||
Usage: "path to the 'run directory' where all state information is stored",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "runtime",
|
||||
Usage: "path to the OCI-compatible binary used to run containers, default is /usr/bin/runc",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "storage-driver, s",
|
||||
Usage: "select which storage driver is used to manage storage of images and containers (default is overlay)",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "storage-opt",
|
||||
Usage: "used to pass an option to the storage driver",
|
||||
},
|
||||
}
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
if debug {
|
||||
logrus.Errorf(err.Error())
|
||||
} else {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
}
|
||||
cli.OsExiter(1)
|
||||
}
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
js "encoding/json"
|
||||
"fmt"
|
||||
|
||||
of "github.com/kubernetes-incubator/cri-o/cmd/kpod/formats"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
mountDescription = `
|
||||
kpod mount
|
||||
Lists all mounted containers mount points
|
||||
|
||||
kpod mount CONTAINER-NAME-OR-ID
|
||||
Mounts the specified container and outputs the mountpoint
|
||||
`
|
||||
|
||||
mountFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "notruncate",
|
||||
Usage: "do not truncate output",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "label",
|
||||
Usage: "SELinux label for the mount point",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "format",
|
||||
Usage: "Change the output format to Go template",
|
||||
},
|
||||
}
|
||||
mountCommand = cli.Command{
|
||||
Name: "mount",
|
||||
Usage: "Mount a working container's root filesystem",
|
||||
Description: mountDescription,
|
||||
Action: mountCmd,
|
||||
ArgsUsage: "[CONTAINER-NAME-OR-ID]",
|
||||
Flags: mountFlags,
|
||||
}
|
||||
)
|
||||
|
||||
// MountOutputParams stores info about each layer
|
||||
type jsonMountPoint struct {
|
||||
ID string `json:"id"`
|
||||
Names []string `json:"names"`
|
||||
MountPoint string `json:"mountpoint"`
|
||||
}
|
||||
|
||||
func mountCmd(c *cli.Context) error {
|
||||
formats := map[string]bool{
|
||||
"": true,
|
||||
of.JSONString: true,
|
||||
}
|
||||
|
||||
args := c.Args()
|
||||
json := c.String("format") == of.JSONString
|
||||
if !formats[c.String("format")] {
|
||||
return errors.Errorf("%q is not a supported format", c.String("format"))
|
||||
}
|
||||
|
||||
if len(args) > 1 {
|
||||
return errors.Errorf("too many arguments specified")
|
||||
}
|
||||
if err := validateFlags(c, mountFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not get config")
|
||||
}
|
||||
store, err := getStore(config)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error getting store")
|
||||
}
|
||||
if len(args) == 1 {
|
||||
if json {
|
||||
return errors.Wrapf(err, "json option can not be used with a container id")
|
||||
}
|
||||
mountPoint, err := store.Mount(args[0], c.String("label"))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error finding container %q", args[0])
|
||||
}
|
||||
fmt.Printf("%s\n", mountPoint)
|
||||
} else {
|
||||
jsonMountPoints := []jsonMountPoint{}
|
||||
containers, err2 := store.Containers()
|
||||
if err2 != nil {
|
||||
return errors.Wrapf(err2, "error reading list of all containers")
|
||||
}
|
||||
for _, container := range containers {
|
||||
layer, err := store.Layer(container.LayerID)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error finding layer %q for container %q", container.LayerID, container.ID)
|
||||
}
|
||||
if layer.MountPoint == "" {
|
||||
continue
|
||||
}
|
||||
if json {
|
||||
jsonMountPoints = append(jsonMountPoints, jsonMountPoint{ID: container.ID, Names: container.Names, MountPoint: layer.MountPoint})
|
||||
continue
|
||||
}
|
||||
|
||||
if c.Bool("notruncate") {
|
||||
fmt.Printf("%-64s %s\n", container.ID, layer.MountPoint)
|
||||
} else {
|
||||
fmt.Printf("%-12.12s %s\n", container.ID, layer.MountPoint)
|
||||
}
|
||||
}
|
||||
if json {
|
||||
data, err := js.MarshalIndent(jsonMountPoints, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s\n", data)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kubernetes-incubator/cri-o/libkpod"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
pauseDescription = `
|
||||
kpod pause
|
||||
|
||||
Pauses one or more running containers. The container name or ID can be used.
|
||||
`
|
||||
pauseCommand = cli.Command{
|
||||
Name: "pause",
|
||||
Usage: "Pauses all the processes in one or more containers",
|
||||
Description: pauseDescription,
|
||||
Action: pauseCmd,
|
||||
ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
|
||||
}
|
||||
)
|
||||
|
||||
func pauseCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if len(args) < 1 {
|
||||
return errors.Errorf("you must provide at least one container name or id")
|
||||
}
|
||||
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get config")
|
||||
}
|
||||
server, err := libkpod.New(config)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get container server")
|
||||
}
|
||||
defer server.Shutdown()
|
||||
if err := server.Update(); err != nil {
|
||||
return errors.Wrapf(err, "could not update list of containers")
|
||||
}
|
||||
var lastError error
|
||||
for _, container := range c.Args() {
|
||||
cid, err := server.ContainerPause(container)
|
||||
if err != nil {
|
||||
if lastError != nil {
|
||||
fmt.Fprintln(os.Stderr, lastError)
|
||||
}
|
||||
lastError = errors.Wrapf(err, "failed to pause container %v", container)
|
||||
} else {
|
||||
fmt.Println(cid)
|
||||
}
|
||||
}
|
||||
|
||||
return lastError
|
||||
}
|
663
cmd/kpod/ps.go
663
cmd/kpod/ps.go
|
@ -1,663 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
|
||||
"github.com/kubernetes-incubator/cri-o/cmd/kpod/formats"
|
||||
"github.com/kubernetes-incubator/cri-o/libkpod"
|
||||
"github.com/kubernetes-incubator/cri-o/oci"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
type psOptions struct {
|
||||
all bool
|
||||
filter string
|
||||
format string
|
||||
last int
|
||||
latest bool
|
||||
noTrunc bool
|
||||
quiet bool
|
||||
size bool
|
||||
label string
|
||||
namespace bool
|
||||
}
|
||||
|
||||
type psTemplateParams struct {
|
||||
ID string
|
||||
Image string
|
||||
Command string
|
||||
CreatedAt string
|
||||
RunningFor string
|
||||
Status string
|
||||
Ports string
|
||||
Size string
|
||||
Names string
|
||||
Labels string
|
||||
Mounts string
|
||||
PID int
|
||||
Cgroup string
|
||||
IPC string
|
||||
MNT string
|
||||
NET string
|
||||
PIDNS string
|
||||
User string
|
||||
UTS string
|
||||
}
|
||||
|
||||
// psJSONParams is only used when the JSON format is specified,
|
||||
// and is better for data processing from JSON.
|
||||
// psJSONParams will be populated by data from libkpod.ContainerData,
|
||||
// the members of the struct are the sama data types as their sources.
|
||||
type psJSONParams struct {
|
||||
ID string `json:"id"`
|
||||
Image string `json:"image"`
|
||||
ImageID string `json:"image_id"`
|
||||
Command string `json:"command"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
RunningFor time.Duration `json:"runningFor"`
|
||||
Status string `json:"status"`
|
||||
Ports map[string]struct{} `json:"ports"`
|
||||
Size uint `json:"size"`
|
||||
Names string `json:"names"`
|
||||
Labels fields.Set `json:"labels"`
|
||||
Mounts []specs.Mount `json:"mounts"`
|
||||
ContainerRunning bool `json:"ctrRunning"`
|
||||
Namespaces *namespace `json:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
type namespace struct {
|
||||
PID string `json:"pid,omitempty"`
|
||||
Cgroup string `json:"cgroup,omitempty"`
|
||||
IPC string `json:"ipc,omitempty"`
|
||||
MNT string `json:"mnt,omitempty"`
|
||||
NET string `json:"net,omitempty"`
|
||||
PIDNS string `json:"pidns,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
UTS string `json:"uts,omitempty"`
|
||||
}
|
||||
|
||||
var (
|
||||
psFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "all, a",
|
||||
Usage: "Show all the containers, default is only running containers",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "filter, f",
|
||||
Usage: "Filter output based on conditions given",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "format",
|
||||
Usage: "Pretty-print containers to JSON or using a Go template",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "last, n",
|
||||
Usage: "Print the n last created containers (all states)",
|
||||
Value: -1,
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "latest, l",
|
||||
Usage: "Show the latest container created (all states)",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "no-trunc",
|
||||
Usage: "Display the extended information",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "quiet, q",
|
||||
Usage: "Print the numeric IDs of the containers only",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "size, s",
|
||||
Usage: "Display the total file sizes",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "namespace, ns",
|
||||
Usage: "Display namespace information",
|
||||
},
|
||||
}
|
||||
psDescription = "Prints out information about the containers"
|
||||
psCommand = cli.Command{
|
||||
Name: "ps",
|
||||
Usage: "List containers",
|
||||
Description: psDescription,
|
||||
Flags: psFlags,
|
||||
Action: psCmd,
|
||||
ArgsUsage: "",
|
||||
}
|
||||
)
|
||||
|
||||
func psCmd(c *cli.Context) error {
|
||||
if err := validateFlags(c, psFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get config")
|
||||
}
|
||||
server, err := libkpod.New(config)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error creating server")
|
||||
}
|
||||
if err := server.Update(); err != nil {
|
||||
return errors.Wrapf(err, "error updating list of containers")
|
||||
}
|
||||
|
||||
if len(c.Args()) > 0 {
|
||||
return errors.Errorf("too many arguments, ps takes no arguments")
|
||||
}
|
||||
|
||||
format := genPsFormat(c.Bool("quiet"), c.Bool("size"), c.Bool("namespace"))
|
||||
if c.IsSet("format") {
|
||||
format = c.String("format")
|
||||
}
|
||||
|
||||
opts := psOptions{
|
||||
all: c.Bool("all"),
|
||||
filter: c.String("filter"),
|
||||
format: format,
|
||||
last: c.Int("last"),
|
||||
latest: c.Bool("latest"),
|
||||
noTrunc: c.Bool("no-trunc"),
|
||||
quiet: c.Bool("quiet"),
|
||||
size: c.Bool("size"),
|
||||
namespace: c.Bool("namespace"),
|
||||
}
|
||||
|
||||
// all, latest, and last are mutually exclusive. Only one flag can be used at a time
|
||||
exclusiveOpts := 0
|
||||
if opts.last >= 0 {
|
||||
exclusiveOpts++
|
||||
}
|
||||
if opts.latest {
|
||||
exclusiveOpts++
|
||||
}
|
||||
if opts.all {
|
||||
exclusiveOpts++
|
||||
}
|
||||
if exclusiveOpts > 1 {
|
||||
return errors.Errorf("Last, latest and all are mutually exclusive")
|
||||
}
|
||||
|
||||
containers, err := server.ListContainers()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error getting containers from server")
|
||||
}
|
||||
var params *FilterParamsPS
|
||||
if opts.filter != "" {
|
||||
params, err = parseFilter(opts.filter, containers)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error parsing filter")
|
||||
}
|
||||
} else {
|
||||
params = nil
|
||||
}
|
||||
|
||||
containerList := getContainersMatchingFilter(containers, params, server)
|
||||
|
||||
return generatePsOutput(containerList, server, opts)
|
||||
}
|
||||
|
||||
// generate the template based on conditions given
|
||||
func genPsFormat(quiet, size, namespace bool) (format string) {
|
||||
if quiet {
|
||||
return formats.IDString
|
||||
}
|
||||
if namespace {
|
||||
format = "table {{.ID}}\t{{.Names}}\t{{.PID}}\t{{.Cgroup}}\t{{.IPC}}\t{{.MNT}}\t{{.NET}}\t{{.PIDNS}}\t{{.User}}\t{{.UTS}}\t"
|
||||
return
|
||||
}
|
||||
format = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.CreatedAt}}\t{{.Status}}\t{{.Ports}}\t{{.Names}}\t"
|
||||
if size {
|
||||
format += "{{.Size}}\t"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func psToGeneric(templParams []psTemplateParams, JSONParams []psJSONParams) (genericParams []interface{}) {
|
||||
if len(templParams) > 0 {
|
||||
for _, v := range templParams {
|
||||
genericParams = append(genericParams, interface{}(v))
|
||||
}
|
||||
return
|
||||
}
|
||||
for _, v := range JSONParams {
|
||||
genericParams = append(genericParams, interface{}(v))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// generate the accurate header based on template given
|
||||
func (p *psTemplateParams) headerMap() map[string]string {
|
||||
v := reflect.Indirect(reflect.ValueOf(p))
|
||||
values := make(map[string]string)
|
||||
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
key := v.Type().Field(i).Name
|
||||
value := key
|
||||
if value == "ID" {
|
||||
value = "Container" + value
|
||||
}
|
||||
values[key] = strings.ToUpper(splitCamelCase(value))
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
// getContainers gets the containers that match the flags given
|
||||
func getContainers(containers []*libkpod.ContainerData, opts psOptions) []*libkpod.ContainerData {
|
||||
var containersOutput []*libkpod.ContainerData
|
||||
if opts.last >= 0 && opts.last < len(containers) {
|
||||
for i := 0; i < opts.last; i++ {
|
||||
containersOutput = append(containersOutput, containers[i])
|
||||
}
|
||||
return containersOutput
|
||||
}
|
||||
if opts.latest {
|
||||
return []*libkpod.ContainerData{containers[0]}
|
||||
}
|
||||
if opts.all || opts.last >= len(containers) {
|
||||
return containers
|
||||
}
|
||||
for _, ctr := range containers {
|
||||
if ctr.State.Status == oci.ContainerStateRunning {
|
||||
containersOutput = append(containersOutput, ctr)
|
||||
}
|
||||
}
|
||||
return containersOutput
|
||||
}
|
||||
|
||||
// getTemplateOutput returns the modified container information
|
||||
func getTemplateOutput(containers []*libkpod.ContainerData, opts psOptions) (psOutput []psTemplateParams) {
|
||||
var status string
|
||||
for _, ctr := range containers {
|
||||
ctrID := ctr.ID
|
||||
runningFor := units.HumanDuration(time.Since(ctr.State.Created))
|
||||
createdAt := runningFor + " ago"
|
||||
command := getStrFromSquareBrackets(ctr.ImageCreatedBy)
|
||||
imageName := ctr.FromImage
|
||||
mounts := getMounts(ctr.Mounts, opts.noTrunc)
|
||||
ports := getPorts(ctr.Config.ExposedPorts)
|
||||
size := units.HumanSize(float64(ctr.SizeRootFs))
|
||||
labels := getLabels(ctr.Labels)
|
||||
|
||||
ns := getNamespaces(ctr.State.Pid)
|
||||
|
||||
switch ctr.State.Status {
|
||||
case oci.ContainerStateStopped:
|
||||
status = "Exited (" + strconv.FormatInt(int64(ctr.State.ExitCode), 10) + ") " + runningFor + " ago"
|
||||
case oci.ContainerStateRunning:
|
||||
status = "Up " + runningFor + " ago"
|
||||
case oci.ContainerStatePaused:
|
||||
status = "Paused"
|
||||
default:
|
||||
status = "Created"
|
||||
}
|
||||
|
||||
if !opts.noTrunc {
|
||||
ctrID = ctr.ID[:idTruncLength]
|
||||
imageName = getImageName(ctr.FromImage)
|
||||
}
|
||||
|
||||
params := psTemplateParams{
|
||||
ID: ctrID,
|
||||
Image: imageName,
|
||||
Command: command,
|
||||
CreatedAt: createdAt,
|
||||
RunningFor: runningFor,
|
||||
Status: status,
|
||||
Ports: ports,
|
||||
Size: size,
|
||||
Names: ctr.Name,
|
||||
Labels: labels,
|
||||
Mounts: mounts,
|
||||
PID: ctr.State.Pid,
|
||||
Cgroup: ns.Cgroup,
|
||||
IPC: ns.IPC,
|
||||
MNT: ns.MNT,
|
||||
NET: ns.NET,
|
||||
PIDNS: ns.PID,
|
||||
User: ns.User,
|
||||
UTS: ns.UTS,
|
||||
}
|
||||
psOutput = append(psOutput, params)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getNamespaces(pid int) *namespace {
|
||||
ctrPID := strconv.Itoa(pid)
|
||||
cgroup, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "cgroup"))
|
||||
ipc, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "ipc"))
|
||||
mnt, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "mnt"))
|
||||
net, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "net"))
|
||||
pidns, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "pid"))
|
||||
user, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "user"))
|
||||
uts, _ := getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "uts"))
|
||||
|
||||
return &namespace{
|
||||
PID: ctrPID,
|
||||
Cgroup: cgroup,
|
||||
IPC: ipc,
|
||||
MNT: mnt,
|
||||
NET: net,
|
||||
PIDNS: pidns,
|
||||
User: user,
|
||||
UTS: uts,
|
||||
}
|
||||
}
|
||||
|
||||
func getNamespaceInfo(path string) (string, error) {
|
||||
val, err := os.Readlink(path)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "error getting info from %q", path)
|
||||
}
|
||||
return getStrFromSquareBrackets(val), nil
|
||||
}
|
||||
|
||||
// getJSONOutput returns the container info in its raw form
|
||||
func getJSONOutput(containers []*libkpod.ContainerData, nSpace bool) (psOutput []psJSONParams) {
|
||||
var ns *namespace
|
||||
for _, ctr := range containers {
|
||||
if nSpace {
|
||||
ns = getNamespaces(ctr.State.Pid)
|
||||
}
|
||||
|
||||
params := psJSONParams{
|
||||
ID: ctr.ID,
|
||||
Image: ctr.FromImage,
|
||||
ImageID: ctr.FromImageID,
|
||||
Command: getStrFromSquareBrackets(ctr.ImageCreatedBy),
|
||||
CreatedAt: ctr.State.Created,
|
||||
RunningFor: time.Since(ctr.State.Created),
|
||||
Status: ctr.State.Status,
|
||||
Ports: ctr.Config.ExposedPorts,
|
||||
Size: ctr.SizeRootFs,
|
||||
Names: ctr.Name,
|
||||
Labels: ctr.Labels,
|
||||
Mounts: ctr.Mounts,
|
||||
ContainerRunning: ctr.State.Status == oci.ContainerStateRunning,
|
||||
Namespaces: ns,
|
||||
}
|
||||
psOutput = append(psOutput, params)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func generatePsOutput(containers []*libkpod.ContainerData, server *libkpod.ContainerServer, opts psOptions) error {
|
||||
containersOutput := getContainers(containers, opts)
|
||||
if len(containersOutput) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var out formats.Writer
|
||||
|
||||
switch opts.format {
|
||||
case formats.JSONString:
|
||||
psOutput := getJSONOutput(containersOutput, opts.namespace)
|
||||
out = formats.JSONStructArray{Output: psToGeneric([]psTemplateParams{}, psOutput)}
|
||||
default:
|
||||
psOutput := getTemplateOutput(containersOutput, opts)
|
||||
out = formats.StdoutTemplateArray{Output: psToGeneric(psOutput, []psJSONParams{}), Template: opts.format, Fields: psOutput[0].headerMap()}
|
||||
}
|
||||
|
||||
return formats.Writer(out).Out()
|
||||
}
|
||||
|
||||
// getStrFromSquareBrackets gets the string inside [] from a string
|
||||
func getStrFromSquareBrackets(cmd string) string {
|
||||
reg, err := regexp.Compile(".*\\[|\\].*")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
arr := strings.Split(reg.ReplaceAllLiteralString(cmd, ""), ",")
|
||||
return strings.Join(arr, ",")
|
||||
}
|
||||
|
||||
// getImageName shortens the image name
|
||||
func getImageName(img string) string {
|
||||
arr := strings.Split(img, "/")
|
||||
if arr[0] == "docker.io" && arr[1] == "library" {
|
||||
img = strings.Join(arr[2:], "/")
|
||||
} else if arr[0] == "docker.io" {
|
||||
img = strings.Join(arr[1:], "/")
|
||||
}
|
||||
return img
|
||||
}
|
||||
|
||||
// getLabels converts the labels to a string of the form "key=value, key2=value2"
|
||||
func getLabels(labels fields.Set) string {
|
||||
var arr []string
|
||||
if len(labels) > 0 {
|
||||
for key, val := range labels {
|
||||
temp := key + "=" + val
|
||||
arr = append(arr, temp)
|
||||
}
|
||||
return strings.Join(arr, ",")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// getMounts converts the volumes mounted to a string of the form "mount1, mount2"
|
||||
// it truncates it if noTrunc is false
|
||||
func getMounts(mounts []specs.Mount, noTrunc bool) string {
|
||||
var arr []string
|
||||
if len(mounts) == 0 {
|
||||
return ""
|
||||
}
|
||||
for _, mount := range mounts {
|
||||
if noTrunc {
|
||||
arr = append(arr, mount.Source)
|
||||
continue
|
||||
}
|
||||
tempArr := strings.SplitAfter(mount.Source, "/")
|
||||
if len(tempArr) >= 3 {
|
||||
arr = append(arr, strings.Join(tempArr[:3], ""))
|
||||
} else {
|
||||
arr = append(arr, mount.Source)
|
||||
}
|
||||
}
|
||||
return strings.Join(arr, ",")
|
||||
}
|
||||
|
||||
// getPorts converts the ports used to a string of the from "port1, port2"
|
||||
func getPorts(ports map[string]struct{}) string {
|
||||
var arr []string
|
||||
if len(ports) == 0 {
|
||||
return ""
|
||||
}
|
||||
for key := range ports {
|
||||
arr = append(arr, key)
|
||||
}
|
||||
return strings.Join(arr, ",")
|
||||
}
|
||||
|
||||
// FilterParamsPS contains the filter options for ps
|
||||
type FilterParamsPS struct {
|
||||
id string
|
||||
label string
|
||||
name string
|
||||
exited int32
|
||||
status string
|
||||
ancestor string
|
||||
before time.Time
|
||||
since time.Time
|
||||
volume string
|
||||
}
|
||||
|
||||
// parseFilter takes a filter string and a list of containers and filters it
|
||||
func parseFilter(filter string, containers []*oci.Container) (*FilterParamsPS, error) {
|
||||
params := new(FilterParamsPS)
|
||||
allFilters := strings.Split(filter, ",")
|
||||
|
||||
for _, param := range allFilters {
|
||||
pair := strings.SplitN(param, "=", 2)
|
||||
switch strings.TrimSpace(pair[0]) {
|
||||
case "id":
|
||||
params.id = pair[1]
|
||||
case "label":
|
||||
params.label = pair[1]
|
||||
case "name":
|
||||
params.name = pair[1]
|
||||
case "exited":
|
||||
exitedCode, err := strconv.ParseInt(pair[1], 10, 32)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("exited code out of range %q", pair[1])
|
||||
}
|
||||
params.exited = int32(exitedCode)
|
||||
case "status":
|
||||
params.status = pair[1]
|
||||
case "ancestor":
|
||||
params.ancestor = pair[1]
|
||||
case "before":
|
||||
if ctr, err := findContainer(containers, pair[1]); err == nil {
|
||||
params.before = ctr.CreatedAt()
|
||||
} else {
|
||||
return nil, errors.Wrapf(err, "no such container %q", pair[1])
|
||||
}
|
||||
case "since":
|
||||
if ctr, err := findContainer(containers, pair[1]); err == nil {
|
||||
params.before = ctr.CreatedAt()
|
||||
} else {
|
||||
return nil, errors.Wrapf(err, "no such container %q", pair[1])
|
||||
}
|
||||
case "volume":
|
||||
params.volume = pair[1]
|
||||
default:
|
||||
return nil, errors.Errorf("invalid filter %q", pair[0])
|
||||
}
|
||||
}
|
||||
return params, nil
|
||||
}
|
||||
|
||||
// findContainer finds a container with a specific name or id from a list of containers
|
||||
func findContainer(containers []*oci.Container, ref string) (*oci.Container, error) {
|
||||
for _, ctr := range containers {
|
||||
if strings.HasPrefix(ctr.ID(), ref) || ctr.Name() == ref {
|
||||
return ctr, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.Errorf("could not find container")
|
||||
}
|
||||
|
||||
// matchesFilter checks if a container matches all the filter parameters
|
||||
func matchesFilter(ctrData *libkpod.ContainerData, params *FilterParamsPS) bool {
|
||||
if params == nil {
|
||||
return true
|
||||
}
|
||||
if params.id != "" && !matchesID(ctrData, params.id) {
|
||||
return false
|
||||
}
|
||||
if params.name != "" && !matchesName(ctrData, params.name) {
|
||||
return false
|
||||
}
|
||||
if !params.before.IsZero() && !matchesBeforeContainer(ctrData, params.before) {
|
||||
return false
|
||||
}
|
||||
if !params.since.IsZero() && !matchesSinceContainer(ctrData, params.since) {
|
||||
return false
|
||||
}
|
||||
if params.exited > 0 && !matchesExited(ctrData, params.exited) {
|
||||
return false
|
||||
}
|
||||
if params.status != "" && !matchesStatus(ctrData, params.status) {
|
||||
return false
|
||||
}
|
||||
if params.ancestor != "" && !matchesAncestor(ctrData, params.ancestor) {
|
||||
return false
|
||||
}
|
||||
if params.label != "" && !matchesLabel(ctrData, params.label) {
|
||||
return false
|
||||
}
|
||||
if params.volume != "" && !matchesVolume(ctrData, params.volume) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// GetContainersMatchingFilter returns a slice of all the containers that match the provided filter parameters
|
||||
func getContainersMatchingFilter(containers []*oci.Container, filter *FilterParamsPS, server *libkpod.ContainerServer) []*libkpod.ContainerData {
|
||||
var filteredCtrs []*libkpod.ContainerData
|
||||
for _, ctr := range containers {
|
||||
ctrData, err := server.GetContainerData(ctr.ID(), true)
|
||||
if err != nil {
|
||||
logrus.Warn("unable to get container data for matched container")
|
||||
}
|
||||
if filter == nil || matchesFilter(ctrData, filter) {
|
||||
filteredCtrs = append(filteredCtrs, ctrData)
|
||||
}
|
||||
}
|
||||
return filteredCtrs
|
||||
}
|
||||
|
||||
// matchesID returns true if the id's match
|
||||
func matchesID(ctrData *libkpod.ContainerData, id string) bool {
|
||||
return strings.HasPrefix(ctrData.ID, id)
|
||||
}
|
||||
|
||||
// matchesBeforeContainer returns true if the container was created before the filter image
|
||||
func matchesBeforeContainer(ctrData *libkpod.ContainerData, beforeTime time.Time) bool {
|
||||
return ctrData.State.Created.Before(beforeTime)
|
||||
}
|
||||
|
||||
// matchesSincecontainer returns true if the container was created since the filter image
|
||||
func matchesSinceContainer(ctrData *libkpod.ContainerData, sinceTime time.Time) bool {
|
||||
return ctrData.State.Created.After(sinceTime)
|
||||
}
|
||||
|
||||
// matchesLabel returns true if the container label matches that of the filter label
|
||||
func matchesLabel(ctrData *libkpod.ContainerData, label string) bool {
|
||||
pair := strings.SplitN(label, "=", 2)
|
||||
if val, ok := ctrData.Labels[pair[0]]; ok {
|
||||
if len(pair) == 2 && val == pair[1] {
|
||||
return true
|
||||
}
|
||||
if len(pair) == 1 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// matchesName returns true if the names are identical
|
||||
func matchesName(ctrData *libkpod.ContainerData, name string) bool {
|
||||
return ctrData.Name == name
|
||||
}
|
||||
|
||||
// matchesExited returns true if the exit codes are identical
|
||||
func matchesExited(ctrData *libkpod.ContainerData, exited int32) bool {
|
||||
return ctrData.State.ExitCode == exited
|
||||
}
|
||||
|
||||
// matchesStatus returns true if the container status matches that of filter status
|
||||
func matchesStatus(ctrData *libkpod.ContainerData, status string) bool {
|
||||
return ctrData.State.Status == status
|
||||
}
|
||||
|
||||
// matchesAncestor returns true if filter ancestor is in container image name
|
||||
func matchesAncestor(ctrData *libkpod.ContainerData, ancestor string) bool {
|
||||
return strings.Contains(ctrData.FromImage, ancestor)
|
||||
}
|
||||
|
||||
// matchesVolue returns true if the volume mounted or path to volue of the container matches that of filter volume
|
||||
func matchesVolume(ctrData *libkpod.ContainerData, volume string) bool {
|
||||
for _, vol := range ctrData.Mounts {
|
||||
if strings.Contains(vol.Source, volume) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
163
cmd/kpod/pull.go
163
cmd/kpod/pull.go
|
@ -1,163 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"fmt"
|
||||
|
||||
"github.com/containers/image/docker/reference"
|
||||
"github.com/containers/image/pkg/sysregistries"
|
||||
"github.com/containers/image/transports/alltransports"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
pullFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
// all-tags is hidden since it has not been implemented yet
|
||||
Name: "all-tags, a",
|
||||
Hidden: true,
|
||||
Usage: "Download all tagged images in the repository",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "signature-policy",
|
||||
Usage: "`pathname` of signature policy file (not usually used)",
|
||||
Hidden: true,
|
||||
},
|
||||
}
|
||||
|
||||
pullDescription = "Pulls an image from a registry and stores it locally.\n" +
|
||||
"An image can be pulled using its tag or digest. If a tag is not\n" +
|
||||
"specified, the image with the 'latest' tag (if it exists) is pulled."
|
||||
pullCommand = cli.Command{
|
||||
Name: "pull",
|
||||
Usage: "pull an image from a registry",
|
||||
Description: pullDescription,
|
||||
Flags: pullFlags,
|
||||
Action: pullCmd,
|
||||
ArgsUsage: "",
|
||||
}
|
||||
)
|
||||
|
||||
// struct for when a user passes a short or incomplete
|
||||
// image name
|
||||
type imagePullStruct struct {
|
||||
imageName string
|
||||
tag string
|
||||
registry string
|
||||
hasRegistry bool
|
||||
transport string
|
||||
}
|
||||
|
||||
func (ips imagePullStruct) returnFQName() string {
|
||||
return fmt.Sprintf("%s%s/%s:%s", ips.transport, ips.registry, ips.imageName, ips.tag)
|
||||
}
|
||||
|
||||
func getRegistriesToTry(image string) ([]string, error) {
|
||||
var registries []string
|
||||
var imageError = fmt.Sprintf("unable to parse '%s'\n", image)
|
||||
imgRef, err := reference.Parse(image)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, imageError)
|
||||
}
|
||||
tagged, isTagged := imgRef.(reference.NamedTagged)
|
||||
tag := "latest"
|
||||
if isTagged {
|
||||
tag = tagged.Tag()
|
||||
}
|
||||
hasDomain := true
|
||||
registry := reference.Domain(imgRef.(reference.Named))
|
||||
if registry == "" {
|
||||
hasDomain = false
|
||||
}
|
||||
imageName := reference.Path(imgRef.(reference.Named))
|
||||
pImage := imagePullStruct{
|
||||
imageName,
|
||||
tag,
|
||||
registry,
|
||||
hasDomain,
|
||||
"docker://",
|
||||
}
|
||||
if pImage.hasRegistry {
|
||||
// If input has a registry, we have to assume they included an image
|
||||
// name but maybe not a tag
|
||||
pullRef, err := alltransports.ParseImageName(pImage.returnFQName())
|
||||
if err != nil {
|
||||
return nil, errors.Errorf(imageError)
|
||||
}
|
||||
registries = append(registries, pullRef.DockerReference().String())
|
||||
} else {
|
||||
// No registry means we check the globals registries configuration file
|
||||
// and assemble a list of candidate sources to try
|
||||
registryConfigPath := ""
|
||||
envOverride := os.Getenv("REGISTRIES_CONFIG_PATH")
|
||||
if len(envOverride) > 0 {
|
||||
registryConfigPath = envOverride
|
||||
}
|
||||
searchRegistries, err := sysregistries.GetRegistries(&types.SystemContext{SystemRegistriesConfPath: registryConfigPath})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, errors.Errorf("unable to parse the registries.conf file and"+
|
||||
" the image name '%s' is incomplete.", imageName)
|
||||
}
|
||||
for _, searchRegistry := range searchRegistries {
|
||||
pImage.registry = searchRegistry
|
||||
pullRef, err := alltransports.ParseImageName(pImage.returnFQName())
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("unable to parse '%s'", pImage.returnFQName())
|
||||
}
|
||||
registries = append(registries, pullRef.DockerReference().String())
|
||||
}
|
||||
}
|
||||
return registries, nil
|
||||
}
|
||||
|
||||
// pullCmd gets the data from the command line and calls pullImage
|
||||
// to copy an image from a registry to a local machine
|
||||
func pullCmd(c *cli.Context) error {
|
||||
var fqRegistries []string
|
||||
|
||||
args := c.Args()
|
||||
if len(args) == 0 {
|
||||
logrus.Errorf("an image name must be specified")
|
||||
return nil
|
||||
}
|
||||
if len(args) > 1 {
|
||||
logrus.Errorf("too many arguments. Requires exactly 1")
|
||||
return nil
|
||||
}
|
||||
if err := validateFlags(c, pullFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
image := args[0]
|
||||
srcRef, err := alltransports.ParseImageName(image)
|
||||
if err != nil {
|
||||
fqRegistries, err = getRegistriesToTry(image)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
} else {
|
||||
fqRegistries = append(fqRegistries, srcRef.DockerReference().String())
|
||||
}
|
||||
runtime, err := getRuntime(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get runtime")
|
||||
}
|
||||
defer runtime.Shutdown(false)
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not create runtime")
|
||||
}
|
||||
for _, fqname := range fqRegistries {
|
||||
fmt.Printf("Trying to pull %s...", fqname)
|
||||
if err := runtime.PullImage(fqname, c.Bool("all-tags"), c.String("signature-policy"), os.Stdout); err != nil {
|
||||
fmt.Printf(" Failed\n")
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.Errorf("error pulling image from %q", image)
|
||||
}
|
126
cmd/kpod/push.go
126
cmd/kpod/push.go
|
@ -1,126 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/containers/image/types"
|
||||
"github.com/containers/storage/pkg/archive"
|
||||
"github.com/kubernetes-incubator/cri-o/libpod"
|
||||
"github.com/kubernetes-incubator/cri-o/libpod/common"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
var (
|
||||
pushFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "signature-policy",
|
||||
Usage: "`pathname` of signature policy file (not usually used)",
|
||||
Hidden: true,
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "creds",
|
||||
Usage: "`credentials` (USERNAME:PASSWORD) to use for authenticating to a registry",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "cert-dir",
|
||||
Usage: "`pathname` of a directory containing TLS certificates and keys",
|
||||
},
|
||||
cli.BoolTFlag{
|
||||
Name: "tls-verify",
|
||||
Usage: "require HTTPS and verify certificates when contacting registries (default: true)",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "remove-signatures",
|
||||
Usage: "discard any pre-existing signatures in the image",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "sign-by",
|
||||
Usage: "add a signature at the destination using the specified key",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "quiet, q",
|
||||
Usage: "don't output progress information when pushing images",
|
||||
},
|
||||
}
|
||||
pushDescription = fmt.Sprintf(`
|
||||
Pushes an image to a specified location.
|
||||
The Image "DESTINATION" uses a "transport":"details" format.
|
||||
See kpod-push(1) section "DESTINATION" for the expected format`)
|
||||
|
||||
pushCommand = cli.Command{
|
||||
Name: "push",
|
||||
Usage: "push an image to a specified destination",
|
||||
Description: pushDescription,
|
||||
Flags: pushFlags,
|
||||
Action: pushCmd,
|
||||
ArgsUsage: "IMAGE DESTINATION",
|
||||
}
|
||||
)
|
||||
|
||||
func pushCmd(c *cli.Context) error {
|
||||
var registryCreds *types.DockerAuthConfig
|
||||
|
||||
args := c.Args()
|
||||
if len(args) < 2 {
|
||||
return errors.New("kpod push requires exactly 2 arguments")
|
||||
}
|
||||
if err := validateFlags(c, pushFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
srcName := c.Args().Get(0)
|
||||
destName := c.Args().Get(1)
|
||||
|
||||
registryCredsString := c.String("creds")
|
||||
certPath := c.String("cert-dir")
|
||||
skipVerify := !c.BoolT("tls-verify")
|
||||
removeSignatures := c.Bool("remove-signatures")
|
||||
signBy := c.String("sign-by")
|
||||
|
||||
if registryCredsString != "" {
|
||||
creds, err := common.ParseRegistryCreds(registryCredsString)
|
||||
if err != nil {
|
||||
if err == common.ErrNoPassword {
|
||||
fmt.Print("Password: ")
|
||||
password, err := terminal.ReadPassword(0)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not read password from terminal")
|
||||
}
|
||||
creds.Password = string(password)
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
registryCreds = creds
|
||||
}
|
||||
|
||||
runtime, err := getRuntime(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not create runtime")
|
||||
}
|
||||
defer runtime.Shutdown(false)
|
||||
|
||||
var writer io.Writer
|
||||
if !c.Bool("quiet") {
|
||||
writer = os.Stdout
|
||||
}
|
||||
|
||||
options := libpod.CopyOptions{
|
||||
Compression: archive.Uncompressed,
|
||||
SignaturePolicyPath: c.String("signature-policy"),
|
||||
DockerRegistryOptions: common.DockerRegistryOptions{
|
||||
DockerRegistryCreds: registryCreds,
|
||||
DockerCertPath: certPath,
|
||||
DockerInsecureSkipTLSVerify: skipVerify,
|
||||
},
|
||||
SigningOptions: common.SigningOptions{
|
||||
RemoveSignatures: removeSignatures,
|
||||
SignBy: signBy,
|
||||
},
|
||||
}
|
||||
|
||||
return runtime.PushImage(srcName, destName, options, writer)
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/kubernetes-incubator/cri-o/libkpod"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
renameDescription = "Rename a container. Container may be created, running, paused, or stopped"
|
||||
renameFlags = []cli.Flag{}
|
||||
renameCommand = cli.Command{
|
||||
Name: "rename",
|
||||
Usage: "rename a container",
|
||||
Description: renameDescription,
|
||||
Action: renameCmd,
|
||||
ArgsUsage: "CONTAINER NEW-NAME",
|
||||
Flags: renameFlags,
|
||||
}
|
||||
)
|
||||
|
||||
func renameCmd(c *cli.Context) error {
|
||||
if len(c.Args()) != 2 {
|
||||
return errors.Errorf("Rename requires a src container name/ID and a dest container name")
|
||||
}
|
||||
if err := validateFlags(c, renameFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not get config")
|
||||
}
|
||||
server, err := libkpod.New(config)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get container server")
|
||||
}
|
||||
defer server.Shutdown()
|
||||
err = server.Update()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not update list of containers")
|
||||
}
|
||||
|
||||
err = server.ContainerRename(c.Args().Get(0), c.Args().Get(1))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not rename container")
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/kubernetes-incubator/cri-o/libkpod"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
rmFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "force, f",
|
||||
Usage: "Force removal of a running container. The default is false",
|
||||
},
|
||||
}
|
||||
rmDescription = "Remove one or more containers"
|
||||
rmCommand = cli.Command{
|
||||
Name: "rm",
|
||||
Usage: fmt.Sprintf(`kpod rm will remove one or more containers from the host. The container name or ID can be used.
|
||||
This does not remove images. Running containers will not be removed without the -f option.`),
|
||||
Description: rmDescription,
|
||||
Flags: rmFlags,
|
||||
Action: rmCmd,
|
||||
ArgsUsage: "",
|
||||
}
|
||||
)
|
||||
|
||||
// saveCmd saves the image to either docker-archive or oci
|
||||
func rmCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if len(args) == 0 {
|
||||
return errors.Errorf("specify one or more containers to remove")
|
||||
}
|
||||
if err := validateFlags(c, rmFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get config")
|
||||
}
|
||||
server, err := libkpod.New(config)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get container server")
|
||||
}
|
||||
defer server.Shutdown()
|
||||
err = server.Update()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not update list of containers")
|
||||
}
|
||||
force := c.Bool("force")
|
||||
|
||||
for _, container := range c.Args() {
|
||||
id, err2 := server.Remove(container, force)
|
||||
if err2 != nil {
|
||||
if err == nil {
|
||||
err = err2
|
||||
} else {
|
||||
err = errors.Wrapf(err, "%v. Stop the container before attempting removal or use -f\n", err2)
|
||||
}
|
||||
} else {
|
||||
fmt.Println(id)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
rmiDescription = "removes one or more locally stored images."
|
||||
rmiFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "force, f",
|
||||
Usage: "force removal of the image",
|
||||
},
|
||||
}
|
||||
rmiCommand = cli.Command{
|
||||
Name: "rmi",
|
||||
Usage: "removes one or more images from local storage",
|
||||
Description: rmiDescription,
|
||||
Action: rmiCmd,
|
||||
ArgsUsage: "IMAGE-NAME-OR-ID [...]",
|
||||
Flags: rmiFlags,
|
||||
}
|
||||
)
|
||||
|
||||
func rmiCmd(c *cli.Context) error {
|
||||
if err := validateFlags(c, rmiFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtime, err := getRuntime(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get runtime")
|
||||
}
|
||||
defer runtime.Shutdown(false)
|
||||
|
||||
args := c.Args()
|
||||
if len(args) == 0 {
|
||||
return errors.Errorf("image name or ID must be specified")
|
||||
}
|
||||
|
||||
for _, arg := range args {
|
||||
image, err := runtime.GetImage(arg)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get image %q", arg)
|
||||
}
|
||||
id, err := runtime.RemoveImage(image, c.Bool("force"))
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error removing image %q", id)
|
||||
}
|
||||
fmt.Printf("%s\n", id)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/kubernetes-incubator/cri-o/libpod"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
saveFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "output, o",
|
||||
Usage: "Write to a file, default is STDOUT",
|
||||
Value: "/dev/stdout",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "quiet, q",
|
||||
Usage: "Suppress the output",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "format",
|
||||
Usage: "Save image to oci-archive",
|
||||
},
|
||||
}
|
||||
saveDescription = `
|
||||
Save an image to docker-archive or oci-archive on the local machine.
|
||||
Default is docker-archive`
|
||||
|
||||
saveCommand = cli.Command{
|
||||
Name: "save",
|
||||
Usage: "Save image to an archive",
|
||||
Description: saveDescription,
|
||||
Flags: saveFlags,
|
||||
Action: saveCmd,
|
||||
ArgsUsage: "",
|
||||
}
|
||||
)
|
||||
|
||||
// saveCmd saves the image to either docker-archive or oci
|
||||
func saveCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if len(args) == 0 {
|
||||
return errors.Errorf("need at least 1 argument")
|
||||
}
|
||||
if err := validateFlags(c, saveFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runtime, err := getRuntime(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not create runtime")
|
||||
}
|
||||
defer runtime.Shutdown(false)
|
||||
|
||||
var writer io.Writer
|
||||
if !c.Bool("quiet") {
|
||||
writer = os.Stdout
|
||||
}
|
||||
|
||||
output := c.String("output")
|
||||
if output == "/dev/stdout" {
|
||||
fi := os.Stdout
|
||||
if logrus.IsTerminal(fi) {
|
||||
return errors.Errorf("refusing to save to terminal. Use -o flag or redirect")
|
||||
}
|
||||
}
|
||||
|
||||
var dst string
|
||||
switch c.String("format") {
|
||||
case libpod.OCIArchive:
|
||||
dst = libpod.OCIArchive + ":" + output
|
||||
case libpod.DockerArchive:
|
||||
fallthrough
|
||||
case "":
|
||||
dst = libpod.DockerArchive + ":" + output
|
||||
default:
|
||||
return errors.Errorf("unknown format option %q", c.String("format"))
|
||||
}
|
||||
|
||||
saveOpts := libpod.CopyOptions{
|
||||
SignaturePolicyPath: "",
|
||||
}
|
||||
|
||||
// only one image is supported for now
|
||||
// future pull requests will fix this
|
||||
for _, image := range args {
|
||||
dest := dst + ":" + image
|
||||
if err := runtime.PushImage(image, dest, saveOpts, writer); err != nil {
|
||||
return errors.Wrapf(err, "unable to save %q", image)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,245 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
|
||||
tm "github.com/buger/goterm"
|
||||
"github.com/kubernetes-incubator/cri-o/libkpod"
|
||||
"github.com/kubernetes-incubator/cri-o/oci"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var printf func(format string, a ...interface{}) (n int, err error)
|
||||
var println func(a ...interface{}) (n int, err error)
|
||||
|
||||
type statsOutputParams struct {
|
||||
Container string
|
||||
ID string
|
||||
CPUPerc string
|
||||
MemUsage string
|
||||
MemPerc string
|
||||
NetIO string
|
||||
BlockIO string
|
||||
PIDs uint64
|
||||
}
|
||||
|
||||
var (
|
||||
statsFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "all, a",
|
||||
Usage: "show all containers. Only running containers are shown by default. The default is false",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "no-stream",
|
||||
Usage: "disable streaming stats and only pull the first result, default setting is false",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "format",
|
||||
Usage: "pretty-print container statistics using a Go template",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "json",
|
||||
Usage: "output container statistics in json format",
|
||||
},
|
||||
}
|
||||
|
||||
statsDescription = "display a live stream of one or more containers' resource usage statistics"
|
||||
statsCommand = cli.Command{
|
||||
Name: "stats",
|
||||
Usage: "Display percentage of CPU, memory, network I/O, block I/O and PIDs for one or more containers",
|
||||
Description: statsDescription,
|
||||
Flags: statsFlags,
|
||||
Action: statsCmd,
|
||||
ArgsUsage: "",
|
||||
}
|
||||
)
|
||||
|
||||
func statsCmd(c *cli.Context) error {
|
||||
if err := validateFlags(c, statsFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not read config")
|
||||
}
|
||||
containerServer, err := libkpod.New(config)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not create container server")
|
||||
}
|
||||
defer containerServer.Shutdown()
|
||||
err = containerServer.Update()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not update list of containers")
|
||||
}
|
||||
times := -1
|
||||
if c.Bool("no-stream") {
|
||||
times = 1
|
||||
}
|
||||
statsChan := make(chan []*libkpod.ContainerStats)
|
||||
// iterate over the channel until it is closed
|
||||
go func() {
|
||||
// print using goterm
|
||||
printf = tm.Printf
|
||||
println = tm.Println
|
||||
for stats := range statsChan {
|
||||
// Continually refresh statistics
|
||||
tm.Clear()
|
||||
tm.MoveCursor(1, 1)
|
||||
outputStats(stats, c.String("format"), c.Bool("json"))
|
||||
tm.Flush()
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}()
|
||||
return getStats(containerServer, c.Args(), c.Bool("all"), statsChan, times)
|
||||
}
|
||||
|
||||
func getStats(server *libkpod.ContainerServer, args []string, all bool, statsChan chan []*libkpod.ContainerStats, times int) error {
|
||||
ctrs, err := server.ListContainers(isRunning, ctrInList(args))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
containerStats := map[string]*libkpod.ContainerStats{}
|
||||
for _, ctr := range ctrs {
|
||||
initialStats, err := server.GetContainerStats(ctr, &libkpod.ContainerStats{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
containerStats[ctr.ID()] = initialStats
|
||||
}
|
||||
step := 1
|
||||
if times == -1 {
|
||||
times = 1
|
||||
step = 0
|
||||
}
|
||||
for i := 0; i < times; i += step {
|
||||
reportStats := []*libkpod.ContainerStats{}
|
||||
for _, ctr := range ctrs {
|
||||
id := ctr.ID()
|
||||
if _, ok := containerStats[ctr.ID()]; !ok {
|
||||
initialStats, err := server.GetContainerStats(ctr, &libkpod.ContainerStats{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
containerStats[id] = initialStats
|
||||
}
|
||||
stats, err := server.GetContainerStats(ctr, containerStats[id])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// replace the previous measurement with the current one
|
||||
containerStats[id] = stats
|
||||
reportStats = append(reportStats, stats)
|
||||
}
|
||||
statsChan <- reportStats
|
||||
|
||||
err := server.Update()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctrs, err = server.ListContainers(isRunning, ctrInList(args))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func outputStats(stats []*libkpod.ContainerStats, format string, json bool) error {
|
||||
if format == "" {
|
||||
outputStatsHeader()
|
||||
}
|
||||
if json {
|
||||
return outputStatsAsJSON(stats)
|
||||
}
|
||||
var err error
|
||||
for _, s := range stats {
|
||||
if format == "" {
|
||||
outputStatsUsingFormatString(s)
|
||||
} else {
|
||||
params := getStatsOutputParams(s)
|
||||
err2 := outputStatsUsingTemplate(format, params)
|
||||
if err2 != nil {
|
||||
err = errors.Wrapf(err, err2.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func outputStatsHeader() {
|
||||
printf("%-64s %-16s %-32s %-16s %-24s %-24s %s\n", "CONTAINER", "CPU %", "MEM USAGE / MEM LIMIT", "MEM %", "NET I/O", "BLOCK I/O", "PIDS")
|
||||
}
|
||||
|
||||
func outputStatsUsingFormatString(stats *libkpod.ContainerStats) {
|
||||
printf("%-64s %-16s %-32s %-16s %-24s %-24s %d\n", stats.Container, floatToPercentString(stats.CPU), combineHumanValues(stats.MemUsage, stats.MemLimit), floatToPercentString(stats.MemPerc), combineHumanValues(stats.NetInput, stats.NetOutput), combineHumanValues(stats.BlockInput, stats.BlockOutput), stats.PIDs)
|
||||
}
|
||||
|
||||
func combineHumanValues(a, b uint64) string {
|
||||
return fmt.Sprintf("%s / %s", units.HumanSize(float64(a)), units.HumanSize(float64(b)))
|
||||
}
|
||||
|
||||
func floatToPercentString(f float64) string {
|
||||
return fmt.Sprintf("%.2f %s", f, "%")
|
||||
}
|
||||
|
||||
func getStatsOutputParams(stats *libkpod.ContainerStats) statsOutputParams {
|
||||
return statsOutputParams{
|
||||
Container: stats.Container,
|
||||
ID: stats.Container,
|
||||
CPUPerc: floatToPercentString(stats.CPU),
|
||||
MemUsage: combineHumanValues(stats.MemUsage, stats.MemLimit),
|
||||
MemPerc: floatToPercentString(stats.MemPerc),
|
||||
NetIO: combineHumanValues(stats.NetInput, stats.NetOutput),
|
||||
BlockIO: combineHumanValues(stats.BlockInput, stats.BlockOutput),
|
||||
PIDs: stats.PIDs,
|
||||
}
|
||||
}
|
||||
|
||||
func outputStatsUsingTemplate(format string, params statsOutputParams) error {
|
||||
tmpl, err := template.New("stats").Parse(format)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "template parsing error")
|
||||
}
|
||||
|
||||
err = tmpl.Execute(os.Stdout, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
println()
|
||||
return nil
|
||||
}
|
||||
|
||||
func outputStatsAsJSON(stats []*libkpod.ContainerStats) error {
|
||||
s, err := json.Marshal(stats)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
println(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func isRunning(ctr *oci.Container) bool {
|
||||
return ctr.State().Status == "running"
|
||||
}
|
||||
|
||||
func ctrInList(idsOrNames []string) func(ctr *oci.Container) bool {
|
||||
if len(idsOrNames) == 0 {
|
||||
return func(*oci.Container) bool { return true }
|
||||
}
|
||||
return func(ctr *oci.Container) bool {
|
||||
for _, idOrName := range idsOrNames {
|
||||
if strings.HasPrefix(ctr.ID(), idOrName) || strings.HasSuffix(ctr.Name(), idOrName) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/kubernetes-incubator/cri-o/libkpod"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultTimeout int64 = 10
|
||||
stopFlags = []cli.Flag{
|
||||
cli.Int64Flag{
|
||||
Name: "timeout, t",
|
||||
Usage: "Seconds to wait for stop before killing the container",
|
||||
Value: defaultTimeout,
|
||||
},
|
||||
}
|
||||
stopDescription = `
|
||||
kpod stop
|
||||
|
||||
Stops one or more running containers. The container name or ID can be used.
|
||||
A timeout to forcibly stop the container can also be set but defaults to 10
|
||||
seconds otherwise.
|
||||
`
|
||||
|
||||
stopCommand = cli.Command{
|
||||
Name: "stop",
|
||||
Usage: "Stop one or more containers",
|
||||
Description: stopDescription,
|
||||
Flags: stopFlags,
|
||||
Action: stopCmd,
|
||||
ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
|
||||
}
|
||||
)
|
||||
|
||||
func stopCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
stopTimeout := c.Int64("timeout")
|
||||
if len(args) < 1 {
|
||||
return errors.Errorf("you must provide at least one container name or id")
|
||||
}
|
||||
if err := validateFlags(c, stopFlags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get config")
|
||||
}
|
||||
server, err := libkpod.New(config)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get container server")
|
||||
}
|
||||
defer server.Shutdown()
|
||||
err = server.Update()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not update list of containers")
|
||||
}
|
||||
var lastError error
|
||||
for _, container := range c.Args() {
|
||||
cid, err := server.ContainerStop(container, stopTimeout)
|
||||
if err != nil {
|
||||
if lastError != nil {
|
||||
fmt.Fprintln(os.Stderr, lastError)
|
||||
}
|
||||
lastError = errors.Wrapf(err, "failed to stop container %v", container)
|
||||
} else {
|
||||
fmt.Println(cid)
|
||||
}
|
||||
}
|
||||
|
||||
return lastError
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/containers/image/docker/reference"
|
||||
"github.com/containers/storage"
|
||||
"github.com/kubernetes-incubator/cri-o/libpod"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
tagDescription = "Adds one or more additional names to locally-stored image"
|
||||
tagCommand = cli.Command{
|
||||
Name: "tag",
|
||||
Usage: "Add an additional name to a local image",
|
||||
Description: tagDescription,
|
||||
Action: tagCmd,
|
||||
ArgsUsage: "IMAGE-NAME [IMAGE-NAME ...]",
|
||||
}
|
||||
)
|
||||
|
||||
func tagCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if len(args) < 2 {
|
||||
return errors.Errorf("image name and at least one new name must be specified")
|
||||
}
|
||||
runtime, err := getRuntime(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not create runtime")
|
||||
}
|
||||
defer runtime.Shutdown(false)
|
||||
|
||||
img, err := runtime.GetImage(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if img == nil {
|
||||
return errors.New("null image")
|
||||
}
|
||||
err = addImageNames(runtime, img, args[1:])
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error adding names %v to image %q", args[1:], args[0])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addImageNames(runtime *libpod.Runtime, image *storage.Image, addNames []string) error {
|
||||
// Add tags to the names if applicable
|
||||
names, err := expandedTags(addNames)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, name := range names {
|
||||
if err := runtime.TagImage(image, name); err != nil {
|
||||
return errors.Wrapf(err, "error adding name (%v) to image %q", name, image.ID)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func expandedTags(tags []string) ([]string, error) {
|
||||
expandedNames := []string{}
|
||||
for _, tag := range tags {
|
||||
var labelName string
|
||||
name, err := reference.Parse(tag)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error parsing tag %q", name)
|
||||
}
|
||||
if _, ok := name.(reference.NamedTagged); ok {
|
||||
labelName = name.String()
|
||||
} else {
|
||||
labelName = name.String() + ":latest"
|
||||
}
|
||||
expandedNames = append(expandedNames, labelName)
|
||||
}
|
||||
return expandedNames, nil
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
umountCommand = cli.Command{
|
||||
Name: "umount",
|
||||
Aliases: []string{"unmount"},
|
||||
Usage: "Unmount a working container's root filesystem",
|
||||
Description: "Unmounts a working container's root filesystem",
|
||||
Action: umountCmd,
|
||||
ArgsUsage: "CONTAINER-NAME-OR-ID",
|
||||
}
|
||||
)
|
||||
|
||||
func umountCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if len(args) == 0 {
|
||||
return errors.Errorf("container ID must be specified")
|
||||
}
|
||||
if len(args) > 1 {
|
||||
return errors.Errorf("too many arguments specified")
|
||||
}
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Could not get config")
|
||||
}
|
||||
store, err := getStore(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = store.Unmount(args[0])
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error unmounting container %q", args[0])
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kubernetes-incubator/cri-o/libkpod"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
unpauseDescription = `
|
||||
kpod unpause
|
||||
|
||||
Unpauses one or more running containers. The container name or ID can be used.
|
||||
`
|
||||
unpauseCommand = cli.Command{
|
||||
Name: "unpause",
|
||||
Usage: "Unpause the processes in one or more containers",
|
||||
Description: unpauseDescription,
|
||||
Action: unpauseCmd,
|
||||
ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
|
||||
}
|
||||
)
|
||||
|
||||
func unpauseCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if len(args) < 1 {
|
||||
return errors.Errorf("you must provide at least one container name or id")
|
||||
}
|
||||
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get config")
|
||||
}
|
||||
server, err := libkpod.New(config)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get container server")
|
||||
}
|
||||
defer server.Shutdown()
|
||||
if err := server.Update(); err != nil {
|
||||
return errors.Wrapf(err, "could not update list of containers")
|
||||
}
|
||||
var lastError error
|
||||
for _, container := range c.Args() {
|
||||
cid, err := server.ContainerUnpause(container)
|
||||
if err != nil {
|
||||
if lastError != nil {
|
||||
fmt.Fprintln(os.Stderr, lastError)
|
||||
}
|
||||
lastError = errors.Wrapf(err, "failed to unpause container %v", container)
|
||||
} else {
|
||||
fmt.Println(cid)
|
||||
}
|
||||
}
|
||||
|
||||
return lastError
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
// Overwritten at build time
|
||||
var (
|
||||
// gitCommit is the commit that the binary is being built from.
|
||||
// It will be populated by the Makefile.
|
||||
gitCommit string
|
||||
// buildInfo is the time at which the binary was built
|
||||
// It will be populated by the Makefile.
|
||||
buildInfo string
|
||||
)
|
||||
|
||||
// versionCmd gets and prints version info for version command
|
||||
func versionCmd(c *cli.Context) error {
|
||||
fmt.Println("Version: ", c.App.Version)
|
||||
fmt.Println("Go Version: ", runtime.Version())
|
||||
if gitCommit != "" {
|
||||
fmt.Println("Git Commit: ", gitCommit)
|
||||
}
|
||||
if buildInfo != "" {
|
||||
// Converts unix time from string to int64
|
||||
buildTime, err := strconv.ParseInt(buildInfo, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Prints out the build time in readable format
|
||||
fmt.Println("Built: ", time.Unix(buildTime, 0).Format(time.ANSIC))
|
||||
}
|
||||
fmt.Println("OS/Arch: ", runtime.GOOS+"/"+runtime.GOARCH)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Cli command to print out the full version of kpod
|
||||
var versionCommand = cli.Command{
|
||||
Name: "version",
|
||||
Usage: "Display the KPOD Version Information",
|
||||
Action: versionCmd,
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/kubernetes-incubator/cri-o/libkpod"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
waitDescription = `
|
||||
kpod wait
|
||||
|
||||
Block until one or more containers stop and then print their exit codes
|
||||
`
|
||||
|
||||
waitCommand = cli.Command{
|
||||
Name: "wait",
|
||||
Usage: "Block on one or more containers",
|
||||
Description: waitDescription,
|
||||
Action: waitCmd,
|
||||
ArgsUsage: "CONTAINER-NAME [CONTAINER-NAME ...]",
|
||||
}
|
||||
)
|
||||
|
||||
func waitCmd(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if len(args) < 1 {
|
||||
return errors.Errorf("you must provide at least one container name or id")
|
||||
}
|
||||
|
||||
config, err := getConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get config")
|
||||
}
|
||||
server, err := libkpod.New(config)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not get container server")
|
||||
}
|
||||
defer server.Shutdown()
|
||||
err = server.Update()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not update list of containers")
|
||||
}
|
||||
|
||||
var lastError error
|
||||
for _, container := range c.Args() {
|
||||
returnCode, err := server.ContainerWait(container)
|
||||
if err != nil {
|
||||
if lastError != nil {
|
||||
fmt.Fprintln(os.Stderr, lastError)
|
||||
}
|
||||
lastError = errors.Wrapf(err, "failed to wait for the container %v", container)
|
||||
} else {
|
||||
fmt.Println(returnCode)
|
||||
}
|
||||
}
|
||||
|
||||
return lastError
|
||||
}
|
|
@ -1,55 +1,3 @@
|
|||
## Kubernetes Community Code of Conduct
|
||||
# Kubernetes Community Code of Conduct
|
||||
|
||||
### Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of this project, and in the interest of fostering
|
||||
an open and welcoming community, we pledge to respect all people who contribute
|
||||
through reporting issues, posting feature requests, updating documentation,
|
||||
submitting pull requests or patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project a harassment-free experience for
|
||||
everyone, regardless of level of experience, gender, gender identity and expression,
|
||||
sexual orientation, disability, personal appearance, body size, race, ethnicity, age,
|
||||
religion, or nationality.
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery.
|
||||
* Personal attacks.
|
||||
* Trolling or insulting/derogatory comments.
|
||||
* Public or private harassment.
|
||||
* Publishing other's private information, such as physical or electronic addresses,
|
||||
without explicit permission.
|
||||
* Other unethical or unprofessional conduct.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are not
|
||||
aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers
|
||||
commit themselves to fairly and consistently applying these principles to every aspect
|
||||
of managing this project. Project maintainers who do not follow or enforce the Code of
|
||||
Conduct may be permanently removed from the project team.
|
||||
|
||||
This code of conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a Kubernetes maintainer, Sarah Novotny <sarahnovotny@google.com>, and/or Dan Kohn <dan@linuxfoundation.org>.
|
||||
|
||||
This Code of Conduct is adapted from the Contributor Covenant
|
||||
(http://contributor-covenant.org), version 1.2.0, available at
|
||||
http://contributor-covenant.org/version/1/2/0/
|
||||
|
||||
### Kubernetes Events Code of Conduct
|
||||
|
||||
Kubernetes events are working conferences intended for professional networking and collaboration in the
|
||||
Kubernetes community. Attendees are expected to behave according to professional standards and in accordance
|
||||
with their employer's policies on appropriate workplace behavior.
|
||||
|
||||
While at Kubernetes events or related social networking opportunities, attendees should not engage in
|
||||
discriminatory or offensive speech or actions regarding gender, sexuality, race, or religion. Speakers should
|
||||
be especially aware of these concerns.
|
||||
|
||||
The Kubernetes team does not condone any statements by speakers contrary to these standards. The Kubernetes
|
||||
team reserves the right to deny entrance and/or eject from an event (without refund) any individual found to
|
||||
be engaging in discriminatory or offensive speech or actions.
|
||||
|
||||
Please bring any concerns to the immediate attention of the Kubernetes event staff.
|
||||
Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md)
|
||||
|
|
|
@ -1,554 +0,0 @@
|
|||
#! /bin/bash
|
||||
|
||||
: ${PROG:=$(basename ${BASH_SOURCE})}
|
||||
|
||||
__kpod_list_images() {
|
||||
COMPREPLY=($(compgen -W "$(kpod images -q)" -- $cur))
|
||||
}
|
||||
|
||||
__kpod_list_containers() {
|
||||
COMPREPLY=($(compgen -W "$(kpod ps -aq)" -- $cur))
|
||||
}
|
||||
|
||||
_kpod_diff() {
|
||||
local options_with_args="
|
||||
--format
|
||||
"
|
||||
local boolean_options="
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
__kpod_list_images
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_kpod_export() {
|
||||
local options_with_args="
|
||||
--output
|
||||
-o
|
||||
"
|
||||
local boolean_options="
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
__kpod_list_images
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_kpod_history() {
|
||||
local options_with_args="
|
||||
--format
|
||||
"
|
||||
local boolean_options="
|
||||
--human -H
|
||||
--no-trunc
|
||||
--quiet -q
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
__kpod_list_images
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_kpod_info() {
|
||||
local boolean_options="
|
||||
--help
|
||||
-h
|
||||
--debug
|
||||
"
|
||||
local options_with_args="
|
||||
--format
|
||||
"
|
||||
|
||||
local all_options="$options_with_args $boolean_options"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
__kpod_list_images
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_kpod_images() {
|
||||
local boolean_options="
|
||||
--help
|
||||
-h
|
||||
--quiet
|
||||
-q
|
||||
--noheading
|
||||
-n
|
||||
--no-trunc
|
||||
--digests
|
||||
--filter
|
||||
-f
|
||||
"
|
||||
local options_with_args="
|
||||
--format
|
||||
"
|
||||
|
||||
local all_options="$options_with_args $boolean_options"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_kpod_inspect() {
|
||||
local boolean_options="
|
||||
--help
|
||||
-h
|
||||
"
|
||||
local options_with_args="
|
||||
--format
|
||||
-f
|
||||
--type
|
||||
-t
|
||||
--size
|
||||
"
|
||||
|
||||
local all_options="$options_with_args $boolean_options"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
esac
|
||||
}
|
||||
_kpod_kill() {
|
||||
local options_with_args="
|
||||
--signal -s
|
||||
"
|
||||
local boolean_options="
|
||||
--help
|
||||
-h"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
}
|
||||
|
||||
_kpod_logs() {
|
||||
local options_with_args="
|
||||
--since
|
||||
--tail
|
||||
"
|
||||
local boolean_options="
|
||||
--follow
|
||||
-f
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
__kpod_list_containers
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_kpod_pull() {
|
||||
local options_with_args="
|
||||
"
|
||||
local boolean_options="
|
||||
--all-tags -a
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
}
|
||||
|
||||
_kpod_unmount() {
|
||||
_kpod_umount $@
|
||||
}
|
||||
|
||||
_kpod_umount() {
|
||||
local boolean_options="
|
||||
--help
|
||||
-h
|
||||
"
|
||||
local options_with_args="
|
||||
"
|
||||
|
||||
local all_options="$options_with_args $boolean_options"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_kpod_mount() {
|
||||
local boolean_options="
|
||||
--help
|
||||
-h
|
||||
--notruncate
|
||||
"
|
||||
|
||||
local options_with_args="
|
||||
--label
|
||||
--format
|
||||
"
|
||||
|
||||
local all_options="$options_with_args $boolean_options"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_kpod_push() {
|
||||
local boolean_options="
|
||||
--disable-compression
|
||||
-D
|
||||
--quiet
|
||||
-q
|
||||
--signature-policy
|
||||
--certs
|
||||
--tls-verify
|
||||
--remove-signatures
|
||||
--sign-by
|
||||
"
|
||||
|
||||
local options_with_args="
|
||||
"
|
||||
|
||||
local all_options="$options_with_args $boolean_options"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_kpod_rename() {
|
||||
local boolean_options="
|
||||
--help
|
||||
-h
|
||||
"
|
||||
local options_with_args="
|
||||
"
|
||||
|
||||
local all_options="$options_with_args $boolean_options"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
__kpod_list_containers
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_kpod_rm() {
|
||||
local boolean_options="
|
||||
--force
|
||||
-f
|
||||
"
|
||||
|
||||
local options_with_args="
|
||||
"
|
||||
|
||||
local all_options="$options_with_args $boolean_options"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
__kpod_list_containers
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_kpod_rmi() {
|
||||
local boolean_options="
|
||||
--help
|
||||
-h
|
||||
--force
|
||||
-f
|
||||
"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
__kpod_list_images
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_kpod_stats() {
|
||||
local boolean_options="
|
||||
--help
|
||||
--all
|
||||
-a
|
||||
--no-stream
|
||||
--format
|
||||
"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
;;
|
||||
*)
|
||||
__kpod_list_containers
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
kpod_tag() {
|
||||
local options_with_args="
|
||||
"
|
||||
local boolean_options="
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
}
|
||||
|
||||
_kpod_version() {
|
||||
local options_with_args="
|
||||
"
|
||||
local boolean_options="
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
}
|
||||
|
||||
_kpod_save() {
|
||||
local options_with_args="
|
||||
--output -o
|
||||
--format
|
||||
"
|
||||
local boolean_options="
|
||||
--quiet -q
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
}
|
||||
|
||||
_kpod_export() {
|
||||
local options_with_args="
|
||||
--output -o
|
||||
"
|
||||
local boolean_options="
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
}
|
||||
|
||||
_kpod_pause() {
|
||||
local options_with_args="
|
||||
--help -h
|
||||
"
|
||||
local boolean_options=""
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
}
|
||||
|
||||
_kpod_ps() {
|
||||
local options_with_args="
|
||||
--filter -f
|
||||
--format
|
||||
--last -n
|
||||
"
|
||||
local boolean_options="
|
||||
--all -a
|
||||
--latest -l
|
||||
--no-trunc
|
||||
--quiet -q
|
||||
--size -s
|
||||
--namespace --ns
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
}
|
||||
|
||||
_kpod_stop() {
|
||||
local options_with_args="
|
||||
--timeout -t
|
||||
"
|
||||
local boolean_options=""
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
}
|
||||
|
||||
_kpod_unpause() {
|
||||
local options_with_args="
|
||||
--help -h
|
||||
"
|
||||
local boolean_options=""
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
|
||||
_kpod_wait() {
|
||||
local options_with_args=""
|
||||
local boolean_options="--help -h"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
}
|
||||
|
||||
_complete_() {
|
||||
local options_with_args=$1
|
||||
local boolean_options="$2 -h --help"
|
||||
|
||||
case "$prev" in
|
||||
$options_with_args)
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) )
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_kpod_load() {
|
||||
local options_with_args="
|
||||
--input -i
|
||||
"
|
||||
local boolean_options="
|
||||
--quiet -q
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
}
|
||||
|
||||
_kpod_login() {
|
||||
local options_with_args="
|
||||
--username
|
||||
-u
|
||||
--password
|
||||
-p
|
||||
--authfile
|
||||
"
|
||||
local boolean_options="
|
||||
--help
|
||||
-h
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
}
|
||||
|
||||
_kpod_logout() {
|
||||
local options_with_args="
|
||||
--authfile
|
||||
"
|
||||
local boolean_options="
|
||||
--all
|
||||
-a
|
||||
--help
|
||||
-h
|
||||
"
|
||||
_complete_ "$options_with_args" "$boolean_options"
|
||||
}
|
||||
|
||||
_kpod_kpod() {
|
||||
local options_with_args="
|
||||
--config -c
|
||||
--root
|
||||
--runroot
|
||||
--storage-driver
|
||||
--storage-opt
|
||||
--log-level
|
||||
"
|
||||
local boolean_options="
|
||||
--help -h
|
||||
--version -v
|
||||
"
|
||||
commands="
|
||||
diff
|
||||
export
|
||||
history
|
||||
images
|
||||
info
|
||||
inspect
|
||||
kill
|
||||
load
|
||||
login
|
||||
logout
|
||||
logs
|
||||
mount
|
||||
pause
|
||||
ps
|
||||
pull
|
||||
push
|
||||
rename
|
||||
rm
|
||||
rmi
|
||||
save
|
||||
stats
|
||||
stop
|
||||
tag
|
||||
umount
|
||||
unmount
|
||||
unpause
|
||||
version
|
||||
wait
|
||||
"
|
||||
|
||||
case "$prev" in
|
||||
$main_options_with_args_glob )
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=( $( compgen -W "${commands[*]} help" -- "$cur" ) )
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
_cli_bash_autocomplete() {
|
||||
local cur opts base
|
||||
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
COMPREPLY=()
|
||||
local cur prev words cword
|
||||
|
||||
_get_comp_words_by_ref -n : cur prev words cword
|
||||
|
||||
local command=${PROG} cpos=0
|
||||
local counter=1
|
||||
counter=1
|
||||
while [ $counter -lt $cword ]; do
|
||||
case "!${words[$counter]}" in
|
||||
*)
|
||||
command=$(echo "${words[$counter]}" | sed 's/-/_/g')
|
||||
cpos=$counter
|
||||
(( cpos++ ))
|
||||
break
|
||||
;;
|
||||
esac
|
||||
(( counter++ ))
|
||||
done
|
||||
|
||||
local completions_func=_kpod_${command}
|
||||
declare -F $completions_func >/dev/null && $completions_func
|
||||
|
||||
eval "$previous_extglob_setting"
|
||||
return 0
|
||||
}
|
||||
|
||||
complete -F _cli_bash_autocomplete $PROG
|
|
@ -5,8 +5,8 @@ override LIBS += $(shell pkg-config --libs glib-2.0)
|
|||
override CFLAGS += -std=c99 -Os -Wall -Wextra $(shell pkg-config --cflags glib-2.0)
|
||||
|
||||
conmon: $(obj)
|
||||
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
|
||||
$(CC) -o ../bin/$@ $^ $(CFLAGS) $(LIBS)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(obj) conmon
|
||||
rm -f $(obj) ../bin/conmon
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -96,6 +95,8 @@ static inline void strv_cleanup(char ***strv)
|
|||
#define CMD_SIZE 1024
|
||||
#define MAX_EVENTS 10
|
||||
|
||||
#define DEFAULT_SOCKET_PATH "/var/lib/crio"
|
||||
|
||||
static bool opt_terminal = false;
|
||||
static bool opt_stdin = false;
|
||||
static char *opt_cid = NULL;
|
||||
|
@ -111,6 +112,7 @@ static char *opt_log_path = NULL;
|
|||
static char *opt_exit_dir = NULL;
|
||||
static int opt_timeout = 0;
|
||||
static int64_t opt_log_size_max = -1;
|
||||
static char *opt_socket_path = DEFAULT_SOCKET_PATH;
|
||||
static GOptionEntry opt_entries[] =
|
||||
{
|
||||
{ "terminal", 't', 0, G_OPTION_ARG_NONE, &opt_terminal, "Terminal", NULL },
|
||||
|
@ -128,6 +130,7 @@ static GOptionEntry opt_entries[] =
|
|||
{ "log-path", 'l', 0, G_OPTION_ARG_STRING, &opt_log_path, "Log file path", NULL },
|
||||
{ "timeout", 'T', 0, G_OPTION_ARG_INT, &opt_timeout, "Timeout in seconds", NULL },
|
||||
{ "log-size-max", 0, 0, G_OPTION_ARG_INT64, &opt_log_size_max, "Maximum size of log file", NULL },
|
||||
{ "socket-dir-path", 0, 0, G_OPTION_ARG_STRING, &opt_socket_path, "Location of container attach sockets", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
@ -292,7 +295,6 @@ const char *stdpipe_name(stdpipe_t pipe)
|
|||
static int write_k8s_log(int fd, stdpipe_t pipe, const char *buf, ssize_t buflen)
|
||||
{
|
||||
char tsbuf[TSBUFLEN];
|
||||
static stdpipe_t trailing_line = NO_PIPE;
|
||||
writev_buffer_t bufv = {0};
|
||||
static int64_t bytes_written = 0;
|
||||
int64_t bytes_to_be_written = 0;
|
||||
|
@ -309,35 +311,22 @@ static int write_k8s_log(int fd, stdpipe_t pipe, const char *buf, ssize_t buflen
|
|||
while (buflen > 0) {
|
||||
const char *line_end = NULL;
|
||||
ptrdiff_t line_len = 0;
|
||||
bool insert_newline = FALSE;
|
||||
bool insert_timestamp = FALSE;
|
||||
bool partial = FALSE;
|
||||
|
||||
/* Find the end of the line, or alternatively the end of the buffer. */
|
||||
line_end = memchr(buf, '\n', buflen);
|
||||
if (line_end == NULL)
|
||||
if (line_end == NULL) {
|
||||
line_end = &buf[buflen-1];
|
||||
partial = TRUE;
|
||||
}
|
||||
line_len = line_end - buf + 1;
|
||||
|
||||
bytes_to_be_written = line_len;
|
||||
if (trailing_line != pipe) {
|
||||
/*
|
||||
* Write the (timestamp, stream) tuple if there isn't any trailing
|
||||
* output from the previous line (or if there is trailing output but
|
||||
* the current buffer being printed is from a different pipe).
|
||||
*/
|
||||
insert_timestamp = TRUE;
|
||||
bytes_to_be_written += (TSBUFLEN - 1);
|
||||
/*
|
||||
* If there was a trailing line from a different pipe, prepend a
|
||||
* newline to split it properly. This technically breaks the flow
|
||||
* of the previous line (adding a newline in the log where there
|
||||
* wasn't one output) but without modifying the file in a
|
||||
* non-append-only way there's not much we can do.
|
||||
*/
|
||||
if (trailing_line != NO_PIPE) {
|
||||
insert_newline = TRUE;
|
||||
bytes_to_be_written += 1;
|
||||
}
|
||||
/* This is line_len bytes + TSBUFLEN - 1 + 2 (- 1 is for ignoring \0). */
|
||||
bytes_to_be_written = line_len + TSBUFLEN + 1;
|
||||
|
||||
/* If partial, then we add a \n */
|
||||
if (partial) {
|
||||
bytes_to_be_written += 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -347,8 +336,6 @@ static int write_k8s_log(int fd, stdpipe_t pipe, const char *buf, ssize_t buflen
|
|||
*/
|
||||
if ((opt_log_size_max > 0) && (bytes_written + bytes_to_be_written) > opt_log_size_max) {
|
||||
ninfo("Creating new log file");
|
||||
insert_newline = FALSE;
|
||||
insert_timestamp = TRUE;
|
||||
bytes_written = 0;
|
||||
|
||||
/* Close the existing fd */
|
||||
|
@ -362,22 +349,25 @@ static int write_k8s_log(int fd, stdpipe_t pipe, const char *buf, ssize_t buflen
|
|||
/* Open the log path file again */
|
||||
log_fd = open(opt_log_path, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, 0600);
|
||||
if (log_fd < 0)
|
||||
pexit("Failed to open log file");
|
||||
pexit("Failed to open log file %s: %s", opt_log_path, strerror(errno));
|
||||
fd = log_fd;
|
||||
}
|
||||
|
||||
/* Output a newline */
|
||||
if (insert_newline) {
|
||||
if (writev_buffer_append_segment(fd, &bufv, "\n", -1) < 0) {
|
||||
nwarn("failed to write newline to log");
|
||||
goto next;
|
||||
}
|
||||
/* Output the timestamp */
|
||||
if (writev_buffer_append_segment(fd, &bufv, tsbuf, -1) < 0) {
|
||||
nwarn("failed to write (timestamp, stream) to log");
|
||||
goto next;
|
||||
}
|
||||
|
||||
/* Output a timestamp */
|
||||
if (insert_timestamp) {
|
||||
if (writev_buffer_append_segment(fd, &bufv, tsbuf, -1) < 0) {
|
||||
nwarn("failed to write (timestamp, stream) to log");
|
||||
/* Output log tag for partial or newline */
|
||||
if (partial) {
|
||||
if (writev_buffer_append_segment(fd, &bufv, "P ", -1) < 0) {
|
||||
nwarn("failed to write partial log tag");
|
||||
goto next;
|
||||
}
|
||||
} else {
|
||||
if (writev_buffer_append_segment(fd, &bufv, "F ", -1) < 0) {
|
||||
nwarn("failed to write end log tag");
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
@ -388,11 +378,15 @@ static int write_k8s_log(int fd, stdpipe_t pipe, const char *buf, ssize_t buflen
|
|||
goto next;
|
||||
}
|
||||
|
||||
/* Output a newline for partial */
|
||||
if (partial) {
|
||||
if (writev_buffer_append_segment(fd, &bufv, "\n", -1) < 0) {
|
||||
nwarn("failed to write newline to log");
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
bytes_written += bytes_to_be_written;
|
||||
|
||||
/* If we did not output a full line, then we are a trailing_line. */
|
||||
trailing_line = (*line_end == '\n') ? NO_PIPE : pipe;
|
||||
|
||||
next:
|
||||
/* Update the head of the buffer remaining to output. */
|
||||
buf += line_len;
|
||||
|
@ -989,14 +983,14 @@ static char *setup_attach_socket(void)
|
|||
* Create a symlink so we don't exceed unix domain socket
|
||||
* path length limit.
|
||||
*/
|
||||
attach_symlink_dir_path = g_build_filename("/var/run/crio", opt_cuuid, NULL);
|
||||
attach_symlink_dir_path = g_build_filename(opt_socket_path, opt_cuuid, NULL);
|
||||
if (unlink(attach_symlink_dir_path) == -1 && errno != ENOENT)
|
||||
pexit("Failed to remove existing symlink for attach socket directory");
|
||||
|
||||
if (symlink(opt_bundle_path, attach_symlink_dir_path) == -1)
|
||||
pexit("Failed to create symlink for attach socket");
|
||||
|
||||
attach_sock_path = g_build_filename("/var/run/crio", opt_cuuid, "attach", NULL);
|
||||
attach_sock_path = g_build_filename(opt_socket_path, opt_cuuid, "attach", NULL);
|
||||
ninfo("attach sock path: %s", attach_sock_path);
|
||||
|
||||
strncpy(attach_addr.sun_path, attach_sock_path, sizeof(attach_addr.sun_path) - 1);
|
||||
|
@ -1126,6 +1120,8 @@ int main(int argc, char *argv[])
|
|||
|
||||
if (opt_runtime_path == NULL)
|
||||
nexit("Runtime path not provided. Use --runtime");
|
||||
if (access(opt_runtime_path, X_OK) < 0)
|
||||
pexit("Runtime path %s is not valid: %s", opt_runtime_path, strerror(errno));
|
||||
|
||||
if (!opt_exec && opt_exit_dir == NULL)
|
||||
nexit("Container exit directory not provided. Use --exit-dir");
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
.PHONY: dist
|
||||
dist: crio.spec
|
||||
spectool -g crio.spec
|
||||
|
||||
.PHONY: rpm
|
||||
rpm: dist
|
||||
rpmbuild --define "_sourcedir `pwd`" --define "_specdir `pwd`" \
|
||||
--define "_rpmdir `pwd`" --define "_srcrpmdir `pwd`" -ba crio.spec
|
||||
|
||||
all: rpm
|
||||
|
||||
clean:
|
||||
rm -f *rpm *gz
|
||||
rm -rf x86_64
|
|
@ -1,76 +0,0 @@
|
|||
%define debug_package %{nil}
|
||||
%global provider github
|
||||
%global provider_tld com
|
||||
%global project kubernetes-incubator
|
||||
%global repo cri-o
|
||||
%global Name crio
|
||||
# https://github.com/kubernetes-incubator/cri-o
|
||||
%global provider_prefix %{provider}.%{provider_tld}/%{project}/%{repo}
|
||||
%global import_path %{provider_prefix}
|
||||
%global commit 8ba639952a95f2e24cc98987689138b67545576c
|
||||
%global shortcommit %(c=%{commit}; echo ${c:0:7})
|
||||
|
||||
Name: %{Name}
|
||||
Version: 0.0.1
|
||||
Release: 1.git%{shortcommit}%{?dist}
|
||||
Summary: Kubelet Container Runtime Interface (CRI) for OCI runtimes.
|
||||
Group: Applications/Text
|
||||
License: Apache 2.0
|
||||
URL: https://%{provider_prefix}
|
||||
Source0: https://%{provider_prefix}/archive/%{commit}/%{repo}-%{shortcommit}.tar.gz
|
||||
Provides: %{repo}
|
||||
|
||||
BuildRequires: golang-github-cpuguy83-go-md2man
|
||||
|
||||
%description
|
||||
The crio package provides an implementation of the
|
||||
Kubelet Container Runtime Interface (CRI) using OCI conformant runtimes.
|
||||
|
||||
crio provides following functionalities:
|
||||
|
||||
Support multiple image formats including the existing Docker image format
|
||||
Support for multiple means to download images including trust & image verification
|
||||
Container image management (managing image layers, overlay filesystems, etc)
|
||||
Container process lifecycle management
|
||||
Monitoring and logging required to satisfy the CRI
|
||||
Resource isolation as required by the CRI
|
||||
|
||||
%prep
|
||||
%setup -q -n %{repo}-%{commit}
|
||||
|
||||
%build
|
||||
make all
|
||||
|
||||
%install
|
||||
%make_install
|
||||
%make_install install.systemd
|
||||
|
||||
#define license tag if not already defined
|
||||
%{!?_licensedir:%global license %doc}
|
||||
%files
|
||||
%{_bindir}/crio
|
||||
%{_bindir}/crioctl
|
||||
%{_mandir}/man5/crio.conf.5*
|
||||
%{_mandir}/man8/crio.8*
|
||||
%{_sysconfdir}/crio.conf
|
||||
%{_sysconfdir}/seccomp.json
|
||||
%dir /%{_libexecdir}/crio
|
||||
/%{_libexecdir}/crio/conmon
|
||||
/%{_libexecdir}/crio/pause
|
||||
%{_unitdir}/crio.service
|
||||
%doc README.md
|
||||
%license LICENSE
|
||||
%dir /usr/share/oci-umount/oci-umount.d
|
||||
/usr/share/oci-umount/oci-umount.d/cri-umount.conf
|
||||
|
||||
|
||||
%preun
|
||||
%systemd_preun %{Name}
|
||||
|
||||
%postun
|
||||
%systemd_postun_with_restart %{Name}
|
||||
|
||||
%changelog
|
||||
* Mon Oct 31 2016 Dan Walsh <dwalsh@redhat.com> - 0.0.1
|
||||
- Initial RPM release
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
FROM centos
|
||||
|
||||
ENV VERSION=0 RELEASE=1 ARCH=x86_64
|
||||
LABEL com.redhat.component="cri-o" \
|
||||
name="$FGC/cri-o" \
|
||||
version="$VERSION" \
|
||||
release="$RELEASE.$DISTTAG" \
|
||||
architecture="$ARCH" \
|
||||
usage="atomic install --system --system-package=no crio && systemctl start crio" \
|
||||
summary="The cri-o daemon as a system container." \
|
||||
maintainer="Yu Qi Zhang <jzehrarnyg@gmail.com>" \
|
||||
atomic.type="system"
|
||||
|
||||
RUN yum-config-manager --nogpgcheck --add-repo https://cbs.centos.org/repos/virt7-container-common-candidate/x86_64/os/ && \
|
||||
yum install --disablerepo=extras --nogpgcheck --setopt=tsflags=nodocs -y iptables cri-o socat iproute runc && \
|
||||
rpm -V iptables cri-o iproute runc && \
|
||||
yum clean all && \
|
||||
mkdir -p /exports/hostfs/etc/crio /exports/hostfs/opt/cni/bin/ /exports/hostfs/var/lib/containers/storage/ && \
|
||||
cp /etc/crio/* /exports/hostfs/etc/crio && \
|
||||
if test -e /usr/libexec/cni; then cp -Lr /usr/libexec/cni/* /exports/hostfs/opt/cni/bin/; fi
|
||||
|
||||
RUN sed -i '/storage_option =/s/.*/&\n"overlay.override_kernel_check=1",/' /exports/hostfs/etc/crio/crio.conf
|
||||
|
||||
COPY manifest.json tmpfiles.template config.json.template service.template /exports/
|
||||
|
||||
COPY set_mounts.sh /
|
||||
COPY run.sh /usr/bin/
|
||||
|
||||
CMD ["/usr/bin/run.sh"]
|
|
@ -0,0 +1,57 @@
|
|||
# cri-o
|
||||
|
||||
This is the cri-o daemon as a system container.
|
||||
|
||||
## Building the image from source:
|
||||
|
||||
```
|
||||
# git clone https://github.com/projectatomic/atomic-system-containers
|
||||
# cd atomic-system-containers/cri-o
|
||||
# docker build -t crio .
|
||||
```
|
||||
|
||||
## Running the system container, with the atomic CLI:
|
||||
|
||||
Pull from registry into ostree:
|
||||
|
||||
```
|
||||
# atomic pull --storage ostree $REGISTRY/crio
|
||||
```
|
||||
|
||||
Or alternatively, pull from local docker:
|
||||
|
||||
```
|
||||
# atomic pull --storage ostree docker:crio:latest
|
||||
```
|
||||
|
||||
Install the container:
|
||||
|
||||
Currently we recommend using --system-package=no to avoid having rpmbuild create an rpm file
|
||||
during installation. This flag will tell the atomic CLI to fall back to copying files to the
|
||||
host instead.
|
||||
|
||||
```
|
||||
# atomic install --system --system-package=no --name=crio ($REGISTRY)/crio
|
||||
```
|
||||
|
||||
Start as a systemd service:
|
||||
|
||||
```
|
||||
# systemctl start crio
|
||||
```
|
||||
|
||||
Stopping the service
|
||||
|
||||
```
|
||||
# systemctl stop crio
|
||||
```
|
||||
|
||||
Removing the container
|
||||
|
||||
```
|
||||
# atomic uninstall crio
|
||||
```
|
||||
|
||||
## Binary version
|
||||
|
||||
You can find the image automatically built as: registry.centos.org/projectatomic/cri-o:latest
|
|
@ -0,0 +1,41 @@
|
|||
# This is for the purpose of building containers on the CentOS Community Container
|
||||
# Pipeline. The containers are built, tested and delivered to registry.centos.org and
|
||||
# lifecycled as well. A corresponding entry must exist in the container index itself,
|
||||
# located at https://github.com/CentOS/container-index/tree/master/index.d
|
||||
# You can know more at the following links:
|
||||
# * https://github.com/CentOS/container-pipeline-service/blob/master/README.md
|
||||
# * https://github.com/CentOS/container-index/blob/master/README.rst
|
||||
# * https://wiki.centos.org/ContainerPipeline
|
||||
|
||||
# This will be part of the name of the container. It should match the job-id in index entry
|
||||
job-id: cri-o
|
||||
|
||||
#the following are optional, can be left blank
|
||||
#defaults, where applicable are filled in
|
||||
#nulecule-file : nulecule
|
||||
|
||||
# This flag tells the container pipeline to skip user defined tests on their container
|
||||
test-skip : True
|
||||
|
||||
# This is path of the script that initiates the user defined tests. It must be able to
|
||||
# return an exit code.
|
||||
test-script : null
|
||||
|
||||
# This is the path of custom build script.
|
||||
build-script : null
|
||||
|
||||
# This is the path of the custom delivery script
|
||||
delivery-script : null
|
||||
|
||||
# This flag tells the pipeline to deliver this container to docker hub.
|
||||
docker-index : True
|
||||
|
||||
# This flag can be used to enable or disable the custom delivery
|
||||
custom-delivery : False
|
||||
|
||||
# This flag can be used to enable or disable delivery of container to local registry
|
||||
local-delivery : True
|
||||
|
||||
Upstreams :
|
||||
- ref :
|
||||
url :
|
|
@ -0,0 +1,427 @@
|
|||
{
|
||||
"ociVersion": "1.0.0",
|
||||
"platform": {
|
||||
"arch": "amd64",
|
||||
"os": "linux"
|
||||
},
|
||||
"process": {
|
||||
"args": [
|
||||
"/usr/bin/run.sh"
|
||||
],
|
||||
"capabilities": {
|
||||
"ambient": [
|
||||
"CAP_CHOWN",
|
||||
"CAP_FOWNER",
|
||||
"CAP_FSETID",
|
||||
"CAP_KILL",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_LINUX_IMMUTABLE",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_BROADCAST",
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_IPC_LOCK",
|
||||
"CAP_IPC_OWNER",
|
||||
"CAP_SYS_MODULE",
|
||||
"CAP_SYS_RAWIO",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_SYS_PTRACE",
|
||||
"CAP_SYS_PACCT",
|
||||
"CAP_SYS_ADMIN",
|
||||
"CAP_SYS_BOOT",
|
||||
"CAP_SYS_NICE",
|
||||
"CAP_SYS_RESOURCE",
|
||||
"CAP_SYS_TIME",
|
||||
"CAP_SYS_TTY_CONFIG",
|
||||
"CAP_MKNOD",
|
||||
"CAP_LEASE",
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_AUDIT_CONTROL",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_MAC_OVERRIDE",
|
||||
"CAP_DAC_READ_SEARCH",
|
||||
"CAP_MAC_ADMIN",
|
||||
"CAP_SYSLOG",
|
||||
"CAP_WAKE_ALARM",
|
||||
"CAP_BLOCK_SUSPEND"
|
||||
],
|
||||
"bounding": [
|
||||
"CAP_CHOWN",
|
||||
"CAP_FOWNER",
|
||||
"CAP_FSETID",
|
||||
"CAP_KILL",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_LINUX_IMMUTABLE",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_BROADCAST",
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_IPC_LOCK",
|
||||
"CAP_IPC_OWNER",
|
||||
"CAP_SYS_MODULE",
|
||||
"CAP_SYS_RAWIO",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_SYS_PTRACE",
|
||||
"CAP_SYS_PACCT",
|
||||
"CAP_SYS_ADMIN",
|
||||
"CAP_SYS_BOOT",
|
||||
"CAP_SYS_NICE",
|
||||
"CAP_SYS_RESOURCE",
|
||||
"CAP_SYS_TIME",
|
||||
"CAP_SYS_TTY_CONFIG",
|
||||
"CAP_MKNOD",
|
||||
"CAP_LEASE",
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_AUDIT_CONTROL",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_MAC_OVERRIDE",
|
||||
"CAP_DAC_READ_SEARCH",
|
||||
"CAP_MAC_ADMIN",
|
||||
"CAP_SYSLOG",
|
||||
"CAP_WAKE_ALARM",
|
||||
"CAP_BLOCK_SUSPEND"
|
||||
],
|
||||
"effective": [
|
||||
"CAP_CHOWN",
|
||||
"CAP_FOWNER",
|
||||
"CAP_FSETID",
|
||||
"CAP_KILL",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_LINUX_IMMUTABLE",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_BROADCAST",
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_IPC_LOCK",
|
||||
"CAP_IPC_OWNER",
|
||||
"CAP_SYS_MODULE",
|
||||
"CAP_SYS_RAWIO",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_SYS_PTRACE",
|
||||
"CAP_SYS_PACCT",
|
||||
"CAP_SYS_ADMIN",
|
||||
"CAP_SYS_BOOT",
|
||||
"CAP_SYS_NICE",
|
||||
"CAP_SYS_RESOURCE",
|
||||
"CAP_SYS_TIME",
|
||||
"CAP_SYS_TTY_CONFIG",
|
||||
"CAP_MKNOD",
|
||||
"CAP_LEASE",
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_AUDIT_CONTROL",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_MAC_OVERRIDE",
|
||||
"CAP_DAC_READ_SEARCH",
|
||||
"CAP_MAC_ADMIN",
|
||||
"CAP_SYSLOG",
|
||||
"CAP_WAKE_ALARM",
|
||||
"CAP_BLOCK_SUSPEND"
|
||||
],
|
||||
"inheritable": [
|
||||
"CAP_CHOWN",
|
||||
"CAP_FOWNER",
|
||||
"CAP_FSETID",
|
||||
"CAP_KILL",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_LINUX_IMMUTABLE",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_BROADCAST",
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_IPC_LOCK",
|
||||
"CAP_IPC_OWNER",
|
||||
"CAP_SYS_MODULE",
|
||||
"CAP_SYS_RAWIO",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_SYS_PTRACE",
|
||||
"CAP_SYS_PACCT",
|
||||
"CAP_SYS_ADMIN",
|
||||
"CAP_SYS_BOOT",
|
||||
"CAP_SYS_NICE",
|
||||
"CAP_SYS_RESOURCE",
|
||||
"CAP_SYS_TIME",
|
||||
"CAP_SYS_TTY_CONFIG",
|
||||
"CAP_MKNOD",
|
||||
"CAP_LEASE",
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_AUDIT_CONTROL",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_MAC_OVERRIDE",
|
||||
"CAP_DAC_READ_SEARCH",
|
||||
"CAP_MAC_ADMIN",
|
||||
"CAP_SYSLOG",
|
||||
"CAP_WAKE_ALARM",
|
||||
"CAP_BLOCK_SUSPEND"
|
||||
],
|
||||
"permitted": [
|
||||
"CAP_CHOWN",
|
||||
"CAP_FOWNER",
|
||||
"CAP_FSETID",
|
||||
"CAP_KILL",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_LINUX_IMMUTABLE",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_BROADCAST",
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_IPC_LOCK",
|
||||
"CAP_IPC_OWNER",
|
||||
"CAP_SYS_MODULE",
|
||||
"CAP_SYS_RAWIO",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_SYS_PTRACE",
|
||||
"CAP_SYS_PACCT",
|
||||
"CAP_SYS_ADMIN",
|
||||
"CAP_SYS_BOOT",
|
||||
"CAP_SYS_NICE",
|
||||
"CAP_SYS_RESOURCE",
|
||||
"CAP_SYS_TIME",
|
||||
"CAP_SYS_TTY_CONFIG",
|
||||
"CAP_MKNOD",
|
||||
"CAP_LEASE",
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_AUDIT_CONTROL",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_MAC_OVERRIDE",
|
||||
"CAP_DAC_READ_SEARCH",
|
||||
"CAP_MAC_ADMIN",
|
||||
"CAP_SYSLOG",
|
||||
"CAP_WAKE_ALARM",
|
||||
"CAP_BLOCK_SUSPEND"
|
||||
]
|
||||
},
|
||||
"selinuxLabel": "system_u:system_r:container_runtime_t:s0",
|
||||
"cwd": "/",
|
||||
"env": [
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/root/go/bin",
|
||||
"TERM=xterm",
|
||||
"LOG_LEVEL=$LOG_LEVEL",
|
||||
"NAME=$NAME"
|
||||
],
|
||||
"noNewPrivileges": false,
|
||||
"terminal": false,
|
||||
"user": {
|
||||
"gid": 0,
|
||||
"uid": 0
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"path": "rootfs",
|
||||
"readonly": true
|
||||
},
|
||||
"hooks": {},
|
||||
"linux": {
|
||||
"namespaces": [
|
||||
{
|
||||
"type": "mount"
|
||||
}
|
||||
],
|
||||
"resources": {
|
||||
"devices": [
|
||||
{
|
||||
"access": "rwm",
|
||||
"allow": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"rootfsPropagation": "private"
|
||||
},
|
||||
"mounts": [
|
||||
{
|
||||
"destination": "/tmp",
|
||||
"options": [
|
||||
"private",
|
||||
"bind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/tmp",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/etc",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/etc",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/lib/modules",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/lib/modules",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/root",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/root",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/home",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/home",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/mnt",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rw",
|
||||
"rprivate",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/mnt",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"type": "bind",
|
||||
"source": "${RUN_DIRECTORY}",
|
||||
"destination": "/run",
|
||||
"options": [
|
||||
"rshared",
|
||||
"rbind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "bind",
|
||||
"source": "${RUN_DIRECTORY}/systemd",
|
||||
"destination": "/run/systemd",
|
||||
"options": [
|
||||
"rslave",
|
||||
"bind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
]
|
||||
},
|
||||
{
|
||||
"destination": "/var/log",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rslave",
|
||||
"rw"
|
||||
],
|
||||
"source": "/var/log",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/var/lib",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"rw"
|
||||
],
|
||||
"source": "${STATE_DIRECTORY}",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/var/lib/containers/storage",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rshared",
|
||||
"rw"
|
||||
],
|
||||
"source": "${VAR_LIB_CONTAINERS_STORAGE}",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/var/lib/origin",
|
||||
"options": [
|
||||
"rshared",
|
||||
"bind",
|
||||
"rw"
|
||||
],
|
||||
"source": "${VAR_LIB_ORIGIN}",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/var/lib/kubelet",
|
||||
"options": [
|
||||
"rshared",
|
||||
"bind",
|
||||
"rw"
|
||||
],
|
||||
"source": "${VAR_LIB_KUBE}",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/opt/cni",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"ro",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "${OPT_CNI}",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/dev",
|
||||
"options": [
|
||||
"rprivate",
|
||||
"rbind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/dev",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/sys",
|
||||
"options": [
|
||||
"rprivate",
|
||||
"rbind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/sys",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/proc",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/proc",
|
||||
"type": "proc"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": "1.0",
|
||||
"defaultValues": {
|
||||
"LOG_LEVEL" : "info",
|
||||
"OPT_CNI" : "/opt/cni",
|
||||
"VAR_LIB_CONTAINERS_STORAGE" : "/var/lib/containers/storage",
|
||||
"VAR_LIB_ORIGIN" : "/var/lib/origin",
|
||||
"VAR_LIB_KUBE" : "/var/lib/kubelet"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Ensure that new process maintain this SELinux label
|
||||
PID=$$
|
||||
LABEL=`tr -d '\000' < /proc/$PID/attr/current`
|
||||
printf %s $LABEL > /proc/self/attr/exec
|
||||
|
||||
test -e /etc/sysconfig/crio-storage && source /etc/sysconfig/crio-storage
|
||||
test -e /etc/sysconfig/crio-network && source /etc/sysconfig/crio-network
|
||||
|
||||
exec /usr/bin/crio --log-level=$LOG_LEVEL
|
|
@ -0,0 +1,20 @@
|
|||
[Unit]
|
||||
Description=crio daemon
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
ExecStartPre=/bin/sh $DESTDIR/rootfs/set_mounts.sh
|
||||
ExecStart=$EXEC_START
|
||||
ExecStop=$EXEC_STOP
|
||||
Restart=on-failure
|
||||
WorkingDirectory=$DESTDIR
|
||||
RuntimeDirectory=${NAME}
|
||||
TasksMax=infinity
|
||||
LimitNOFILE=1048576
|
||||
LimitNPROC=1048576
|
||||
LimitCORE=infinity
|
||||
TimeoutStartSec=0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
findmnt /var/lib/containers/storage > /dev/null || mount --rbind --make-shared /var/lib/containers/storage /var/lib/containers/storage
|
||||
findmnt /var/lib/origin > /dev/null || mount --bind --make-shared /var/lib/origin /var/lib/origin
|
||||
findmnt /var/lib/kubelet > /dev/null || mount --bind --make-shared /var/lib/kubelet /var/lib/kubelet
|
||||
mount --make-shared /run
|
||||
findmnt /run/systemd > /dev/null || mount --bind --make-rslave /run/systemd /run/systemd
|
|
@ -0,0 +1,5 @@
|
|||
d ${RUN_DIRECTORY}/crio - - - - -
|
||||
d /etc/crio - - - - -
|
||||
Z /etc/crio - - - - -
|
||||
d ${STATE_DIRECTORY}/origin - - - - -
|
||||
d ${STATE_DIRECTORY}/kubelet - - - - -
|
|
@ -0,0 +1,30 @@
|
|||
FROM registry.fedoraproject.org/fedora:27
|
||||
|
||||
ENV VERSION=0 RELEASE=1 ARCH=x86_64
|
||||
LABEL com.redhat.component="cri-o" \
|
||||
name="$FGC/cri-o" \
|
||||
version="$VERSION" \
|
||||
release="$RELEASE.$DISTTAG" \
|
||||
architecture="$ARCH" \
|
||||
usage="atomic install --system --system-package=no crio && systemctl start crio" \
|
||||
summary="The cri-o daemon as a system container." \
|
||||
maintainer="Yu Qi Zhang <jzehrarnyg@gmail.com>" \
|
||||
atomic.type="system"
|
||||
|
||||
COPY README.md /
|
||||
|
||||
RUN dnf install --enablerepo=updates-testing --setopt=tsflags=nodocs -y iptables cri-o socat iproute runc && \
|
||||
rpm -V iptables cri-o iproute runc && \
|
||||
dnf clean all && \
|
||||
mkdir -p /exports/hostfs/etc/crio /exports/hostfs/opt/cni/bin/ /exports/hostfs/var/lib/containers/storage/ && \
|
||||
cp /etc/crio/* /exports/hostfs/etc/crio && \
|
||||
if test -e /usr/libexec/cni; then cp -Lr /usr/libexec/cni/* /exports/hostfs/opt/cni/bin/; fi
|
||||
|
||||
RUN sed -i '/storage_option =/s/.*/&\n"overlay.override_kernel_check=1",/' /exports/hostfs/etc/crio/crio.conf
|
||||
|
||||
COPY manifest.json tmpfiles.template config.json.template service.template /exports/
|
||||
|
||||
COPY set_mounts.sh /
|
||||
COPY run.sh /usr/bin/
|
||||
|
||||
CMD ["/usr/bin/run.sh"]
|
|
@ -0,0 +1,53 @@
|
|||
# cri-o
|
||||
|
||||
This is the cri-o daemon as a system container.
|
||||
|
||||
## Building the image from source:
|
||||
|
||||
```
|
||||
# git clone https://github.com/projectatomic/atomic-system-containers
|
||||
# cd atomic-system-containers/cri-o
|
||||
# docker build -t crio .
|
||||
```
|
||||
|
||||
## Running the system container, with the atomic CLI:
|
||||
|
||||
Pull from registry into ostree:
|
||||
|
||||
```
|
||||
# atomic pull --storage ostree $REGISTRY/crio
|
||||
```
|
||||
|
||||
Or alternatively, pull from local docker:
|
||||
|
||||
```
|
||||
# atomic pull --storage ostree docker:crio:latest
|
||||
```
|
||||
|
||||
Install the container:
|
||||
|
||||
Currently we recommend using --system-package=no to avoid having rpmbuild create an rpm file
|
||||
during installation. This flag will tell the atomic CLI to fall back to copying files to the
|
||||
host instead.
|
||||
|
||||
```
|
||||
# atomic install --system --system-package=no --name=crio ($REGISTRY)/crio
|
||||
```
|
||||
|
||||
Start as a systemd service:
|
||||
|
||||
```
|
||||
# systemctl start crio
|
||||
```
|
||||
|
||||
Stopping the service
|
||||
|
||||
```
|
||||
# systemctl stop crio
|
||||
```
|
||||
|
||||
Removing the container
|
||||
|
||||
```
|
||||
# atomic uninstall crio
|
||||
```
|
|
@ -0,0 +1,432 @@
|
|||
{
|
||||
"ociVersion": "1.0.0",
|
||||
"platform": {
|
||||
"arch": "amd64",
|
||||
"os": "linux"
|
||||
},
|
||||
"process": {
|
||||
"args": [
|
||||
"/usr/bin/run.sh"
|
||||
],
|
||||
"selinuxLabel": "system_u:system_r:container_runtime_t:s0",
|
||||
"capabilities": {
|
||||
"ambient": [
|
||||
"CAP_CHOWN",
|
||||
"CAP_FOWNER",
|
||||
"CAP_FSETID",
|
||||
"CAP_KILL",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_LINUX_IMMUTABLE",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_BROADCAST",
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_IPC_LOCK",
|
||||
"CAP_IPC_OWNER",
|
||||
"CAP_SYS_MODULE",
|
||||
"CAP_SYS_RAWIO",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_SYS_PTRACE",
|
||||
"CAP_SYS_PACCT",
|
||||
"CAP_SYS_ADMIN",
|
||||
"CAP_SYS_BOOT",
|
||||
"CAP_SYS_NICE",
|
||||
"CAP_SYS_RESOURCE",
|
||||
"CAP_SYS_TIME",
|
||||
"CAP_SYS_TTY_CONFIG",
|
||||
"CAP_MKNOD",
|
||||
"CAP_LEASE",
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_AUDIT_CONTROL",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_MAC_OVERRIDE",
|
||||
"CAP_DAC_READ_SEARCH",
|
||||
"CAP_MAC_ADMIN",
|
||||
"CAP_SYSLOG",
|
||||
"CAP_WAKE_ALARM",
|
||||
"CAP_BLOCK_SUSPEND",
|
||||
"CAP_AUDIT_READ"
|
||||
],
|
||||
"bounding": [
|
||||
"CAP_CHOWN",
|
||||
"CAP_FOWNER",
|
||||
"CAP_FSETID",
|
||||
"CAP_KILL",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_LINUX_IMMUTABLE",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_BROADCAST",
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_IPC_LOCK",
|
||||
"CAP_IPC_OWNER",
|
||||
"CAP_SYS_MODULE",
|
||||
"CAP_SYS_RAWIO",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_SYS_PTRACE",
|
||||
"CAP_SYS_PACCT",
|
||||
"CAP_SYS_ADMIN",
|
||||
"CAP_SYS_BOOT",
|
||||
"CAP_SYS_NICE",
|
||||
"CAP_SYS_RESOURCE",
|
||||
"CAP_SYS_TIME",
|
||||
"CAP_SYS_TTY_CONFIG",
|
||||
"CAP_MKNOD",
|
||||
"CAP_LEASE",
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_AUDIT_CONTROL",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_MAC_OVERRIDE",
|
||||
"CAP_DAC_READ_SEARCH",
|
||||
"CAP_MAC_ADMIN",
|
||||
"CAP_SYSLOG",
|
||||
"CAP_WAKE_ALARM",
|
||||
"CAP_BLOCK_SUSPEND",
|
||||
"CAP_AUDIT_READ"
|
||||
],
|
||||
"effective": [
|
||||
"CAP_CHOWN",
|
||||
"CAP_FOWNER",
|
||||
"CAP_FSETID",
|
||||
"CAP_KILL",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_LINUX_IMMUTABLE",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_BROADCAST",
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_IPC_LOCK",
|
||||
"CAP_IPC_OWNER",
|
||||
"CAP_SYS_MODULE",
|
||||
"CAP_SYS_RAWIO",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_SYS_PTRACE",
|
||||
"CAP_SYS_PACCT",
|
||||
"CAP_SYS_ADMIN",
|
||||
"CAP_SYS_BOOT",
|
||||
"CAP_SYS_NICE",
|
||||
"CAP_SYS_RESOURCE",
|
||||
"CAP_SYS_TIME",
|
||||
"CAP_SYS_TTY_CONFIG",
|
||||
"CAP_MKNOD",
|
||||
"CAP_LEASE",
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_AUDIT_CONTROL",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_MAC_OVERRIDE",
|
||||
"CAP_DAC_READ_SEARCH",
|
||||
"CAP_MAC_ADMIN",
|
||||
"CAP_SYSLOG",
|
||||
"CAP_WAKE_ALARM",
|
||||
"CAP_BLOCK_SUSPEND",
|
||||
"CAP_AUDIT_READ"
|
||||
],
|
||||
"inheritable": [
|
||||
"CAP_CHOWN",
|
||||
"CAP_FOWNER",
|
||||
"CAP_FSETID",
|
||||
"CAP_KILL",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_LINUX_IMMUTABLE",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_BROADCAST",
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_IPC_LOCK",
|
||||
"CAP_IPC_OWNER",
|
||||
"CAP_SYS_MODULE",
|
||||
"CAP_SYS_RAWIO",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_SYS_PTRACE",
|
||||
"CAP_SYS_PACCT",
|
||||
"CAP_SYS_ADMIN",
|
||||
"CAP_SYS_BOOT",
|
||||
"CAP_SYS_NICE",
|
||||
"CAP_SYS_RESOURCE",
|
||||
"CAP_SYS_TIME",
|
||||
"CAP_SYS_TTY_CONFIG",
|
||||
"CAP_MKNOD",
|
||||
"CAP_LEASE",
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_AUDIT_CONTROL",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_MAC_OVERRIDE",
|
||||
"CAP_DAC_READ_SEARCH",
|
||||
"CAP_MAC_ADMIN",
|
||||
"CAP_SYSLOG",
|
||||
"CAP_WAKE_ALARM",
|
||||
"CAP_BLOCK_SUSPEND",
|
||||
"CAP_AUDIT_READ"
|
||||
],
|
||||
"permitted": [
|
||||
"CAP_CHOWN",
|
||||
"CAP_FOWNER",
|
||||
"CAP_FSETID",
|
||||
"CAP_KILL",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_LINUX_IMMUTABLE",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_BROADCAST",
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_IPC_LOCK",
|
||||
"CAP_IPC_OWNER",
|
||||
"CAP_SYS_MODULE",
|
||||
"CAP_SYS_RAWIO",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_SYS_PTRACE",
|
||||
"CAP_SYS_PACCT",
|
||||
"CAP_SYS_ADMIN",
|
||||
"CAP_SYS_BOOT",
|
||||
"CAP_SYS_NICE",
|
||||
"CAP_SYS_RESOURCE",
|
||||
"CAP_SYS_TIME",
|
||||
"CAP_SYS_TTY_CONFIG",
|
||||
"CAP_MKNOD",
|
||||
"CAP_LEASE",
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_AUDIT_CONTROL",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_MAC_OVERRIDE",
|
||||
"CAP_DAC_READ_SEARCH",
|
||||
"CAP_MAC_ADMIN",
|
||||
"CAP_SYSLOG",
|
||||
"CAP_WAKE_ALARM",
|
||||
"CAP_BLOCK_SUSPEND",
|
||||
"CAP_AUDIT_READ"
|
||||
]
|
||||
},
|
||||
"cwd": "/",
|
||||
"env": [
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/root/go/bin",
|
||||
"TERM=xterm",
|
||||
"LOG_LEVEL=$LOG_LEVEL",
|
||||
"NAME=$NAME"
|
||||
],
|
||||
"noNewPrivileges": false,
|
||||
"terminal": false,
|
||||
"user": {
|
||||
"gid": 0,
|
||||
"uid": 0
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"path": "rootfs",
|
||||
"readonly": true
|
||||
},
|
||||
"hooks": {},
|
||||
"linux": {
|
||||
"namespaces": [
|
||||
{
|
||||
"type": "mount"
|
||||
}
|
||||
],
|
||||
"resources": {
|
||||
"devices": [
|
||||
{
|
||||
"access": "rwm",
|
||||
"allow": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"rootfsPropagation": "private"
|
||||
},
|
||||
"mounts": [
|
||||
{
|
||||
"destination": "/tmp",
|
||||
"options": [
|
||||
"private",
|
||||
"bind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/tmp",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/etc",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/etc",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/lib/modules",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/lib/modules",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/root",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/root",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/home",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/home",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/mnt",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rw",
|
||||
"rprivate",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/mnt",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"type": "bind",
|
||||
"source": "${RUN_DIRECTORY}",
|
||||
"destination": "/run",
|
||||
"options": [
|
||||
"rshared",
|
||||
"rbind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "bind",
|
||||
"source": "${RUN_DIRECTORY}/systemd",
|
||||
"destination": "/run/systemd",
|
||||
"options": [
|
||||
"rslave",
|
||||
"bind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
]
|
||||
},
|
||||
{
|
||||
"destination": "/var/log",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rslave",
|
||||
"rw"
|
||||
],
|
||||
"source": "/var/log",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/var/lib",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"rw"
|
||||
],
|
||||
"source": "${STATE_DIRECTORY}",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/var/lib/containers/storage",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rshared",
|
||||
"rw"
|
||||
],
|
||||
"source": "${VAR_LIB_CONTAINERS_STORAGE}",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/var/lib/origin",
|
||||
"options": [
|
||||
"rshared",
|
||||
"bind",
|
||||
"rw"
|
||||
],
|
||||
"source": "${VAR_LIB_ORIGIN}",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/var/lib/kubelet",
|
||||
"options": [
|
||||
"rshared",
|
||||
"bind",
|
||||
"rw"
|
||||
],
|
||||
"source": "${VAR_LIB_KUBE}",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/opt/cni",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"ro",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "${OPT_CNI}",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/dev",
|
||||
"options": [
|
||||
"rprivate",
|
||||
"rbind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/dev",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/sys",
|
||||
"options": [
|
||||
"rprivate",
|
||||
"rbind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/sys",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/proc",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/proc",
|
||||
"type": "proc"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": "1.0",
|
||||
"defaultValues": {
|
||||
"LOG_LEVEL" : "info",
|
||||
"OPT_CNI" : "/opt/cni",
|
||||
"VAR_LIB_CONTAINERS_STORAGE" : "/var/lib/containers/storage",
|
||||
"VAR_LIB_ORIGIN" : "/var/lib/origin",
|
||||
"VAR_LIB_KUBE" : "/var/lib/kubelet"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Ensure that new process maintain this SELinux label
|
||||
PID=$$
|
||||
LABEL=`tr -d '\000' < /proc/$PID/attr/current`
|
||||
printf %s $LABEL > /proc/self/attr/exec
|
||||
|
||||
test -e /etc/sysconfig/crio-storage && source /etc/sysconfig/crio-storage
|
||||
test -e /etc/sysconfig/crio-network && source /etc/sysconfig/crio-network
|
||||
|
||||
exec /usr/bin/crio --log-level=$LOG_LEVEL
|
|
@ -0,0 +1,20 @@
|
|||
[Unit]
|
||||
Description=crio daemon
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
ExecStartPre=/bin/sh $DESTDIR/rootfs/set_mounts.sh
|
||||
ExecStart=$EXEC_START
|
||||
ExecStop=$EXEC_STOP
|
||||
Restart=on-failure
|
||||
WorkingDirectory=$DESTDIR
|
||||
RuntimeDirectory=${NAME}
|
||||
TasksMax=infinity
|
||||
LimitNOFILE=1048576
|
||||
LimitNPROC=1048576
|
||||
LimitCORE=infinity
|
||||
TimeoutStartSec=0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
findmnt /var/lib/containers/storage > /dev/null || mount --rbind --make-shared /var/lib/containers/storage /var/lib/containers/storage
|
||||
findmnt /var/lib/origin > /dev/null || mount --bind --make-shared /var/lib/origin /var/lib/origin
|
||||
findmnt /var/lib/kubelet > /dev/null || mount --bind --make-shared /var/lib/kubelet /var/lib/kubelet
|
||||
mount --make-shared /run
|
||||
findmnt /run/systemd > /dev/null || mount --bind --make-rslave /run/systemd /run/systemd
|
|
@ -0,0 +1,5 @@
|
|||
d ${RUN_DIRECTORY}/crio - - - - -
|
||||
d /etc/crio - - - - -
|
||||
Z /etc/crio - - - - -
|
||||
d ${STATE_DIRECTORY}/origin - - - - -
|
||||
d ${STATE_DIRECTORY}/kubelet - - - - -
|
|
@ -0,0 +1,41 @@
|
|||
#oit## This file is managed by the OpenShift Image Tool
|
||||
#oit## by the OpenShift Continuous Delivery team.
|
||||
#oit##
|
||||
#oit## Any yum repos listed in this file will effectively be ignored during CD builds.
|
||||
#oit## Yum repos must be enabled in the oit configuration files.
|
||||
#oit## Some aspects of this file may be managed programmatically. For example, the image name, labels (version,
|
||||
#oit## release, and other), and the base FROM. Changes made directly in distgit may be lost during the next
|
||||
#oit## reconciliation.
|
||||
#oit##
|
||||
FROM rhel7:7-released
|
||||
|
||||
RUN \
|
||||
yum install --setopt=tsflags=nodocs -y socat iptables cri-o iproute runc skopeo-containers container-selinux && \
|
||||
rpm -V socat iptables cri-o iproute runc skopeo-containers container-selinux && \
|
||||
yum clean all && \
|
||||
mkdir -p /exports/hostfs/etc/crio /exports/hostfs/opt/cni/bin/ /exports/hostfs/var/lib/containers/storage/ && \
|
||||
cp /etc/crio/* /exports/hostfs/etc/crio && \
|
||||
if test -e /usr/libexec/cni; then cp -Lr /usr/libexec/cni/* /exports/hostfs/opt/cni/bin/; fi
|
||||
|
||||
COPY manifest.json tmpfiles.template config.json.template service.template /exports/
|
||||
|
||||
COPY set_mounts.sh /
|
||||
COPY run.sh /usr/bin/
|
||||
|
||||
CMD ["/usr/bin/run.sh"]
|
||||
|
||||
LABEL \
|
||||
com.redhat.component="cri-o-docker" \
|
||||
io.k8s.description="CRI-O is an implementation of the Kubernetes CRI. It is a lightweight, OCI-compliant runtime that is native to kubernetes. CRI-O supports OCI container images and can pull from any container registry." \
|
||||
maintainer="Jhon Honce <jhonce@redhat.com>" \
|
||||
name="openshift3/cri-o" \
|
||||
License="GPLv2+" \
|
||||
io.k8s.display-name="CRI-O" \
|
||||
summary="OCI-based implementation of Kubernetes Container Runtime Interface" \
|
||||
release="0.13.0.0" \
|
||||
version="v3.8.0" \
|
||||
architecture="x86_64" \
|
||||
usage="atomic install --system --system-package=no crio && systemctl start crio" \
|
||||
vendor="Red Hat" \
|
||||
io.openshift.tags="cri-o system rhel7" \
|
||||
atomic.type="system"
|
|
@ -0,0 +1,422 @@
|
|||
{
|
||||
"ociVersion": "1.0.0",
|
||||
"platform": {
|
||||
"arch": "amd64",
|
||||
"os": "linux"
|
||||
},
|
||||
"process": {
|
||||
"args": [
|
||||
"/usr/bin/run.sh"
|
||||
],
|
||||
"capabilities": {
|
||||
"ambient": [
|
||||
"CAP_CHOWN",
|
||||
"CAP_FOWNER",
|
||||
"CAP_FSETID",
|
||||
"CAP_KILL",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_LINUX_IMMUTABLE",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_BROADCAST",
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_IPC_LOCK",
|
||||
"CAP_IPC_OWNER",
|
||||
"CAP_SYS_MODULE",
|
||||
"CAP_SYS_RAWIO",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_SYS_PTRACE",
|
||||
"CAP_SYS_PACCT",
|
||||
"CAP_SYS_ADMIN",
|
||||
"CAP_SYS_BOOT",
|
||||
"CAP_SYS_NICE",
|
||||
"CAP_SYS_RESOURCE",
|
||||
"CAP_SYS_TIME",
|
||||
"CAP_SYS_TTY_CONFIG",
|
||||
"CAP_MKNOD",
|
||||
"CAP_LEASE",
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_AUDIT_CONTROL",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_MAC_OVERRIDE",
|
||||
"CAP_DAC_READ_SEARCH",
|
||||
"CAP_MAC_ADMIN",
|
||||
"CAP_SYSLOG",
|
||||
"CAP_WAKE_ALARM",
|
||||
"CAP_BLOCK_SUSPEND"
|
||||
],
|
||||
"bounding": [
|
||||
"CAP_CHOWN",
|
||||
"CAP_FOWNER",
|
||||
"CAP_FSETID",
|
||||
"CAP_KILL",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_LINUX_IMMUTABLE",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_BROADCAST",
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_IPC_LOCK",
|
||||
"CAP_IPC_OWNER",
|
||||
"CAP_SYS_MODULE",
|
||||
"CAP_SYS_RAWIO",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_SYS_PTRACE",
|
||||
"CAP_SYS_PACCT",
|
||||
"CAP_SYS_ADMIN",
|
||||
"CAP_SYS_BOOT",
|
||||
"CAP_SYS_NICE",
|
||||
"CAP_SYS_RESOURCE",
|
||||
"CAP_SYS_TIME",
|
||||
"CAP_SYS_TTY_CONFIG",
|
||||
"CAP_MKNOD",
|
||||
"CAP_LEASE",
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_AUDIT_CONTROL",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_MAC_OVERRIDE",
|
||||
"CAP_DAC_READ_SEARCH",
|
||||
"CAP_MAC_ADMIN",
|
||||
"CAP_SYSLOG",
|
||||
"CAP_WAKE_ALARM",
|
||||
"CAP_BLOCK_SUSPEND"
|
||||
],
|
||||
"effective": [
|
||||
"CAP_CHOWN",
|
||||
"CAP_FOWNER",
|
||||
"CAP_FSETID",
|
||||
"CAP_KILL",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_LINUX_IMMUTABLE",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_BROADCAST",
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_IPC_LOCK",
|
||||
"CAP_IPC_OWNER",
|
||||
"CAP_SYS_MODULE",
|
||||
"CAP_SYS_RAWIO",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_SYS_PTRACE",
|
||||
"CAP_SYS_PACCT",
|
||||
"CAP_SYS_ADMIN",
|
||||
"CAP_SYS_BOOT",
|
||||
"CAP_SYS_NICE",
|
||||
"CAP_SYS_RESOURCE",
|
||||
"CAP_SYS_TIME",
|
||||
"CAP_SYS_TTY_CONFIG",
|
||||
"CAP_MKNOD",
|
||||
"CAP_LEASE",
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_AUDIT_CONTROL",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_MAC_OVERRIDE",
|
||||
"CAP_DAC_READ_SEARCH",
|
||||
"CAP_MAC_ADMIN",
|
||||
"CAP_SYSLOG",
|
||||
"CAP_WAKE_ALARM",
|
||||
"CAP_BLOCK_SUSPEND"
|
||||
],
|
||||
"inheritable": [
|
||||
"CAP_CHOWN",
|
||||
"CAP_FOWNER",
|
||||
"CAP_FSETID",
|
||||
"CAP_KILL",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_LINUX_IMMUTABLE",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_BROADCAST",
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_IPC_LOCK",
|
||||
"CAP_IPC_OWNER",
|
||||
"CAP_SYS_MODULE",
|
||||
"CAP_SYS_RAWIO",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_SYS_PTRACE",
|
||||
"CAP_SYS_PACCT",
|
||||
"CAP_SYS_ADMIN",
|
||||
"CAP_SYS_BOOT",
|
||||
"CAP_SYS_NICE",
|
||||
"CAP_SYS_RESOURCE",
|
||||
"CAP_SYS_TIME",
|
||||
"CAP_SYS_TTY_CONFIG",
|
||||
"CAP_MKNOD",
|
||||
"CAP_LEASE",
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_AUDIT_CONTROL",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_MAC_OVERRIDE",
|
||||
"CAP_DAC_READ_SEARCH",
|
||||
"CAP_MAC_ADMIN",
|
||||
"CAP_SYSLOG",
|
||||
"CAP_WAKE_ALARM",
|
||||
"CAP_BLOCK_SUSPEND"
|
||||
],
|
||||
"permitted": [
|
||||
"CAP_CHOWN",
|
||||
"CAP_FOWNER",
|
||||
"CAP_FSETID",
|
||||
"CAP_KILL",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_LINUX_IMMUTABLE",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_NET_BROADCAST",
|
||||
"CAP_NET_ADMIN",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_IPC_LOCK",
|
||||
"CAP_IPC_OWNER",
|
||||
"CAP_SYS_MODULE",
|
||||
"CAP_SYS_RAWIO",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_SYS_PTRACE",
|
||||
"CAP_SYS_PACCT",
|
||||
"CAP_SYS_ADMIN",
|
||||
"CAP_SYS_BOOT",
|
||||
"CAP_SYS_NICE",
|
||||
"CAP_SYS_RESOURCE",
|
||||
"CAP_SYS_TIME",
|
||||
"CAP_SYS_TTY_CONFIG",
|
||||
"CAP_MKNOD",
|
||||
"CAP_LEASE",
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_AUDIT_CONTROL",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_MAC_OVERRIDE",
|
||||
"CAP_DAC_READ_SEARCH",
|
||||
"CAP_MAC_ADMIN",
|
||||
"CAP_SYSLOG",
|
||||
"CAP_WAKE_ALARM",
|
||||
"CAP_BLOCK_SUSPEND"
|
||||
]
|
||||
},
|
||||
"selinuxLabel": "system_u:system_r:container_runtime_t:s0",
|
||||
"cwd": "/",
|
||||
"env": [
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/root/go/bin",
|
||||
"TERM=xterm",
|
||||
"LOG_LEVEL=$LOG_LEVEL",
|
||||
"NAME=$NAME"
|
||||
],
|
||||
"noNewPrivileges": false,
|
||||
"terminal": false,
|
||||
"user": {
|
||||
"gid": 0,
|
||||
"uid": 0
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"path": "rootfs",
|
||||
"readonly": true
|
||||
},
|
||||
"hooks": {},
|
||||
"linux": {
|
||||
"namespaces": [{
|
||||
"type": "mount"
|
||||
}],
|
||||
"resources": {
|
||||
"devices": [{
|
||||
"access": "rwm",
|
||||
"allow": true
|
||||
}]
|
||||
},
|
||||
"rootfsPropagation": "private"
|
||||
},
|
||||
"mounts": [{
|
||||
"destination": "/tmp",
|
||||
"options": [
|
||||
"private",
|
||||
"bind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/tmp",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/etc",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/etc",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/lib/modules",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/lib/modules",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/root",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/root",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/home",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/home",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/mnt",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rw",
|
||||
"rprivate",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/mnt",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"type": "bind",
|
||||
"source": "${RUN_DIRECTORY}",
|
||||
"destination": "/run",
|
||||
"options": [
|
||||
"rshared",
|
||||
"rbind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "bind",
|
||||
"source": "${RUN_DIRECTORY}/systemd",
|
||||
"destination": "/run/systemd",
|
||||
"options": [
|
||||
"rslave",
|
||||
"bind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
]
|
||||
},
|
||||
{
|
||||
"destination": "/var/log",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rslave",
|
||||
"rw"
|
||||
],
|
||||
"source": "/var/log",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/var/lib",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"rw"
|
||||
],
|
||||
"source": "${STATE_DIRECTORY}",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/var/lib/containers/storage",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rshared",
|
||||
"rw"
|
||||
],
|
||||
"source": "${VAR_LIB_CONTAINERS_STORAGE}",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/var/lib/origin",
|
||||
"options": [
|
||||
"rshared",
|
||||
"bind",
|
||||
"rw"
|
||||
],
|
||||
"source": "${VAR_LIB_ORIGIN}",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/var/lib/kubelet",
|
||||
"options": [
|
||||
"rshared",
|
||||
"bind",
|
||||
"rw"
|
||||
],
|
||||
"source": "${VAR_LIB_KUBE}",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/opt/cni",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rprivate",
|
||||
"ro",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "${OPT_CNI}",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/dev",
|
||||
"options": [
|
||||
"rprivate",
|
||||
"rbind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/dev",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/sys",
|
||||
"options": [
|
||||
"rprivate",
|
||||
"rbind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/sys",
|
||||
"type": "bind"
|
||||
},
|
||||
{
|
||||
"destination": "/proc",
|
||||
"options": [
|
||||
"rbind",
|
||||
"rw",
|
||||
"mode=755"
|
||||
],
|
||||
"source": "/proc",
|
||||
"type": "proc"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
% CRI-O (1) Container Image Pages
|
||||
% Jhon Honce
|
||||
% September 7, 2017
|
||||
|
||||
# NAME
|
||||
cri-o - OCI-based implementation of Kubernetes Container Runtime Interface
|
||||
|
||||
# DESCRIPTION
|
||||
CRI-O is an implementation of the Kubernetes CRI. It is a lightweight, OCI-compliant runtime that is native to kubernetes. CRI-O supports OCI container images and can pull from any container registry.
|
||||
|
||||
You can find more information on the CRI-O project at <https://github.com/kubernetes-incubator/cri-o/>
|
||||
|
||||
# USAGE
|
||||
Pull from local docker and install system container:
|
||||
|
||||
```
|
||||
# atomic pull --storage ostree docker:openshift3/cri-o:latest
|
||||
# atomic install --system --system-package=no --name cri-o openshift3/cri-o
|
||||
```
|
||||
|
||||
Start and enable as a systemd service:
|
||||
```
|
||||
# systemctl enable --now cri-o
|
||||
```
|
||||
|
||||
Stopping the service
|
||||
```
|
||||
# systemctl stop cri-o
|
||||
```
|
||||
|
||||
Removing the container
|
||||
```
|
||||
# atomic uninstall cri-o
|
||||
```
|
||||
|
||||
# SEE ALSO
|
||||
man systemd(1)
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": "1.0",
|
||||
"defaultValues": {
|
||||
"LOG_LEVEL": "info",
|
||||
"OPT_CNI": "/opt/cni",
|
||||
"VAR_LIB_CONTAINERS_STORAGE": "/var/lib/containers/storage",
|
||||
"VAR_LIB_ORIGIN": "/var/lib/origin",
|
||||
"VAR_LIB_KUBE": "/var/lib/kubelet"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Ensure that new process maintain this SELinux label
|
||||
PID=$$
|
||||
LABEL=`tr -d '\000' < /proc/$PID/attr/current`
|
||||
printf %s $LABEL > /proc/self/attr/exec
|
||||
|
||||
test -e /etc/sysconfig/crio-storage && source /etc/sysconfig/crio-storage
|
||||
test -e /etc/sysconfig/crio-network && source /etc/sysconfig/crio-network
|
||||
|
||||
exec /usr/bin/crio --log-level=$LOG_LEVEL
|
|
@ -0,0 +1,20 @@
|
|||
[Unit]
|
||||
Description=crio daemon
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
ExecStartPre=/bin/sh $DESTDIR/rootfs/set_mounts.sh
|
||||
ExecStart=$EXEC_START
|
||||
ExecStop=$EXEC_STOP
|
||||
Restart=on-failure
|
||||
WorkingDirectory=$DESTDIR
|
||||
RuntimeDirectory=${NAME}
|
||||
TasksMax=infinity
|
||||
LimitNOFILE=1048576
|
||||
LimitNPROC=1048576
|
||||
LimitCORE=infinity
|
||||
TimeoutStartSec=0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
findmnt /var/lib/containers/storage > /dev/null || mount --rbind --make-shared /var/lib/containers/storage /var/lib/containers/storage
|
||||
findmnt /var/lib/origin > /dev/null || mount --bind --make-shared /var/lib/origin /var/lib/origin
|
||||
findmnt /var/lib/kubelet > /dev/null || mount --bind --make-shared /var/lib/kubelet /var/lib/kubelet
|
||||
mount --make-shared /run
|
||||
findmnt /run/systemd > /dev/null || mount --bind --make-rslave /run/systemd /run/systemd
|
|
@ -0,0 +1,5 @@
|
|||
d ${RUN_DIRECTORY}/crio - - - - -
|
||||
d /etc/crio - - - - -
|
||||
Z /etc/crio - - - - -
|
||||
d ${STATE_DIRECTORY}/origin - - - - -
|
||||
d ${STATE_DIRECTORY}/kubelet - - - - -
|
|
@ -12,7 +12,7 @@ ExecStart=/usr/local/bin/crio \
|
|||
$CRIO_STORAGE_OPTIONS \
|
||||
$CRIO_NETWORK_OPTIONS
|
||||
ExecReload=/bin/kill -s HUP $MAINPID
|
||||
TasksMax=8192
|
||||
TasksMax=infinity
|
||||
LimitNOFILE=1048576
|
||||
LimitNPROC=1048576
|
||||
LimitCORE=infinity
|
||||
|
|
|
@ -4,13 +4,23 @@
|
|||
git:
|
||||
repo: "https://github.com/kubernetes-incubator/cri-tools.git"
|
||||
dest: "{{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator/cri-tools"
|
||||
version: "16e6fe4d7199c5689db4630a9330e6a8a12cecd1"
|
||||
version: "{{ cri_tools_git_version }}"
|
||||
force: "{{ force_clone | default(False) | bool}}"
|
||||
|
||||
- name: install crictl
|
||||
command: "/usr/bin/go install github.com/kubernetes-incubator/cri-tools/cmd/crictl"
|
||||
|
||||
- name: install critest
|
||||
command: "/usr/bin/go install github.com/kubernetes-incubator/cri-tools/cmd/critest"
|
||||
|
||||
- name: link crictl
|
||||
file:
|
||||
src: "{{ ansible_env.GOPATH }}/bin/crictl"
|
||||
dest: /usr/bin/crictl
|
||||
state: link
|
||||
|
||||
- name: link critest
|
||||
file:
|
||||
src: "{{ ansible_env.GOPATH }}/bin/critest"
|
||||
dest: /usr/bin/critest
|
||||
state: link
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
|
||||
- name: clone kubernetes source repo
|
||||
git:
|
||||
repo: "https://github.com/runcom/kubernetes.git"
|
||||
repo: "https://github.com/{{ k8s_github_fork }}/kubernetes.git"
|
||||
dest: "{{ ansible_env.GOPATH }}/src/k8s.io/kubernetes"
|
||||
version: "cri-o-node-e2e-patched"
|
||||
# based on kube v1.9.0-alpha.2, update as needed
|
||||
version: "{{ k8s_git_version }}"
|
||||
force: "{{ force_clone | default(False) | bool}}"
|
||||
|
||||
- name: install etcd
|
||||
command: "hack/install-etcd.sh"
|
||||
|
@ -38,13 +40,15 @@
|
|||
export PATH=/usr/local/go/bin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/root/bin:{{ ansible_env.GOPATH }}/bin:{{ ansible_env.GOPATH }}/src/k8s.io/kubernetes/third_party/etcd:{{ ansible_env.GOPATH }}/src/k8s.io/kubernetes/_output/local/bin/linux/amd64/
|
||||
export CONTAINER_RUNTIME=remote
|
||||
export CGROUP_DRIVER=systemd
|
||||
export CONTAINER_RUNTIME_ENDPOINT='/var/run/crio.sock --runtime-request-timeout=5m'
|
||||
export CONTAINER_RUNTIME_ENDPOINT='{{ crio_socket }} --runtime-request-timeout=5m'
|
||||
export ALLOW_SECURITY_CONTEXT=","
|
||||
export ALLOW_PRIVILEGED=1
|
||||
export DNS_SERVER_IP={{ ansible_eth0.ipv4.address }}
|
||||
export API_HOST={{ ansible_eth0.ipv4.address }}
|
||||
export API_HOST_IP={{ ansible_eth0.ipv4.address }}
|
||||
export DNS_SERVER_IP={{ ansible_default_ipv4.address }}
|
||||
export API_HOST={{ ansible_default_ipv4.address }}
|
||||
export API_HOST_IP={{ ansible_default_ipv4.address }}
|
||||
export KUBE_ENABLE_CLUSTER_DNS=true
|
||||
export ENABLE_HOSTPATH_PROVISIONER=true
|
||||
export KUBE_ENABLE_CLUSTER_DASHBOARD=true
|
||||
./hack/local-up-cluster.sh
|
||||
mode: "u=rwx,g=rwx,o=x"
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
git:
|
||||
repo: "https://github.com/opencontainers/runc.git"
|
||||
dest: "{{ ansible_env.GOPATH }}/src/github.com/opencontainers/runc"
|
||||
version: "c6e4a1ebeb1a72b529c6f1b6ee2b1ae5b868b14f"
|
||||
|
||||
- name: build runc
|
||||
make:
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
|
||||
- name: enable and start CRI-O
|
||||
systemd:
|
||||
name: crio
|
||||
state: started
|
||||
enabled: yes
|
||||
daemon_reload: yes
|
||||
|
||||
- name: Flush the iptables
|
||||
command: iptables -F
|
||||
|
||||
- name: Enable localnet routing
|
||||
command: sysctl -w net.ipv4.conf.all.route_localnet=1
|
||||
|
||||
- name: Add masquerade for localhost
|
||||
command: iptables -t nat -I POSTROUTING -s 127.0.0.1 ! -d 127.0.0.1 -j MASQUERADE
|
||||
|
||||
- name: run critest validation
|
||||
shell: "critest -c --runtime-endpoint /var/run/crio/crio.sock --image-endpoint /var/run/crio/crio.sock v"
|
||||
args:
|
||||
chdir: "{{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator/cri-o"
|
||||
async: 5400
|
||||
poll: 30
|
||||
when: ansible_distribution not in ['RedHat', 'CentOS']
|
||||
|
||||
# XXX: RHEL has an additional test which fails because of selinux but disabling
|
||||
# it doesn't solve the issue.
|
||||
# TODO(runcom): enable skipped tests once we fix them (selinux)
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1414236
|
||||
# https://access.redhat.com/solutions/2897781
|
||||
- name: run critest validation
|
||||
shell: "critest -c --runtime-endpoint /var/run/crio/crio.sock --image-endpoint /var/run/crio/crio.sock -s 'should not allow privilege escalation when true' v"
|
||||
args:
|
||||
chdir: "{{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator/cri-o"
|
||||
async: 5400
|
||||
poll: 30
|
||||
when: ansible_distribution in ['RedHat', 'CentOS']
|
||||
|
||||
- name: run critest benchmarks
|
||||
shell: "critest -c --runtime-endpoint /var/run/crio/crio.sock --image-endpoint /var/run/crio/crio.sock b"
|
||||
args:
|
||||
chdir: "{{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator/cri-o"
|
||||
async: 5400
|
||||
poll: 30
|
|
@ -10,7 +10,7 @@
|
|||
- name: update the server address for the custom cluster
|
||||
lineinfile:
|
||||
dest: /usr/local/bin/createcluster.sh
|
||||
line: "export {{ item }}={{ ansible_eth0.ipv4.address }}"
|
||||
line: "export {{ item }}={{ ansible_default_ipv4.address }}"
|
||||
regexp: "^export {{ item }}="
|
||||
state: present
|
||||
with_items:
|
||||
|
@ -37,13 +37,14 @@
|
|||
path: "{{ artifacts }}"
|
||||
state: directory
|
||||
|
||||
# TODO remove the last test skipped once https://github.com/kubernetes-incubator/cri-o/pull/1217 is merged
|
||||
- name: Buffer the e2e testing command to workaround Ansible YAML folding "feature"
|
||||
set_fact:
|
||||
e2e_shell_cmd: >
|
||||
/usr/bin/go run hack/e2e.go
|
||||
--test
|
||||
-test_args="-host=https://{{ ansible_default_ipv4.address }}:6443
|
||||
--ginkgo.focus=\[Conformance\]
|
||||
--test_args="-host=https://{{ ansible_default_ipv4.address }}:6443
|
||||
--ginkgo.skip=\[Slow\]|\[Serial\]|\[Disruptive\]|\[Flaky\]|\[Feature:.+\]|PersistentVolumes|\[HPA\]|should.support.building.a.client.with.a.CSR|should.support.inline.execution.and.attach
|
||||
--report-dir={{ artifacts }}"
|
||||
&> {{ artifacts }}/e2e.log
|
||||
# Fix vim syntax hilighting: "
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
---
|
||||
|
||||
- name: ensure Golang dir is empty first
|
||||
file:
|
||||
path: /usr/local/go
|
||||
state: absent
|
||||
|
||||
- name: fetch Golang
|
||||
unarchive:
|
||||
remote_src: yes
|
||||
src: https://storage.googleapis.com/golang/go1.8.4.linux-amd64.tar.gz
|
||||
src: "https://storage.googleapis.com/golang/go{{ version }}.linux-amd64.tar.gz"
|
||||
dest: /usr/local
|
||||
|
||||
- name: link go toolchain
|
||||
|
@ -47,5 +52,4 @@
|
|||
- onsi/gomega
|
||||
- cloudflare/cfssl/cmd/...
|
||||
- jteeuwen/go-bindata/go-bindata
|
||||
- vbatts/git-validation
|
||||
- cpuguy83/go-md2man
|
||||
|
|
|
@ -10,15 +10,23 @@
|
|||
|
||||
- name: install Golang tools
|
||||
include: golang.yml
|
||||
vars:
|
||||
version: "1.8.5"
|
||||
|
||||
- name: clone build and install bats
|
||||
include: "build/bats.yml"
|
||||
|
||||
- name: clone build and install cri-tools
|
||||
include: "build/cri-tools.yml"
|
||||
vars:
|
||||
cri_tools_git_version: "b42fc3f364dd48f649d55926c34492beeb9b2e99"
|
||||
|
||||
- name: clone build and install kubernetes
|
||||
include: "build/kubernetes.yml"
|
||||
vars:
|
||||
k8s_git_version: "cri-o-node-e2e-patched-logs"
|
||||
k8s_github_fork: "runcom"
|
||||
crio_socket: "/var/run/crio.sock"
|
||||
|
||||
- name: clone build and install runc
|
||||
include: "build/runc.yml"
|
||||
|
@ -33,6 +41,8 @@
|
|||
tags:
|
||||
- integration
|
||||
- e2e
|
||||
- node-e2e
|
||||
- critest
|
||||
tasks:
|
||||
- name: clone build and install cri-o
|
||||
include: "build/cri-o.yml"
|
||||
|
@ -44,9 +54,54 @@
|
|||
tags:
|
||||
- integration
|
||||
tasks:
|
||||
- name: clone build and install cri-tools
|
||||
include: "build/cri-tools.yml"
|
||||
vars:
|
||||
force_clone: True
|
||||
cri_tools_git_version: "a9e38a4a000bc1a4052fb33de1c967b8cfe9ad40"
|
||||
- name: run cri-o integration tests
|
||||
include: test.yml
|
||||
|
||||
- hosts: all
|
||||
remote_user: root
|
||||
vars_files:
|
||||
- "{{ playbook_dir }}/vars.yml"
|
||||
tags:
|
||||
- critest
|
||||
tasks:
|
||||
- name: install Golang tools
|
||||
include: golang.yml
|
||||
vars:
|
||||
version: "1.9.2"
|
||||
- name: setup critest
|
||||
include: "build/cri-tools.yml"
|
||||
vars:
|
||||
force_clone: True
|
||||
cri_tools_git_version: "a9e38a4a000bc1a4052fb33de1c967b8cfe9ad40"
|
||||
- name: run critest validation and benchmarks
|
||||
include: critest.yml
|
||||
|
||||
- hosts: all
|
||||
remote_user: root
|
||||
vars_files:
|
||||
- "{{ playbook_dir }}/vars.yml"
|
||||
tags:
|
||||
- node-e2e
|
||||
tasks:
|
||||
- name: install Golang tools
|
||||
include: golang.yml
|
||||
vars:
|
||||
version: "1.9.2"
|
||||
- name: clone build and install kubernetes
|
||||
include: "build/kubernetes.yml"
|
||||
vars:
|
||||
force_clone: True
|
||||
k8s_git_version: "master"
|
||||
k8s_github_fork: "kubernetes"
|
||||
crio_socket: "/var/run/crio/crio.sock"
|
||||
- name: run k8s node-e2e tests
|
||||
include: node-e2e.yml
|
||||
|
||||
- hosts: all
|
||||
remote_user: root
|
||||
vars_files:
|
||||
|
@ -54,5 +109,17 @@
|
|||
tags:
|
||||
- e2e
|
||||
tasks:
|
||||
- name: install Golang tools
|
||||
include: golang.yml
|
||||
vars:
|
||||
version: "1.9.2"
|
||||
- name: clone build and install kubernetes
|
||||
include: "build/kubernetes.yml"
|
||||
vars:
|
||||
force_clone: True
|
||||
# master as of 12/11/2017
|
||||
k8s_git_version: "master-nfs-fix"
|
||||
k8s_github_fork: "runcom"
|
||||
crio_socket: "/var/run/crio/crio.sock"
|
||||
- name: run k8s e2e tests
|
||||
include: e2e.yml
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
|
||||
- name: enable and start CRI-O
|
||||
systemd:
|
||||
name: crio
|
||||
state: started
|
||||
enabled: yes
|
||||
daemon_reload: yes
|
||||
|
||||
- name: disable SELinux
|
||||
command: setenforce 0
|
||||
|
||||
- name: Flush the iptables
|
||||
command: iptables -F
|
||||
|
||||
- name: run node-e2e tests
|
||||
shell: |
|
||||
# parametrize crio socket
|
||||
# cgroup-driver???
|
||||
# TODO(runcom): remove conformance focus, we want everything for testgrid
|
||||
make test-e2e-node PARALLELISM=1 RUNTIME=remote CONTAINER_RUNTIME_ENDPOINT=/var/run/crio.sock IMAGE_SERVICE_ENDPOINT=/var/run/crio/crio.sock TEST_ARGS='--prepull-images=true --kubelet-flags="--cgroup-driver=systemd"' FOCUS="\[Conformance\]" &> {{ artifacts }}/node-e2e.log
|
||||
args:
|
||||
chdir: "{{ ansible_env.GOPATH }}/src/k8s.io/kubernetes"
|
||||
async: 7200
|
||||
poll: 10
|
||||
ignore_errors: true
|
|
@ -5,6 +5,7 @@
|
|||
name: "{{ item }}"
|
||||
state: present
|
||||
with_items:
|
||||
- atomic-registries
|
||||
- container-selinux
|
||||
- curl
|
||||
- device-mapper-devel
|
||||
|
@ -41,9 +42,9 @@
|
|||
- ostree-devel
|
||||
- pkgconfig
|
||||
- python
|
||||
- python2-boto
|
||||
- python2-crypto
|
||||
- python-devel
|
||||
- python-rhsm-certificates
|
||||
- python-virtualenv
|
||||
- PyYAML
|
||||
- redhat-rpm-config
|
||||
|
@ -57,6 +58,22 @@
|
|||
async: 600
|
||||
poll: 10
|
||||
|
||||
- name: Add python2-boto for Fedora
|
||||
package:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
with_items:
|
||||
- python2-boto
|
||||
when: ansible_distribution in ['Fedora']
|
||||
|
||||
- name: Add python-boto for RHEL and CentOS
|
||||
package:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
with_items:
|
||||
- python-boto
|
||||
when: ansible_distribution in ['RedHat', 'CentOS']
|
||||
|
||||
- name: Add Btrfs for Fedora
|
||||
package:
|
||||
name: "{{ item }}"
|
||||
|
@ -106,6 +123,12 @@
|
|||
- name: Flush the iptables
|
||||
command: iptables -F
|
||||
|
||||
- name: Enable localnet routing
|
||||
command: sysctl -w net.ipv4.conf.all.route_localnet=1
|
||||
|
||||
- name: Add masquerade for localhost
|
||||
command: iptables -t nat -I POSTROUTING -s 127.0.0.1 ! -d 127.0.0.1 -j MASQUERADE
|
||||
|
||||
- name: Update the kernel cmdline to include quota support
|
||||
command: grubby --update-kernel=ALL --args="rootflags=pquota"
|
||||
when: ansible_distribution in ['RedHat', 'CentOS']
|
||||
when: ansible_distribution in ['RedHat', 'CentOS']
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
state: directory
|
||||
|
||||
- name: run integration tests
|
||||
shell: "CGROUP_MANAGER=cgroupfs STORAGE_OPTS='--storage-driver=overlay{{ extra_storage_opts | default('') }}' make localintegration >& {{ artifacts }}/testout.txt"
|
||||
shell: "CGROUP_MANAGER=cgroupfs STORAGE_OPTIONS='--storage-driver=overlay{{ extra_storage_opts | default('') }}' make localintegration >& {{ artifacts }}/testout.txt"
|
||||
args:
|
||||
chdir: "{{ ansible_env.GOPATH }}/src/github.com/kubernetes-incubator/cri-o"
|
||||
async: 5400
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
runtime-endpoint: /var/run/crio/crio.sock
|
193
docs/crio.8.md
193
docs/crio.8.md
|
@ -5,166 +5,131 @@
|
|||
crio - OCI Kubernetes Container Runtime daemon
|
||||
|
||||
# SYNOPSIS
|
||||
**crio**
|
||||
[**--apparmor-profile**=[*value*]]
|
||||
[**--cgroup-manager**=[*value*]]
|
||||
[**--cni-config-dir**=[*value*]]
|
||||
[**--cni-plugin-dir**=[*value*]]
|
||||
[**--config**=[*value*]]
|
||||
[**--conmon**=[*value*]]
|
||||
[**--cpu-profile**=[*value*]]
|
||||
[**--default-transport**=[*value*]]
|
||||
[**--help**|**-h**]
|
||||
[**--insecure-registry**=[*value*]]
|
||||
[**--listen**=[*value*]]
|
||||
[**--log**=[*value*]]
|
||||
[**--log-format value**]
|
||||
[**--log-level value**]
|
||||
[**--pause-command**=[*value*]]
|
||||
[**--pause-image**=[*value*]]
|
||||
[**--registry**=[*value*]]
|
||||
[**--root**=[*value*]]
|
||||
[**--runroot**=[*value*]]
|
||||
[**--runtime**=[*value*]]
|
||||
[**--seccomp-profile**=[*value*]]
|
||||
[**--selinux**]
|
||||
[**--signature-policy**=[*value*]]
|
||||
[**--storage-driver**=[*value*]]
|
||||
[**--storage-opt**=[*value*]]
|
||||
[**--version**|**-v**]
|
||||
|
||||
crio
|
||||
```
|
||||
[--apparmor-profile=[value]]
|
||||
[--cgroup-manager=[value]]
|
||||
[--cni-config-dir=[value]]
|
||||
[--cni-plugin-dir=[value]]
|
||||
[--config=[value]]
|
||||
[--conmon=[value]]
|
||||
[--cpu-profile=[value]]
|
||||
[--default-transport=[value]]
|
||||
[--help|-h]
|
||||
[--insecure-registry=[value]]
|
||||
[--listen=[value]]
|
||||
[--log=[value]]
|
||||
[--log-format value]
|
||||
[--log-level value]
|
||||
[--pause-command=[value]]
|
||||
[--pause-image=[value]]
|
||||
[--registry=[value]]
|
||||
[--root=[value]]
|
||||
[--runroot=[value]]
|
||||
[--runtime=[value]]
|
||||
[--seccomp-profile=[value]]
|
||||
[--selinux]
|
||||
[--signature-policy=[value]]
|
||||
[--storage-driver=[value]]
|
||||
[--storage-opt=[value]]
|
||||
[--version|-v]
|
||||
```
|
||||
# DESCRIPTION
|
||||
OCI-based implementation of Kubernetes Container Runtime Interface Daemon
|
||||
|
||||
crio is meant to provide an integration path between OCI conformant runtimes and the kubelet. Specifically, it implements the Kubelet Container Runtime Interface (CRI) using OCI conformant runtimes. The scope of crio is tied to the scope of the CRI.
|
||||
|
||||
* Support multiple image formats including the existing Docker image format
|
||||
* Support for multiple means to download images including trust & image verification
|
||||
* Container image management (managing image layers, overlay filesystems, etc)
|
||||
* Container process lifecycle management
|
||||
* Monitoring and logging required to satisfy the CRI
|
||||
* Resource isolation as required by the CRI
|
||||
|
||||
**crio [GLOBAL OPTIONS]**
|
||||
|
||||
**crio [GLOBAL OPTIONS] config [OPTIONS]**
|
||||
1. Support multiple image formats including the existing Docker image format.
|
||||
2. Support for multiple means to download images including trust & image verification.
|
||||
3. Container image management (managing image layers, overlay filesystems, etc).
|
||||
4. Container process lifecycle management.
|
||||
5. Monitoring and logging required to satisfy the CRI.
|
||||
6. Resource isolation as required by the CRI.
|
||||
|
||||
**Usage**:
|
||||
```
|
||||
crio [GLOBAL OPTIONS]
|
||||
crio [GLOBAL OPTIONS] config [OPTIONS]
|
||||
```
|
||||
# GLOBAL OPTIONS
|
||||
**--apparmor_profile**="": Name of the apparmor profile to be used as the runtime's default (default: "crio-default")
|
||||
|
||||
**--apparmor_profile**=""
|
||||
Name of the apparmor profile to be used as the runtime's default (default: "crio-default")
|
||||
**--cgroup-manager**="": cgroup manager (cgroupfs or systemd)
|
||||
|
||||
**--cgroup-manager**=""
|
||||
cgroup manager (cgroupfs or systemd)
|
||||
**--config**="": path to configuration file
|
||||
|
||||
**--config**=""
|
||||
path to configuration file
|
||||
**--conmon**="": path to the conmon executable (default: "/usr/local/libexec/crio/conmon")
|
||||
|
||||
**--conmon**=""
|
||||
path to the conmon executable (default: "/usr/local/libexec/crio/conmon")
|
||||
**--cpu-profile**="": set the CPU profile file path
|
||||
|
||||
**--cpu-profile**=""
|
||||
set the CPU profile file path
|
||||
**--default-transport**: A prefix to prepend to image names that can't be pulled as-is.
|
||||
|
||||
**--default-transport**
|
||||
A prefix to prepend to image names that can't be pulled as-is.
|
||||
**--help, -h**: Print usage statement
|
||||
|
||||
**--help, -h**
|
||||
Print usage statement
|
||||
**--insecure-registry=**: Enable insecure registry communication, i.e., enable un-encrypted and/or untrusted communication.
|
||||
|
||||
**--insecure-registry=**
|
||||
Enable insecure registry communication, i.e., enable un-encrypted
|
||||
and/or untrusted communication.
|
||||
1. List of insecure registries can contain an element with CIDR notation to specify a whole subnet.
|
||||
2. Insecure registries accept HTTP or accept HTTPS with certificates from unknown CAs.
|
||||
3. Enabling `--insecure-registry` is useful when running a local registry. However, because its use creates security vulnerabilities, **it should ONLY be enabled for testing purposes**. For increased security, users should add their CA to their system's list of trusted CAs instead of using `--insecure-registry`.
|
||||
|
||||
List of insecure registries can contain an element with CIDR notation
|
||||
to specify a whole subnet. Insecure registries accept HTTP and/or
|
||||
accept HTTPS with certificates from unknown CAs.
|
||||
**--image-volumes**="": Image volume handling ('mkdir', 'bind' or 'ignore') (default: "mkdir")
|
||||
|
||||
Enabling --insecure-registry is useful when running a local registry.
|
||||
However, because its use creates security vulnerabilities it should
|
||||
ONLY be enabled for testing purposes. For increased security, users
|
||||
should add their CA to their system's list of trusted CAs instead of
|
||||
using --insecure-registry.
|
||||
1. mkdir: A directory is created inside the container root filesystem for the volumes.
|
||||
2. bind: A directory is created inside container state directory and bind mounted into the container for the volumes.
|
||||
3. ignore: All volumes are just ignored and no action is taken.
|
||||
|
||||
**--image-volumes**=""
|
||||
Image volume handling ('mkdir', 'bind' or 'ignore') (default: "mkdir")
|
||||
mkdir: A directory is created inside the container root filesystem for the volumes.
|
||||
bind: A directory is created inside container state directory and bind mounted into
|
||||
the container for the volumes.
|
||||
ignore: All volumes are just ignored and no action is taken.
|
||||
**--listen**="": Path to CRI-O socket (default: "/var/run/crio/crio.sock")
|
||||
|
||||
**--listen**=""
|
||||
Path to crio socket (default: "/var/run/crio.sock")
|
||||
**--log**="": Set the log file path where internal debug information is written
|
||||
|
||||
**--log**=""
|
||||
Set the log file path where internal debug information is written
|
||||
**--log-format**="": Set the format used by logs ('text' (default), or 'json') (default: "text")
|
||||
|
||||
**--log-format**=""
|
||||
Set the format used by logs ('text' (default), or 'json') (default: "text")
|
||||
**--log-level**="": log crio messages above specified level: debug, info (default), warn, error, fatal or panic
|
||||
|
||||
**--log-level**=""
|
||||
log CRI-O messages above specified level: debug, info (default), warn, error, fatal or panic
|
||||
**--log-size-max**="": Maximum log size in bytes for a container (default: -1 (no limit)). If it is positive, it must be >= 8192 (to match/exceed conmon read buffer).
|
||||
|
||||
**--log-size-max**=""
|
||||
Maximum log size in bytes for a container (default: -1 (no limit)).
|
||||
If it is positive, it must be >= 8192 (to match/exceed conmon read buffer).
|
||||
**--pause-command**="": Path to the pause executable in the pause image (default: "/pause")
|
||||
|
||||
**--pause-command**=""
|
||||
Path to the pause executable in the pause image (default: "/pause")
|
||||
**--pause-image**="": Image which contains the pause executable (default: "kubernetes/pause")
|
||||
|
||||
**--pause-image**=""
|
||||
Image which contains the pause executable (default: "kubernetes/pause")
|
||||
**--pids-limit**="": Maximum number of processes allowed in a container (default: 1024)
|
||||
|
||||
**--pids-limit**=""
|
||||
Maximum number of processes allowed in a container (default: 1024)
|
||||
**--enable-shared-pid-namespace**="": Enable using a shared PID namespace for containers in a pod (default: false)
|
||||
|
||||
**--root**=""
|
||||
CRIO root dir (default: "/var/lib/containers/storage")
|
||||
**--root**="": The crio root dir (default: "/var/lib/containers/storage")
|
||||
|
||||
**--registry**=""
|
||||
Registry host which will be prepended to unqualified images, can be specified multiple times
|
||||
**--registry**="": Registry host which will be prepended to unqualified images, can be specified multiple times
|
||||
|
||||
**--runroot**=""
|
||||
CRIO state dir (default: "/var/run/containers/storage")
|
||||
**--runroot**="": The crio state dir (default: "/var/run/containers/storage")
|
||||
|
||||
**--runtime**=""
|
||||
OCI runtime path (default: "/usr/bin/runc")
|
||||
**--runtime**="": OCI runtime path (default: "/usr/bin/runc")
|
||||
|
||||
**--selinux**=*true*|*false*
|
||||
Enable selinux support (default: false)
|
||||
**--selinux**=**true**|**false**: Enable selinux support (default: false)
|
||||
|
||||
**--seccomp-profile**=""
|
||||
Path to the seccomp json profile to be used as the runtime's default (default: "/etc/crio/seccomp.json")
|
||||
**--seccomp-profile**="": Path to the seccomp json profile to be used as the runtime's default (default: "/etc/crio/seccomp.json")
|
||||
|
||||
**--signature-policy**=""
|
||||
Path to the signature policy json file (default: "", to use the system-wide default)
|
||||
**--signature-policy**="": Path to the signature policy json file (default: "", to use the system-wide default)
|
||||
|
||||
**--storage-driver**
|
||||
OCI storage driver (default: "devicemapper")
|
||||
**--storage-driver**: OCI storage driver (default: "devicemapper")
|
||||
|
||||
**--storage-opt**
|
||||
OCI storage driver option (no default)
|
||||
**--storage-opt**: OCI storage driver option (no default)
|
||||
|
||||
**--cni-config-dir**=""
|
||||
CNI configuration files directory (default: "/etc/cni/net.d/")
|
||||
**--cni-config-dir**="": CNI configuration files directory (default: "/etc/cni/net.d/")
|
||||
|
||||
**--cni-plugin-dir**=""
|
||||
CNI plugin binaries directory (default: "/opt/cni/bin/")
|
||||
**--cni-plugin-dir**="": CNI plugin binaries directory (default: "/opt/cni/bin/")
|
||||
|
||||
**--cpu-profile**
|
||||
Set the CPU profile file path
|
||||
**--cpu-profile**: Set the CPU profile file path
|
||||
|
||||
**--version, -v**
|
||||
Print the version
|
||||
**--version, -v**: Print the version
|
||||
|
||||
# COMMANDS
|
||||
CRIO's default command is to start the daemon. However, it currently offers a
|
||||
CRI-O's default command is to start the daemon. However, it currently offers a
|
||||
single additional subcommand.
|
||||
|
||||
## config
|
||||
|
||||
Outputs a commented version of the configuration file that would've been used
|
||||
by CRIO. This allows you to save you current configuration setup and then load
|
||||
by CRI-O. This allows you to save you current configuration setup and then load
|
||||
it later with **--config**. Global options will modify the output.
|
||||
|
||||
**--default**
|
||||
|
|
|
@ -68,7 +68,7 @@ Example:
|
|||
## CRIO.API TABLE
|
||||
|
||||
**listen**=""
|
||||
Path to crio socket (default: "/var/run/crio.sock")
|
||||
Path to crio socket (default: "/var/run/crio/crio.sock")
|
||||
|
||||
## CRIO.RUNTIME TABLE
|
||||
|
||||
|
@ -87,6 +87,9 @@ Example:
|
|||
**pids_limit**=""
|
||||
Maximum number of processes allowed in a container (default: 1024)
|
||||
|
||||
**enable_shared_pid_namespace**=""
|
||||
Enable using a shared PID namespace for containers in a pod (default: false)
|
||||
|
||||
**runtime**=""
|
||||
OCI runtime path (default: "/usr/bin/runc")
|
||||
|
||||
|
@ -105,6 +108,9 @@ Example:
|
|||
**no_pivot**=*true*|*false*
|
||||
Instructs the runtime to not use pivot_root, but instead use MS_MOVE
|
||||
|
||||
**default_mounts**=[]
|
||||
List of mount points, in the form host:container, to be mounted in every container
|
||||
|
||||
## CRIO.IMAGE TABLE
|
||||
|
||||
**default_transport**
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
% kpod(1) kpod-attach - See the output of pid 1 of a container or enter the container
|
||||
% Dan Walsh
|
||||
# kpod-attach "1" "September 2017" "kpod"
|
||||
|
||||
## NAME
|
||||
kpod-attach - Attach to a running container
|
||||
|
||||
## Description
|
||||
|
||||
We chose not to implement the `attach` feature in `kpod` even though the upstream Docker
|
||||
project has it. The upstream project has had lots of issues with attaching to running
|
||||
processes that we did not want to replicate. The `kpod exec` and `kpod log` commands
|
||||
offer you the same functionality far more dependably.
|
||||
|
||||
**Reasons to attach to the primary PID of a container:**
|
||||
|
||||
|
||||
1) Executing commands inside of the container
|
||||
|
||||
We recommend that you use `kpod exec` to execute a command within a container
|
||||
|
||||
`kpod exec CONTAINERID /bin/sh`
|
||||
|
||||
2) Viewing the output stream of the primary process in the container
|
||||
|
||||
We recommend that you use `kpod logs` to see the output from the container
|
||||
|
||||
`kpod logs CONTAINERID`
|
||||
|
||||
## SEE ALSO
|
||||
kpod(1), kpod-exec(1), kpod-logs(1)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue