Bump github.com/docker/docker to latest release (#1866)

* Bump github.com/docker/docker to latest release

* Pin deps to docker/docker's requirements

fix build breakages
fix unit test
Trying to see whether am-i-in-a-container checks are broken for integration tests...
This commit is contained in:
Jason Hall
2022-01-14 15:58:32 -05:00
committed by GitHub
parent d587122a9d
commit 76624697df
1457 changed files with 103937 additions and 40342 deletions
+177 -18
View File
@@ -4,6 +4,7 @@
Aanand Prasad <aanand.prasad@gmail.com>
Aaron Davidson <aaron@databricks.com>
Aaron Feng <aaron.feng@gmail.com>
Aaron Hnatiw <aaron@griddio.com>
Aaron Huslage <huslage@gmail.com>
Aaron L. Xu <liker.xu@foxmail.com>
Aaron Lehmann <aaron.lehmann@docker.com>
@@ -17,6 +18,7 @@ Abhishek Chanda <abhishek.becs@gmail.com>
Abhishek Sharma <abhishek@asharma.me>
Abin Shahab <ashahab@altiscale.com>
Adam Avilla <aavilla@yp.com>
Adam Dobrawy <naczelnik@jawnosc.tk>
Adam Eijdenberg <adam.eijdenberg@gmail.com>
Adam Kunk <adam.kunk@tiaa-cref.org>
Adam Miller <admiller@redhat.com>
@@ -43,17 +45,20 @@ AJ Bowen <aj@soulshake.net>
Ajey Charantimath <ajey.charantimath@gmail.com>
ajneu <ajneu@users.noreply.github.com>
Akash Gupta <akagup@microsoft.com>
Akhil Mohan <akhil.mohan@mayadata.io>
Akihiro Matsushima <amatsusbit@gmail.com>
Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
Akim Demaille <akim.demaille@docker.com>
Akira Koyasu <mail@akirakoyasu.net>
Akshay Karle <akshay.a.karle@gmail.com>
Al Tobey <al@ooyala.com>
alambike <alambike@gmail.com>
Alan Hoyle <alan@alanhoyle.com>
Alan Scherger <flyinprogrammer@gmail.com>
Alan Thompson <cloojure@gmail.com>
Albert Callarisa <shark234@gmail.com>
Albert Zhang <zhgwenming@gmail.com>
Albin Kerouanton <albin@akerouanton.name>
Alejandro González Hevia <alejandrgh11@gmail.com>
Aleksa Sarai <asarai@suse.de>
Aleksandrs Fadins <aleks@s-ko.net>
@@ -81,6 +86,7 @@ Alexandre Garnier <zigarn@gmail.com>
Alexandre González <agonzalezro@gmail.com>
Alexandre Jomin <alexandrejomin@gmail.com>
Alexandru Sfirlogea <alexandru.sfirlogea@gmail.com>
Alexei Margasov <alexei38@yandex.ru>
Alexey Guskov <lexag@mail.ru>
Alexey Kotlyarov <alexey@infoxchange.net.au>
Alexey Shamrin <shamrin@gmail.com>
@@ -106,11 +112,13 @@ Amy Lindburg <amy.lindburg@docker.com>
Anand Patil <anand.prabhakar.patil@gmail.com>
AnandkumarPatel <anandkumarpatel@gmail.com>
Anatoly Borodin <anatoly.borodin@gmail.com>
Anca Iordache <anca.iordache@docker.com>
Anchal Agrawal <aagrawa4@illinois.edu>
Anda Xu <anda.xu@docker.com>
Anders Janmyr <anders@janmyr.com>
Andre Dublin <81dublin@gmail.com>
Andre Granovsky <robotciti@live.com>
Andrea Denisse Gómez <crypto.andrea@protonmail.ch>
Andrea Luzzardi <aluzzardi@gmail.com>
Andrea Turli <andrea.turli@gmail.com>
Andreas Elvers <andreas@work.de>
@@ -118,6 +126,7 @@ Andreas Köhler <andi5.py@gmx.net>
Andreas Savvides <andreas@editd.com>
Andreas Tiefenthaler <at@an-ti.eu>
Andrei Gherzan <andrei@resin.io>
Andrei Vagin <avagin@gmail.com>
Andrew C. Bodine <acbodine@us.ibm.com>
Andrew Clay Shafer <andrewcshafer@gmail.com>
Andrew Duckworth <grillopress@gmail.com>
@@ -137,6 +146,7 @@ Andrew Po <absourd.noise@gmail.com>
Andrew Weiss <andrew.weiss@docker.com>
Andrew Williams <williams.andrew@gmail.com>
Andrews Medina <andrewsmedina@gmail.com>
Andrey Kolomentsev <andrey.kolomentsev@docker.com>
Andrey Petrov <andrey.petrov@shazow.net>
Andrey Stolbovsky <andrey.stolbovsky@gmail.com>
André Martins <aanm90@gmail.com>
@@ -151,6 +161,7 @@ Andy Wilson <wilson.andrew.j+github@gmail.com>
Anes Hasicic <anes.hasicic@gmail.com>
Anil Belur <askb23@gmail.com>
Anil Madhavapeddy <anil@recoil.org>
Ankit Jain <ajatkj@yahoo.co.in>
Ankush Agarwal <ankushagarwal11@gmail.com>
Anonmily <michelle@michelleliu.io>
Anran Qiao <anran.qiao@daocloud.io>
@@ -172,8 +183,10 @@ Anusha Ragunathan <anusha.ragunathan@docker.com>
apocas <petermdias@gmail.com>
Arash Deshmeh <adeshmeh@ca.ibm.com>
ArikaChen <eaglesora@gmail.com>
Arko Dasgupta <arko.dasgupta@docker.com>
Arnaud Lefebvre <a.lefebvre@outlook.fr>
Arnaud Porterie <arnaud.porterie@docker.com>
Arnaud Rebillout <arnaud.rebillout@collabora.com>
Arthur Barr <arthur.barr@uk.ibm.com>
Arthur Gautier <baloo@gandi.net>
Artur Meyster <arthurfbi@yahoo.com>
@@ -182,6 +195,7 @@ Asad Saeeduddin <masaeedu@gmail.com>
Asbjørn Enge <asbjorn@hanafjedle.net>
averagehuman <averagehuman@users.noreply.github.com>
Avi Das <andas222@gmail.com>
Avi Kivity <avi@scylladb.com>
Avi Miller <avi.miller@oracle.com>
Avi Vaid <avaid1996@gmail.com>
ayoshitake <airandfingers@gmail.com>
@@ -195,6 +209,7 @@ bdevloed <boris.de.vloed@gmail.com>
Ben Bonnefoy <frenchben@docker.com>
Ben Firshman <ben@firshman.co.uk>
Ben Golub <ben.golub@dotcloud.com>
Ben Gould <ben@bengould.co.uk>
Ben Hall <ben@benhall.me.uk>
Ben Sargent <ben@brokendigits.com>
Ben Severson <BenSeverson@users.noreply.github.com>
@@ -204,20 +219,25 @@ Benjamin Atkin <ben@benatkin.com>
Benjamin Baker <Benjamin.baker@utexas.edu>
Benjamin Boudreau <boudreau.benjamin@gmail.com>
Benjamin Yolken <yolken@stripe.com>
Benny Ng <benny.tpng@gmail.com>
Benoit Chesneau <bchesneau@gmail.com>
Bernerd Schaefer <bj.schaefer@gmail.com>
Bernhard M. Wiedemann <bwiedemann@suse.de>
Bert Goethals <bert@bertg.be>
Bertrand Roussel <broussel@sierrawireless.com>
Bevisy Zhang <binbin36520@gmail.com>
Bharath Thiruveedula <bharath_ves@hotmail.com>
Bhiraj Butala <abhiraj.butala@gmail.com>
Bhumika Bayani <bhumikabayani@gmail.com>
Bilal Amarni <bilal.amarni@gmail.com>
Bill Wang <ozbillwang@gmail.com>
Bily Zhang <xcoder@tenxcloud.com>
Bin Liu <liubin0329@gmail.com>
Bingshen Wang <bingshen.wbs@alibaba-inc.com>
Blake Geno <blakegeno@gmail.com>
Boaz Shuster <ripcurld.github@gmail.com>
bobby abbott <ttobbaybbob@gmail.com>
Boqin Qin <bobbqqin@gmail.com>
Boris Pruessmann <boris@pruessmann.org>
Boshi Lian <farmer1992@gmail.com>
Bouke Haarsma <bouke@webatoom.nl>
@@ -271,6 +291,7 @@ Carl Loa Odin <carlodin@gmail.com>
Carl X. Su <bcbcarl@gmail.com>
Carlo Mion <mion00@gmail.com>
Carlos Alexandro Becker <caarlos0@gmail.com>
Carlos de Paula <me@carlosedp.com>
Carlos Sanchez <carlos@apache.org>
Carol Fager-Higgins <carol.fager-higgins@docker.com>
Cary <caryhartline@users.noreply.github.com>
@@ -302,6 +323,7 @@ Chen Min <chenmin46@huawei.com>
Chen Mingjie <chenmingjie0828@163.com>
Chen Qiu <cheney-90@hotmail.com>
Cheng-mean Liu <soccerl@microsoft.com>
Chengfei Shang <cfshang@alauda.io>
Chengguang Xu <cgxu519@gmx.com>
chenyuzhu <chenyuzhi@oschina.cn>
Chetan Birajdar <birajdar.chetan@gmail.com>
@@ -319,6 +341,7 @@ Chris Gibson <chris@chrisg.io>
Chris Khoo <chris.khoo@gmail.com>
Chris McKinnel <chris.mckinnel@tangentlabs.co.uk>
Chris McKinnel <chrismckinnel@gmail.com>
Chris Price <cprice@mirantis.com>
Chris Seto <chriskseto@gmail.com>
Chris Snow <chsnow123@gmail.com>
Chris St. Pierre <chris.a.st.pierre@gmail.com>
@@ -345,7 +368,7 @@ Christopher Currie <codemonkey+github@gmail.com>
Christopher Jones <tophj@linux.vnet.ibm.com>
Christopher Latham <sudosurootdev@gmail.com>
Christopher Rigor <crigor@gmail.com>
Christy Perez <christy@linux.vnet.ibm.com>
Christy Norman <christy@linux.vnet.ibm.com>
Chun Chen <ramichen@tencent.com>
Ciro S. Costa <ciro.costa@usp.br>
Clayton Coleman <ccoleman@redhat.com>
@@ -354,6 +377,7 @@ Cody Roseborough <crrosebo@amazon.com>
Coenraad Loubser <coenraad@wish.org.za>
Colin Dunklau <colin.dunklau@gmail.com>
Colin Hebert <hebert.colin@gmail.com>
Colin Panisset <github@clabber.com>
Colin Rice <colin@daedrum.net>
Colin Walters <walters@verbum.org>
Collin Guarino <collin.guarino@gmail.com>
@@ -364,8 +388,10 @@ Corey Farrell <git@cfware.com>
Cory Forsyth <cory.forsyth@gmail.com>
cressie176 <github@stephen-cresswell.net>
CrimsonGlory <CrimsonGlory@users.noreply.github.com>
Cristian Ariza <dev@cristianrz.com>
Cristian Staretu <cristian.staretu@gmail.com>
cristiano balducci <cristiano.balducci@gmail.com>
Cristina Yenyxe Gonzalez Garcia <cristina.yenyxe@gmail.com>
Cruceru Calin-Cristian <crucerucalincristian@gmail.com>
CUI Wei <ghostplant@qq.com>
Cyprian Gracz <cyprian.gracz@micro-jumbo.eu>
@@ -389,14 +415,17 @@ Dan Levy <dan@danlevy.net>
Dan McPherson <dmcphers@redhat.com>
Dan Stine <sw@stinemail.com>
Dan Williams <me@deedubs.com>
Dani Hodovic <dani.hodovic@gmail.com>
Dani Louca <dani.louca@docker.com>
Daniel Antlinger <d.antlinger@gmx.at>
Daniel Black <daniel@linux.ibm.com>
Daniel Dao <dqminh@cloudflare.com>
Daniel Exner <dex@dragonslave.de>
Daniel Farrell <dfarrell@redhat.com>
Daniel Garcia <daniel@danielgarcia.info>
Daniel Gasienica <daniel@gasienica.ch>
Daniel Grunwell <mwgrunny@gmail.com>
Daniel Helfand <helfand.4@gmail.com>
Daniel Hiltgen <daniel.hiltgen@docker.com>
Daniel J Walsh <dwalsh@redhat.com>
Daniel Menet <membership@sontags.ch>
@@ -406,12 +435,14 @@ Daniel Norberg <dano@spotify.com>
Daniel Nordberg <dnordberg@gmail.com>
Daniel Robinson <gottagetmac@gmail.com>
Daniel S <dan.streby@gmail.com>
Daniel Sweet <danieljsweet@icloud.com>
Daniel Von Fange <daniel@leancoder.com>
Daniel Watkins <daniel@daniel-watkins.co.uk>
Daniel X Moore <yahivin@gmail.com>
Daniel YC Lin <dlin.tw@gmail.com>
Daniel Zhang <jmzwcn@gmail.com>
Danny Berger <dpb587@gmail.com>
Danny Milosavljevic <dannym@scratchpost.org>
Danny Yates <danny@codeaholics.org>
Danyal Khaliq <danyal.khaliq@tenpearls.com>
Darren Coxall <darren@darrencoxall.com>
@@ -442,6 +473,7 @@ David Mackey <tdmackey@booleanhaiku.com>
David Mat <david@davidmat.com>
David Mcanulty <github@hellspark.com>
David McKay <david@rawkode.com>
David P Hilton <david.hilton.p@gmail.com>
David Pelaez <pelaez89@gmail.com>
David R. Jenni <david.r.jenni@gmail.com>
David Röthlisberger <david@rothlis.net>
@@ -459,6 +491,7 @@ dcylabs <dcylabs@gmail.com>
Debayan De <debayande@users.noreply.github.com>
Deborah Gertrude Digges <deborah.gertrude.digges@gmail.com>
deed02392 <georgehafiz@gmail.com>
Deep Debroy <ddebroy@docker.com>
Deng Guangxing <dengguangxing@huawei.com>
Deni Bertovic <deni@kset.org>
Denis Defreyne <denis@soundcloud.com>
@@ -474,6 +507,7 @@ Derek McGowan <derek@mcgstyle.net>
Deric Crago <deric.crago@gmail.com>
Deshi Xiao <dxiao@redhat.com>
devmeyster <arthurfbi@yahoo.com>
Devon Estes <devon.estes@klarna.com>
Devvyn Murphy <devvyn@devvyn.com>
Dharmit Shah <shahdharmit@gmail.com>
Dhawal Yogesh Bhanushali <dbhanushali@vmware.com>
@@ -483,6 +517,7 @@ Dieter Reuter <dieter.reuter@me.com>
Dillon Dixon <dillondixon@gmail.com>
Dima Stopel <dima@twistlock.com>
Dimitri John Ledkov <dimitri.j.ledkov@intel.com>
Dimitris Mandalidis <dimitris.mandalidis@gmail.com>
Dimitris Rozakis <dimrozakis@gmail.com>
Dimitry Andric <d.andric@activevideo.com>
Dinesh Subhraveti <dineshs@altiscale.com>
@@ -496,11 +531,14 @@ Dmitri Shuralyov <shurcooL@gmail.com>
Dmitry Demeshchuk <demeshchuk@gmail.com>
Dmitry Gusev <dmitry.gusev@gmail.com>
Dmitry Kononenko <d@dm42.ru>
Dmitry Sharshakov <d3dx12.xx@gmail.com>
Dmitry Shyshkin <dmitry@shyshkin.org.ua>
Dmitry Smirnov <onlyjob@member.fsf.org>
Dmitry V. Krivenok <krivenok.dmitry@gmail.com>
Dmitry Vorobev <dimahabr@gmail.com>
Dolph Mathews <dolph.mathews@gmail.com>
Dominic Tubach <dominic.tubach@to.com>
Dominic Yin <yindongchao@inspur.com>
Dominik Dingel <dingel@linux.vnet.ibm.com>
Dominik Finkbeiner <finkes93@gmail.com>
Dominik Honnef <dominik@honnef.co>
@@ -519,7 +557,7 @@ Douglas Curtis <dougcurtis1@gmail.com>
Dr Nic Williams <drnicwilliams@gmail.com>
dragon788 <dragon788@users.noreply.github.com>
Dražen Lučanin <kermit666@gmail.com>
Drew Erny <drew.erny@docker.com>
Drew Erny <derny@mirantis.com>
Drew Hubl <drew.hubl@gmail.com>
Dustin Sallings <dustin@spy.net>
Ed Costello <epc@epcostello.com>
@@ -569,6 +607,7 @@ Erik Weathers <erikdw@gmail.com>
Erno Hopearuoho <erno.hopearuoho@gmail.com>
Erwin van der Koogh <info@erronis.nl>
Ethan Bell <ebgamer29@gmail.com>
Ethan Mosbaugh <ethan@replicated.com>
Euan Kemp <euan.kemp@coreos.com>
Eugen Krizo <eugen.krizo@gmail.com>
Eugene Yakubovich <eugene.yakubovich@coreos.com>
@@ -580,12 +619,14 @@ Evan Phoenix <evan@fallingsnow.net>
Evan Wies <evan@neomantra.net>
Evelyn Xu <evelynhsu21@gmail.com>
Everett Toews <everett.toews@rackspace.com>
Evgeniy Makhrov <e.makhrov@corp.badoo.com>
Evgeny Shmarnev <shmarnev@gmail.com>
Evgeny Vereshchagin <evvers@ya.ru>
Ewa Czechowska <ewa@ai-traders.com>
Eystein Måløy Stenberg <eystein.maloy.stenberg@cfengine.com>
ezbercih <cem.ezberci@gmail.com>
Ezra Silvera <ezra@il.ibm.com>
Fabian Kramm <kramm@covexo.com>
Fabian Lauer <kontakt@softwareschmiede-saar.de>
Fabian Raetz <fabian.raetz@gmail.com>
Fabiano Rosas <farosas@br.ibm.com>
@@ -604,6 +645,7 @@ Fareed Dudhia <fareeddudhia@googlemail.com>
Fathi Boudra <fathi.boudra@linaro.org>
Federico Gimenez <fgimenez@coit.es>
Felipe Oliveira <felipeweb.programador@gmail.com>
Felipe Ruhland <felipe.ruhland@gmail.com>
Felix Abecassis <fabecassis@nvidia.com>
Felix Geisendörfer <felix@debuggable.com>
Felix Hupfeld <felix@quobyte.com>
@@ -624,6 +666,7 @@ Florian <FWirtz@users.noreply.github.com>
Florian Klein <florian.klein@free.fr>
Florian Maier <marsmensch@users.noreply.github.com>
Florian Noeding <noeding@adobe.com>
Florian Schmaus <flo@geekplace.eu>
Florian Weingarten <flo@hackvalue.de>
Florin Asavoaie <florin.asavoaie@gmail.com>
Florin Patan <florinpatan@gmail.com>
@@ -638,12 +681,14 @@ Frank Groeneveld <frank@ivaldi.nl>
Frank Herrmann <fgh@4gh.tv>
Frank Macreery <frank@macreery.com>
Frank Rosquin <frank.rosquin+github@gmail.com>
frankyang <yyb196@gmail.com>
Fred Lifton <fred.lifton@docker.com>
Frederick F. Kautz IV <fkautz@redhat.com>
Frederik Loeffert <frederik@zitrusmedia.de>
Frederik Nordahl Jul Sabroe <frederikns@gmail.com>
Freek Kalter <freek@kalteronline.org>
Frieder Bluemle <frieder.bluemle@gmail.com>
Fu JinLin <withlin@yeah.net>
Félix Baylac-Jacqué <baylac.felix@gmail.com>
Félix Cantournet <felix.cantournet@cloudwatt.com>
Gabe Rosenhouse <gabe@missionst.com>
@@ -658,7 +703,7 @@ Gareth Rushgrove <gareth@morethanseven.net>
Garrett Barboza <garrett@garrettbarboza.com>
Gary Schaetz <gary@schaetzkc.com>
Gaurav <gaurav.gosec@gmail.com>
gautam, prasanna <prasannagautam@gmail.com>
Gaurav Singh <gaurav1086@gmail.com>
Gaël PORTAY <gael.portay@savoirfairelinux.com>
Genki Takiuchi <genki@s21g.com>
GennadySpb <lipenkov@gmail.com>
@@ -676,6 +721,7 @@ Ghislain Bourgeois <ghislain.bourgeois@gmail.com>
Giampaolo Mancini <giampaolo@trampolineup.com>
Gianluca Borello <g.borello@gmail.com>
Gildas Cuisinier <gildas.cuisinier@gcuisinier.net>
Giovan Isa Musthofa <giovanism@outlook.co.id>
gissehel <public-devgit-dantus@gissehel.org>
Giuseppe Mazzotta <gdm85@users.noreply.github.com>
Gleb Fotengauer-Malinovskiy <glebfm@altlinux.org>
@@ -683,11 +729,12 @@ Gleb M Borisov <borisov.gleb@gmail.com>
Glyn Normington <gnormington@gopivotal.com>
GoBella <caili_welcome@163.com>
Goffert van Gool <goffert@phusion.nl>
Goldwyn Rodrigues <rgoldwyn@suse.com>
Gopikannan Venugopalsamy <gopikannan.venugopalsamy@gmail.com>
Gosuke Miyashita <gosukenator@gmail.com>
Gou Rao <gou@portworx.com>
Govinda Fichtner <govinda.fichtner@googlemail.com>
Grant Millar <grant@cylo.io>
Grant Millar <rid@cylo.io>
Grant Reaber <grant.reaber@gmail.com>
Graydon Hoare <graydon@pobox.com>
Greg Fausak <greg@tacodata.com>
@@ -706,15 +753,20 @@ Guruprasad <lgp171188@gmail.com>
Gustav Sinder <gustav.sinder@gmail.com>
gwx296173 <gaojing3@huawei.com>
Günter Zöchbauer <guenter@gzoechbauer.com>
Haichao Yang <yang.haichao@zte.com.cn>
haikuoliu <haikuo@amazon.com>
Hakan Özler <hakan.ozler@kodcu.com>
Hamish Hutchings <moredhel@aoeu.me>
Hannes Ljungberg <hannes@5monkeys.se>
Hans Kristian Flaatten <hans@starefossen.com>
Hans Rødtang <hansrodtang@gmail.com>
Hao Shu Wei <haosw@cn.ibm.com>
Hao Zhang <21521210@zju.edu.cn>
Harald Albers <github@albersweb.de>
Harald Niesche <harald@niesche.de>
Harley Laue <losinggeneration@gmail.com>
Harold Cooper <hrldcpr@gmail.com>
Harrison Turton <harrisonturton@gmail.com>
Harry Zhang <harryz@hyper.sh>
Harshal Patil <harshal.patil@in.ibm.com>
Harshal Patil <harshalp@linux.vnet.ibm.com>
@@ -726,13 +778,18 @@ Hector Castro <hectcastro@gmail.com>
Helen Xie <chenjg@harmonycloud.cn>
Henning Sprang <henning.sprang@gmail.com>
Hiroshi Hatake <hatake@clear-code.com>
Hiroyuki Sasagawa <hs19870702@gmail.com>
Hobofan <goisser94@gmail.com>
Hollie Teal <hollie@docker.com>
Hong Xu <hong@topbug.net>
Hongbin Lu <hongbin034@gmail.com>
Hongxu Jia <hongxu.jia@windriver.com>
Honza Pokorny <me@honza.ca>
Hsing-Hui Hsu <hsinghui@amazon.com>
hsinko <21551195@zju.edu.cn>
Hu Keping <hukeping@huawei.com>
Hu Tao <hutao@cn.fujitsu.com>
HuanHuan Ye <logindaveye@gmail.com>
Huanzhong Zhang <zhanghuanzhong90@gmail.com>
Huayi Zhang <irachex@gmail.com>
Hugo Duncan <hugo@hugoduncan.org>
@@ -766,8 +823,10 @@ Ilya Khlopotov <ilya.khlopotov@gmail.com>
imre Fitos <imre.fitos+github@gmail.com>
inglesp <peter.inglesby@gmail.com>
Ingo Gottwald <in.gottwald@gmail.com>
Innovimax <innovimax@gmail.com>
Isaac Dupree <antispam@idupree.com>
Isabel Jimenez <contact.isabeljimenez@gmail.com>
Isaiah Grace <irgkenya4@gmail.com>
Isao Jonas <isao.jonas@gmail.com>
Iskander Sharipov <quasilyte@gmail.com>
Ivan Babrou <ibobrik@gmail.com>
@@ -783,6 +842,7 @@ Jacob Edelman <edelman.jd@gmail.com>
Jacob Tomlinson <jacob@tom.linson.uk>
Jacob Vallejo <jakeev@amazon.com>
Jacob Wen <jian.w.wen@oracle.com>
Jaime Cepeda <jcepedavillamayor@gmail.com>
Jaivish Kothari <janonymous.codevulture@gmail.com>
Jake Champlin <jake.champlin.27@gmail.com>
Jake Moshenko <jake@devtable.com>
@@ -797,11 +857,13 @@ James Kyburz <james.kyburz@gmail.com>
James Kyle <james@jameskyle.org>
James Lal <james@lightsofapollo.com>
James Mills <prologic@shortcircuit.net.au>
James Nesbitt <james.nesbitt@wunderkraut.com>
James Nesbitt <jnesbitt@mirantis.com>
James Nugent <james@jen20.com>
James Turnbull <james@lovedthanlost.net>
James Watkins-Harvey <jwatkins@progi-media.com>
Jamie Hannaford <jamie@limetree.org>
Jamshid Afshar <jafshar@yahoo.com>
Jan Chren <dev.rindeal@gmail.com>
Jan Keromnes <janx@linux.com>
Jan Koprowski <jan.koprowski@gmail.com>
Jan Pazdziora <jpazdziora@redhat.com>
@@ -816,6 +878,7 @@ Jared Hocutt <jaredh@netapp.com>
Jaroslaw Zabiello <hipertracker@gmail.com>
jaseg <jaseg@jaseg.net>
Jasmine Hegman <jasmine@jhegman.com>
Jason A. Donenfeld <Jason@zx2c4.com>
Jason Divock <jdivock@gmail.com>
Jason Giedymin <jasong@apache.org>
Jason Green <Jason.Green@AverInformatics.Com>
@@ -832,6 +895,7 @@ jaxgeller <jacksongeller@gmail.com>
Jay <imjching@hotmail.com>
Jay <teguhwpurwanto@gmail.com>
Jay Kamat <github@jgkamat.33mail.com>
Jean Rouge <rougej+github@gmail.com>
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
Jean-Christophe Berthon <huygens@berthon.eu>
@@ -862,29 +926,33 @@ Jeroen Franse <jeroenfranse@gmail.com>
Jeroen Jacobs <github@jeroenj.be>
Jesse Dearing <jesse.dearing@gmail.com>
Jesse Dubay <jesse@thefortytwo.net>
Jessica Frazelle <acidburn@microsoft.com>
Jessica Frazelle <jess@oxide.computer>
Jezeniel Zapanta <jpzapanta22@gmail.com>
Jhon Honce <jhonce@redhat.com>
Ji.Zhilong <zhilongji@gmail.com>
Jian Liao <jliao@alauda.io>
Jian Zhang <zhangjian.fnst@cn.fujitsu.com>
Jiang Jinyang <jjyruby@gmail.com>
Jie Luo <luo612@zju.edu.cn>
Jie Ma <jienius@outlook.com>
Jihyun Hwang <jhhwang@telcoware.com>
Jilles Oldenbeuving <ojilles@gmail.com>
Jim Alateras <jima@comware.com.au>
Jim Ehrismann <jim.ehrismann@docker.com>
Jim Galasyn <jim.galasyn@docker.com>
Jim Minter <jminter@redhat.com>
Jim Perrin <jperrin@centos.org>
Jimmy Cuadra <jimmy@jimmycuadra.com>
Jimmy Puckett <jimmy.puckett@spinen.com>
Jimmy Song <rootsongjc@gmail.com>
jimmyxian <jimmyxian2004@yahoo.com.cn>
Jinsoo Park <cellpjs@gmail.com>
Jintao Zhang <zhangjintao9020@gmail.com>
Jiri Appl <jiria@microsoft.com>
Jiri Popelka <jpopelka@redhat.com>
Jiuyue Ma <majiuyue@huawei.com>
Jiří Župka <jzupka@redhat.com>
jjy <jiangjinyang@outlook.com>
jmzwcn <jmzwcn@gmail.com>
Joao Fernandes <joao.fernandes@docker.com>
Joao Trindade <trindade.joao@gmail.com>
Joe Beda <joe.github@bedafamily.com>
Joe Doliner <jdoliner@pachyderm.io>
Joe Ferguson <joe@infosiftr.com>
@@ -908,7 +976,7 @@ John Feminella <jxf@jxf.me>
John Gardiner Myers <jgmyers@proofpoint.com>
John Gossman <johngos@microsoft.com>
John Harris <john@johnharris.io>
John Howard (VM) <John.Howard@microsoft.com>
John Howard <github@lowenna.com>
John Laswell <john.n.laswell@gmail.com>
John Maguire <jmaguire@duosecurity.com>
John Mulhausen <john@docker.com>
@@ -922,7 +990,10 @@ John Willis <john.willis@docker.com>
Jon Johnson <jonjohnson@google.com>
Jon Surrell <jon.surrell@gmail.com>
Jon Wedaman <jweede@gmail.com>
Jonas Dohse <jonas@dohse.ch>
Jonas Heinrich <Jonas@JonasHeinrich.com>
Jonas Pfenniger <jonas@pfenniger.name>
Jonathan A. Schweder <jonathanschweder@gmail.com>
Jonathan A. Sternberg <jonathansternberg@gmail.com>
Jonathan Boulle <jonathanboulle@gmail.com>
Jonathan Camp <jonathan@irondojo.com>
@@ -943,7 +1014,7 @@ Jordan Jennings <jjn2009@gmail.com>
Jordan Sissel <jls@semicomplete.com>
Jorge Marin <chipironcin@users.noreply.github.com>
Jorit Kleine-Möllhoff <joppich@bricknet.de>
Jose Diaz-Gonzalez <jose@seatgeek.com>
Jose Diaz-Gonzalez <email@josediazgonzalez.com>
Joseph Anthony Pasquale Holsten <joseph@josephholsten.com>
Joseph Hager <ajhager@gmail.com>
Joseph Kern <jkern@semafour.net>
@@ -970,10 +1041,13 @@ Julien Dubois <julien.dubois@gmail.com>
Julien Kassar <github@kassisol.com>
Julien Maitrehenry <julien.maitrehenry@me.com>
Julien Pervillé <julien.perville@perfect-memory.com>
Julien Pivotto <roidelapluie@inuits.eu>
Julio Guerra <julio@sqreen.com>
Julio Montes <imc.coder@gmail.com>
Jun-Ru Chang <jrjang@gmail.com>
Jussi Nummelin <jussi.nummelin@gmail.com>
Justas Brazauskas <brazauskasjustas@gmail.com>
Justen Martin <jmart@the-coder.com>
Justin Cormack <justin.cormack@docker.com>
Justin Force <justin.force@gmail.com>
Justin Menga <justin.menga@gmail.com>
@@ -982,6 +1056,7 @@ Justin Simonelis <justin.p.simonelis@gmail.com>
Justin Terry <juterry@microsoft.com>
Justyn Temme <justyntemme@gmail.com>
Jyrki Puttonen <jyrkiput@gmail.com>
Jérémy Leherpeur <amenophis@leherpeur.net>
Jérôme Petazzoni <jerome.petazzoni@docker.com>
Jörg Thalheim <joerg@higgsboson.tk>
K. Heller <pestophagous@gmail.com>
@@ -997,7 +1072,7 @@ kargakis <kargakis@users.noreply.github.com>
Karl Grzeszczak <karlgrz@gmail.com>
Karol Duleba <mr.fuxi@gmail.com>
Karthik Karanth <karanth.karthik@gmail.com>
Karthik Nayak <Karthik.188@gmail.com>
Karthik Nayak <karthik.188@gmail.com>
Kasper Fabæch Brandt <poizan@poizan.dk>
Kate Heddleston <kate.heddleston@gmail.com>
Katie McLaughlin <katie@glasnt.com>
@@ -1019,6 +1094,7 @@ Ken Reese <krrgithub@gmail.com>
Kenfe-Mickaël Laventure <mickael.laventure@gmail.com>
Kenjiro Nakayama <nakayamakenjiro@gmail.com>
Kent Johnson <kentoj@gmail.com>
Kenta Tada <Kenta.Tada@sony.com>
Kevin "qwazerty" Houdebert <kevin.houdebert@gmail.com>
Kevin Burke <kev@inburke.com>
Kevin Clark <kevin.clark@gmail.com>
@@ -1029,6 +1105,7 @@ Kevin Kern <kaiwentan@harmonycloud.cn>
Kevin Menard <kevin@nirvdrum.com>
Kevin Meredith <kevin.m.meredith@gmail.com>
Kevin P. Kucharczyk <kevinkucharczyk@gmail.com>
Kevin Parsons <kevpar@microsoft.com>
Kevin Richardson <kevin@kevinrichardson.co>
Kevin Shi <kshi@andrew.cmu.edu>
Kevin Wallace <kevin@pentabarf.net>
@@ -1053,11 +1130,13 @@ Krasimir Georgiev <support@vip-consult.co.uk>
Kris-Mikael Krister <krismikael@protonmail.com>
Kristian Haugene <kristian.haugene@capgemini.com>
Kristina Zabunova <triara.xiii@gmail.com>
Krystian Wojcicki <kwojcicki@sympatico.ca>
Kun Zhang <zkazure@gmail.com>
Kunal Kushwaha <kushwaha_kunal_v7@lab.ntt.co.jp>
Kunal Tyagi <tyagi.kunal@live.com>
Kyle Conroy <kyle.j.conroy@gmail.com>
Kyle Linden <linden.kyle@gmail.com>
Kyle Wuolle <kyle.wuolle@gmail.com>
kyu <leehk1227@gmail.com>
Lachlan Coote <lcoote@vmware.com>
Lai Jiangshan <jiangshanlai@gmail.com>
@@ -1095,6 +1174,8 @@ Liana Lo <liana.lixia@gmail.com>
Liang Mingqiang <mqliang.zju@gmail.com>
Liang-Chi Hsieh <viirya@gmail.com>
Liao Qingwei <liaoqingwei@huawei.com>
Lifubang <lifubang@acmcoder.com>
Lihua Tang <lhtang@alauda.io>
Lily Guo <lily.guo@docker.com>
limsy <seongyeol37@gmail.com>
Lin Lu <doraalin@163.com>
@@ -1113,8 +1194,9 @@ Lloyd Dewolf <foolswisdom@gmail.com>
Lokesh Mandvekar <lsm5@fedoraproject.org>
longliqiang88 <394564827@qq.com>
Lorenz Leutgeb <lorenz.leutgeb@gmail.com>
Lorenzo Fontana <lo@linux.com>
Lorenzo Fontana <fontanalorenz@gmail.com>
Lotus Fenn <fenn.lotus@gmail.com>
Louis Delossantos <ldelossa.ld@gmail.com>
Louis Opter <kalessin@kalessin.fr>
Luca Favatella <luca.favatella@erlang-solutions.com>
Luca Marturana <lucamarturana@gmail.com>
@@ -1123,9 +1205,11 @@ Luca-Bogdan Grigorescu <Luca-Bogdan Grigorescu>
Lucas Chan <lucas-github@lucaschan.com>
Lucas Chi <lucas@teacherspayteachers.com>
Lucas Molas <lmolas@fundacionsadosky.org.ar>
Lucas Silvestre <lukas.silvestre@gmail.com>
Luciano Mores <leslau@gmail.com>
Luis Martínez de Bartolomé Izquierdo <lmartinez@biicode.com>
Luiz Svoboda <luizek@gmail.com>
Lukas Heeren <lukas-heeren@hotmail.com>
Lukas Waslowski <cr7pt0gr4ph7@gmail.com>
lukaspustina <lukas.pustina@centerdevice.com>
Lukasz Zajaczkowski <Lukasz.Zajaczkowski@ts.fujitsu.com>
@@ -1171,6 +1255,7 @@ Marius Gundersen <me@mariusgundersen.net>
Marius Sturm <marius@graylog.com>
Marius Voila <marius.voila@gmail.com>
Mark Allen <mrallen1@yahoo.com>
Mark Jeromin <mark.jeromin@sysfrog.net>
Mark McGranaghan <mmcgrana@gmail.com>
Mark McKinstry <mmckinst@umich.edu>
Mark Milstein <mark@epiloque.com>
@@ -1221,14 +1306,18 @@ Matthias Klumpp <matthias@tenstral.net>
Matthias Kühnle <git.nivoc@neverbox.com>
Matthias Rampke <mr@soundcloud.com>
Matthieu Hauglustaine <matt.hauglustaine@gmail.com>
Mattias Jernberg <nostrad@gmail.com>
Mauricio Garavaglia <mauricio@medallia.com>
mauriyouth <mauriyouth@gmail.com>
Max Harmathy <max.harmathy@web.de>
Max Shytikov <mshytikov@gmail.com>
Maxim Fedchyshyn <sevmax@gmail.com>
Maxim Ivanov <ivanov.maxim@gmail.com>
Maxim Kulkin <mkulkin@mirantis.com>
Maxim Treskin <zerthurd@gmail.com>
Maxime Petazzoni <max@signalfuse.com>
Maximiliano Maccanti <maccanti@amazon.com>
Maxwell <csuhp007@gmail.com>
Meaglith Ma <genedna@gmail.com>
meejah <meejah@meejah.ca>
Megan Kostick <mkostick@us.ibm.com>
@@ -1261,6 +1350,7 @@ Michael Stapelberg <michael+gh@stapelberg.de>
Michael Steinert <mike.steinert@gmail.com>
Michael Thies <michaelthies78@gmail.com>
Michael West <mwest@mdsol.com>
Michael Zhao <michael.zhao@arm.com>
Michal Fojtik <mfojtik@redhat.com>
Michal Gebauer <mishak@mishak.net>
Michal Jemala <michal.jemala@gmail.com>
@@ -1277,6 +1367,7 @@ Miguel Morales <mimoralea@gmail.com>
Mihai Borobocea <MihaiBorob@gmail.com>
Mihuleacc Sergiu <mihuleac.sergiu@gmail.com>
Mike Brown <brownwm@us.ibm.com>
Mike Bush <mpbush@gmail.com>
Mike Casas <mkcsas0@gmail.com>
Mike Chelen <michael.chelen@gmail.com>
Mike Danese <mikedanese@google.com>
@@ -1302,6 +1393,7 @@ Mitch Capper <mitch.capper@gmail.com>
Mizuki Urushida <z11111001011@gmail.com>
mlarcher <github@ringabell.org>
Mohammad Banikazemi <mb@us.ibm.com>
Mohammad Nasirifar <farnasirim@gmail.com>
Mohammed Aaqib Ansari <maaquib@gmail.com>
Mohit Soni <mosoni@ebay.com>
Moorthy RS <rsmoorthy@gmail.com>
@@ -1326,6 +1418,7 @@ Nan Monnand Deng <monnand@gmail.com>
Naoki Orii <norii@cs.cmu.edu>
Natalie Parker <nparker@omnifone.com>
Natanael Copa <natanael.copa@docker.com>
Natasha Jarus <linuxmercedes@gmail.com>
Nate Brennand <nate.brennand@clever.com>
Nate Eagleson <nate@nateeag.com>
Nate Jones <nate@endot.org>
@@ -1343,6 +1436,7 @@ Neyazul Haque <nuhaque@gmail.com>
Nghia Tran <nghia@google.com>
Niall O'Higgins <niallo@unworkable.org>
Nicholas E. Rabenau <nerab@gmx.at>
Nick Adcock <nick.adcock@docker.com>
Nick DeCoursin <n.decoursin@foodpanda.com>
Nick Irvine <nfirvine@nfirvine.com>
Nick Neisen <nwneisen@gmail.com>
@@ -1366,6 +1460,7 @@ Nik Nyby <nikolas@gnu.org>
Nikhil Chawla <chawlanikhil24@gmail.com>
NikolaMandic <mn080202@gmail.com>
Nikolas Garofil <nikolas.garofil@uantwerpen.be>
Nikolay Edigaryev <edigaryev@gmail.com>
Nikolay Milovanov <nmil@itransformers.net>
Nirmal Mehta <nirmalkmehta@gmail.com>
Nishant Totla <nishanttotla@gmail.com>
@@ -1375,19 +1470,25 @@ Noah Treuhaft <noah.treuhaft@docker.com>
NobodyOnSE <ich@sektor.selfip.com>
noducks <onemannoducks@gmail.com>
Nolan Darilek <nolan@thewordnerd.info>
Noriki Nakamura <noriki.nakamura@miraclelinux.com>
nponeccop <andy.melnikov@gmail.com>
Nuutti Kotivuori <naked@iki.fi>
nzwsch <hi@nzwsch.com>
O.S. Tezer <ostezer@gmail.com>
objectified <objectified@gmail.com>
Odin Ugedal <odin@ugedal.com>
Oguz Bilgic <fisyonet@gmail.com>
Oh Jinkyun <tintypemolly@gmail.com>
Ohad Schneider <ohadschn@users.noreply.github.com>
ohmystack <jun.jiang02@ele.me>
Ole Reifschneider <mail@ole-reifschneider.de>
Oliver Neal <ItsVeryWindy@users.noreply.github.com>
Oliver Reason <oli@overrateddev.co>
Olivier Gambier <dmp42@users.noreply.github.com>
Olle Jonsson <olle.jonsson@gmail.com>
Olli Janatuinen <olli.janatuinen@gmail.com>
Olly Pomeroy <oppomeroy@gmail.com>
Omri Shiv <Omri.Shiv@teradata.com>
Oriol Francès <oriolfa@gmail.com>
Oskar Niburski <oskarniburski@gmail.com>
Otto Kekäläinen <otto@seravo.fi>
@@ -1396,6 +1497,7 @@ Ovidio Mallo <ovidio.mallo@gmail.com>
Panagiotis Moustafellos <pmoust@elastic.co>
Paolo G. Giarrusso <p.giarrusso@gmail.com>
Pascal <pascalgn@users.noreply.github.com>
Pascal Bach <pascal.bach@siemens.com>
Pascal Borreli <pascal@borreli.com>
Pascal Hartig <phartig@rdrei.net>
Patrick Böänziger <patrick.baenziger@bsi-software.com>
@@ -1420,6 +1522,7 @@ Paul Nasrat <pnasrat@gmail.com>
Paul Weaver <pauweave@cisco.com>
Paulo Ribeiro <paigr.io@gmail.com>
Pavel Lobashov <ShockwaveNN@gmail.com>
Pavel Matěja <pavel@verotel.cz>
Pavel Pletenev <cpp.create@gmail.com>
Pavel Pospisil <pospispa@gmail.com>
Pavel Sutyrin <pavel.sutyrin@gmail.com>
@@ -1443,6 +1546,7 @@ Peter Edge <peter.edge@gmail.com>
Peter Ericson <pdericson@gmail.com>
Peter Esbensen <pkesbensen@gmail.com>
Peter Jaffe <pjaffe@nevo.com>
Peter Kang <peter@spell.run>
Peter Malmgren <ptmalmgren@gmail.com>
Peter Salvatore <peter@psftw.com>
Peter Volpe <petervo@redhat.com>
@@ -1486,6 +1590,7 @@ Quentin Brossard <qbrossard@gmail.com>
Quentin Perez <qperez@ocs.online.net>
Quentin Tayssier <qtayssier@gmail.com>
r0n22 <cameron.regan@gmail.com>
Radostin Stoyanov <rstoyanov1@gmail.com>
Rafal Jeczalik <rjeczalik@gmail.com>
Rafe Colton <rafael.colton@gmail.com>
Raghavendra K T <raghavendra.kt@linux.vnet.ibm.com>
@@ -1499,6 +1604,7 @@ Ralph Bean <rbean@redhat.com>
Ramkumar Ramachandra <artagnon@gmail.com>
Ramon Brooker <rbrooker@aetherealmind.com>
Ramon van Alteren <ramon@vanalteren.nl>
RaviTeja Pothana <ravi-teja@live.com>
Ray Tsang <rayt@google.com>
ReadmeCritic <frankensteinbot@gmail.com>
Recursive Madman <recursive.madman@gmx.de>
@@ -1528,6 +1634,7 @@ Riku Voipio <riku.voipio@linaro.org>
Riley Guerin <rileytg.dev@gmail.com>
Ritesh H Shukla <sritesh@vmware.com>
Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
Rob Gulewich <rgulewich@netflix.com>
Rob Vesse <rvesse@dotnetrdf.org>
Robert Bachmann <rb@robertbachmann.at>
Robert Bittle <guywithnose@gmail.com>
@@ -1536,11 +1643,13 @@ Robert Schneider <mail@shakeme.info>
Robert Stern <lexandro2000@gmail.com>
Robert Terhaar <rterhaar@atlanticdynamic.com>
Robert Wallis <smilingrob@gmail.com>
Robert Wang <robert@arctic.tw>
Roberto G. Hashioka <roberto.hashioka@docker.com>
Roberto Muñoz Fernández <robertomf@gmail.com>
Robin Naundorf <r.naundorf@fh-muenster.de>
Robin Schneider <ypid@riseup.net>
Robin Speekenbrink <robin@kingsquare.nl>
Robin Thoni <robin@rthoni.com>
robpc <rpcann@gmail.com>
Rodolfo Carvalho <rhcarvalho@gmail.com>
Rodrigo Vaz <rodrigo.vaz@gmail.com>
@@ -1548,15 +1657,20 @@ Roel Van Nyen <roel.vannyen@gmail.com>
Roger Peppe <rogpeppe@gmail.com>
Rohit Jnagal <jnagal@google.com>
Rohit Kadam <rohit.d.kadam@gmail.com>
Rohit Kapur <rkapur@flatiron.com>
Rojin George <rojingeorge@huawei.com>
Roland Huß <roland@jolokia.org>
Roland Kammerer <roland.kammerer@linbit.com>
Roland Moriz <rmoriz@users.noreply.github.com>
Roma Sokolov <sokolov.r.v@gmail.com>
Roman Dudin <katrmr@gmail.com>
Roman Mazur <roman@balena.io>
Roman Strashkin <roman.strashkin@gmail.com>
Ron Smits <ron.smits@gmail.com>
Ron Williams <ron.a.williams@gmail.com>
Rong Gao <gaoronggood@163.com>
Rong Zhang <rongzhang@alauda.io>
Rongxiang Song <tinysong1226@gmail.com>
root <docker-dummy@example.com>
root <root@lxdebmas.marist.edu>
root <root@ubuntu-14.04-amd64-vbox>
@@ -1568,7 +1682,9 @@ Rovanion Luckey <rovanion.luckey@gmail.com>
Royce Remer <royceremer@gmail.com>
Rozhnov Alexandr <nox73@ya.ru>
Rudolph Gottesheim <r.gottesheim@loot.at>
Rui Cao <ruicao@alauda.io>
Rui Lopes <rgl@ruilopes.com>
Ruilin Li <liruilin4@huawei.com>
Runshen Zhu <runshen.zhu@gmail.com>
Russ Magee <rmagee@gmail.com>
Ryan Abrams <rdabrams@gmail.com>
@@ -1589,6 +1705,7 @@ Ryan Wallner <ryan.wallner@clusterhq.com>
Ryan Zhang <ryan.zhang@docker.com>
ryancooper7 <ryan.cooper7@gmail.com>
RyanDeng <sheldon.d1018@gmail.com>
Ryo Nakao <nakabonne@gmail.com>
Rémy Greinhofer <remy.greinhofer@livelovely.com>
s. rannou <mxs@sbrk.org>
s00318865 <sunyuan3@huawei.com>
@@ -1606,6 +1723,7 @@ Sam J Sharpe <sam.sharpe@digital.cabinet-office.gov.uk>
Sam Neirinck <sam@samneirinck.com>
Sam Reis <sreis@atlassian.com>
Sam Rijs <srijs@airpost.net>
Sam Whited <sam@samwhited.com>
Sambuddha Basu <sambuddhabasu1@gmail.com>
Sami Wagiaalla <swagiaal@redhat.com>
Samuel Andaya <samuel@andaya.net>
@@ -1619,6 +1737,8 @@ Santhosh Manohar <santhosh@docker.com>
sapphiredev <se.imas.kr@gmail.com>
Sargun Dhillon <sargun@netflix.com>
Sascha Andres <sascha.andres@outlook.com>
Sascha Grunert <sgrunert@suse.com>
SataQiu <qiushida@beyondcent.com>
Satnam Singh <satnam@raintown.org>
Satoshi Amemiya <satoshi_amemiya@voyagegroup.com>
Satoshi Tagomori <tagomoris@gmail.com>
@@ -1645,6 +1765,7 @@ Serge Hallyn <serge.hallyn@ubuntu.com>
Sergey Alekseev <sergey.alekseev.minsk@gmail.com>
Sergey Evstifeev <sergey.evstifeev@gmail.com>
Sergii Kabashniuk <skabashnyuk@codenvy.com>
Sergio Lopez <slp@redhat.com>
Serhat Gülçiçek <serhat25@gmail.com>
SeungUkLee <lsy931106@gmail.com>
Sevki Hasirci <s@sevki.org>
@@ -1666,6 +1787,7 @@ Shijun Qin <qinshijun16@mails.ucas.ac.cn>
Shishir Mahajan <shishir.mahajan@redhat.com>
Shoubhik Bose <sbose78@gmail.com>
Shourya Sarcar <shourya.sarcar@gmail.com>
Shu-Wai Chow <shu-wai.chow@seattlechildrens.org>
shuai-z <zs.broccoli@gmail.com>
Shukui Yang <yangshukui@huawei.com>
Shuwei Hao <haosw@cn.ibm.com>
@@ -1674,7 +1796,9 @@ Sidhartha Mani <sidharthamn@gmail.com>
sidharthamani <sid@rancher.com>
Silas Sewell <silas@sewell.org>
Silvan Jegen <s.jegen@gmail.com>
Simão Reis <smnrsti@gmail.com>
Simei He <hesimei@zju.edu.cn>
Simon Barendse <simon.barendse@gmail.com>
Simon Eskildsen <sirup@sirupsen.com>
Simon Ferquel <simon.ferquel@docker.com>
Simon Leinen <simon.leinen@gmail.com>
@@ -1683,6 +1807,7 @@ Simon Taranto <simon.taranto@gmail.com>
Simon Vikstrom <pullreq@devsn.se>
Sindhu S <sindhus@live.in>
Sjoerd Langkemper <sjoerd-github@linuxonly.nl>
skanehira <sho19921005@gmail.com>
Solganik Alexander <solganik@gmail.com>
Solomon Hykes <solomon@docker.com>
Song Gao <song@gao.io>
@@ -1694,18 +1819,21 @@ Sridatta Thatipamala <sthatipamala@gmail.com>
Sridhar Ratnakumar <sridharr@activestate.com>
Srini Brahmaroutu <srbrahma@us.ibm.com>
Srinivasan Srivatsan <srinivasan.srivatsan@hpe.com>
Staf Wagemakers <staf@wagemakers.be>
Stanislav Bondarenko <stanislav.bondarenko@gmail.com>
Stanislav Levin <slev@altlinux.org>
Steeve Morin <steeve.morin@gmail.com>
Stefan Berger <stefanb@linux.vnet.ibm.com>
Stefan J. Wernli <swernli@microsoft.com>
Stefan Praszalowicz <stefan@greplin.com>
Stefan S. <tronicum@user.github.com>
Stefan Scherer <scherer_stefan@icloud.com>
Stefan Scherer <stefan.scherer@docker.com>
Stefan Staudenmeyer <doerte@instana.com>
Stefan Weil <sw@weilnetz.de>
Stephan Spindler <shutefan@gmail.com>
Stephen Benjamin <stephen@redhat.com>
Stephen Crosby <stevecrozz@gmail.com>
Stephen Day <stephen.day@docker.com>
Stephen Day <stevvooe@gmail.com>
Stephen Drake <stephen@xenolith.net>
Stephen Rust <srust@blockbridge.com>
Steve Desmond <steve@vtsv.ca>
@@ -1720,10 +1848,12 @@ Steven Iveson <sjiveson@outlook.com>
Steven Merrill <steven.merrill@gmail.com>
Steven Richards <steven@axiomzen.co>
Steven Taylor <steven.taylor@me.com>
Stig Larsson <stig@larsson.dev>
Subhajit Ghosh <isubuz.g@gmail.com>
Sujith Haridasan <sujith.h@gmail.com>
Sun Gengze <690388648@qq.com>
Sun Jianbo <wonderflow.sun@gmail.com>
Sune Keller <sune.keller@gmail.com>
Sunny Gogoi <indiasuny000@gmail.com>
Suryakumar Sudar <surya.trunks@gmail.com>
Sven Dowideit <SvenDowideit@home.org.au>
@@ -1774,6 +1904,8 @@ Tianyi Wang <capkurmagati@gmail.com>
Tibor Vass <teabee89@gmail.com>
Tiffany Jernigan <tiffany.f.j@gmail.com>
Tiffany Low <tiffany@box.com>
Till Wegmüller <toasterson@gmail.com>
Tim <elatllat@gmail.com>
Tim Bart <tim@fewagainstmany.com>
Tim Bosse <taim@bosboot.org>
Tim Dettrick <t.dettrick@uq.edu.au>
@@ -1825,7 +1957,7 @@ Tony Miller <mcfiredrill@gmail.com>
toogley <toogley@mailbox.org>
Torstein Husebø <torstein@huseboe.net>
Tõnis Tiigi <tonistiigi@gmail.com>
tpng <benny.tpng@gmail.com>
Trace Andreason <tandreason@gmail.com>
tracylihui <793912329@qq.com>
Trapier Marshall <trapier.marshall@docker.com>
Travis Cline <travis.cline@gmail.com>
@@ -1848,6 +1980,7 @@ Utz Bacher <utz.bacher@de.ibm.com>
vagrant <vagrant@ubuntu-14.04-amd64-vbox>
Vaidas Jablonskis <jablonskis@gmail.com>
vanderliang <lansheng@meili-inc.com>
Velko Ivanov <vivanov@deeperplane.com>
Veres Lajos <vlajos@gmail.com>
Victor Algaze <valgaze@gmail.com>
Victor Coisne <victor.coisne@dotcloud.com>
@@ -1859,11 +1992,13 @@ Victor Palma <palma.victor@gmail.com>
Victor Vieux <victor.vieux@docker.com>
Victoria Bialas <victoria.bialas@docker.com>
Vijaya Kumar K <vijayak@caviumnetworks.com>
Vikram bir Singh <vsingh@mirantis.com>
Viktor Stanchev <me@viktorstanchev.com>
Viktor Vojnovski <viktor.vojnovski@amadeus.com>
VinayRaghavanKS <raghavan.vinay@gmail.com>
Vincent Batts <vbatts@redhat.com>
Vincent Bernat <Vincent.Bernat@exoscale.ch>
Vincent Boulineau <vincent.boulineau@datadoghq.com>
Vincent Demeester <vincent.demeester@docker.com>
Vincent Giersch <vincent.giersch@ovh.net>
Vincent Mayers <vincent.mayers@inbloom.org>
@@ -1894,12 +2029,15 @@ Wang Long <long.wanglong@huawei.com>
Wang Ping <present.wp@icloud.com>
Wang Xing <hzwangxing@corp.netease.com>
Wang Yuexiao <wang.yuexiao@zte.com.cn>
Wang Yumu <37442693@qq.com>
wanghuaiqing <wanghuaiqing@loongson.cn>
Ward Vandewege <ward@jhvc.com>
WarheadsSE <max@warheads.net>
Wassim Dhif <wassimdhif@gmail.com>
Wayne Chang <wayne@neverfear.org>
Wayne Song <wsong@docker.com>
Weerasak Chongnguluam <singpor@gmail.com>
Wei Fu <fuweid89@gmail.com>
Wei Wu <wuwei4455@gmail.com>
Wei-Ting Kuo <waitingkuo0527@gmail.com>
weipeng <weipeng@tuscloud.io>
@@ -1909,12 +2047,14 @@ Wen Cheng Ma <wenchma@cn.ibm.com>
Wendel Fleming <wfleming@usc.edu>
Wenjun Tang <tangwj2@lenovo.com>
Wenkai Yin <yinw@vmware.com>
wenlxie <wenlxie@ebay.com>
Wentao Zhang <zhangwentao234@huawei.com>
Wenxuan Zhao <viz@linux.com>
Wenyu You <21551128@zju.edu.cn>
Wenzhi Liang <wenzhi.liang@gmail.com>
Wes Morgan <cap10morgan@gmail.com>
Wewang Xiaorenfine <wang.xiaoren@zte.com.cn>
Wiktor Kwapisiewicz <wiktor@metacode.biz>
Will Dietz <w@wdtz.org>
Will Rouesnel <w.rouesnel@gmail.com>
Will Weaver <monkey@buildingbananas.com>
@@ -1925,18 +2065,27 @@ William Hubbs <w.d.hubbs@gmail.com>
William Martin <wmartin@pivotal.io>
William Riancho <wr.wllm@gmail.com>
William Thurston <thurstw@amazon.com>
Wilson Júnior <wilsonpjunior@gmail.com>
Wing-Kam Wong <wingkwong.code@gmail.com>
WiseTrem <shepelyov.g@gmail.com>
Wolfgang Powisch <powo@powo.priv.at>
Wonjun Kim <wonjun.kim@navercorp.com>
xamyzhao <x.amy.zhao@gmail.com>
Xian Chaobo <xianchaobo@huawei.com>
Xianglin Gao <xlgao@zju.edu.cn>
Xianlu Bird <xianlubird@gmail.com>
Xiao YongBiao <xyb4638@gmail.com>
XiaoBing Jiang <s7v7nislands@gmail.com>
Xiaodong Liu <liuxiaodong@loongson.cn>
Xiaodong Zhang <a4012017@sina.com>
Xiaoxi He <xxhe@alauda.io>
Xiaoxu Chen <chenxiaoxu14@otcaix.iscas.ac.cn>
Xiaoyu Zhang <zhang.xiaoyu33@zte.com.cn>
xichengliudui <1693291525@qq.com>
xiekeyang <xiekeyang@huawei.com>
Ximo Guanter Gonzálbez <joaquin.guantergonzalbez@telefonica.com>
Xinbo Weng <xihuanbo_0521@zju.edu.cn>
Xinfeng Liu <xinfeng.liu@gmail.com>
Xinzi Zhou <imdreamrunner@gmail.com>
Xiuming Chen <cc@cxm.cc>
Xuecong Liao <satorulogic@gmail.com>
@@ -1951,6 +2100,7 @@ Yang Pengfei <yangpengfei4@huawei.com>
yangchenliang <yangchenliang@huawei.com>
Yanqiang Miao <miao.yanqiang@zte.com.cn>
Yao Zaiyong <yaozaiyong@hotmail.com>
Yash Murty <yashmurty@gmail.com>
Yassine Tijani <yasstij11@gmail.com>
Yasunori Mahata <nori@mahata.net>
Yazhong Liu <yorkiefixer@gmail.com>
@@ -1961,9 +2111,11 @@ Yihang Ho <hoyihang5@gmail.com>
Ying Li <ying.li@docker.com>
Yohei Ueda <yohei@jp.ibm.com>
Yong Tang <yong.tang.github@outlook.com>
Yongxin Li <yxli@alauda.io>
Yongzhi Pan <panyongzhi@gmail.com>
Yosef Fertel <yfertel@gmail.com>
You-Sheng Yang (楊有勝) <vicamo@gmail.com>
youcai <omegacoleman@gmail.com>
Youcef YEKHLEF <yyekhlef@gmail.com>
Yu Changchun <yuchangchun1@huawei.com>
Yu Chengxia <yuchengxia@huawei.com>
@@ -1971,10 +2123,12 @@ Yu Peng <yu.peng36@zte.com.cn>
Yu-Ju Hong <yjhong@google.com>
Yuan Sun <sunyuan3@huawei.com>
Yuanhong Peng <pengyuanhong@huawei.com>
Yue Zhang <zy675793960@yeah.net>
Yuhao Fang <fangyuhao@gmail.com>
Yuichiro Kaneko <spiketeika@gmail.com>
Yunxiang Huang <hyxqshk@vip.qq.com>
Yurii Rashkovskii <yrashk@gmail.com>
Yusuf Tarık Günaydın <yusuf_tarik@hotmail.com>
Yves Junqueira <yves.junqueira@gmail.com>
Zac Dover <zdover@redhat.com>
Zach Borboa <zachborboa@gmail.com>
@@ -1991,11 +2145,15 @@ ZhangHang <stevezhang2014@gmail.com>
zhangxianwei <xianwei.zw@alibaba-inc.com>
Zhenan Ye <21551168@zju.edu.cn>
zhenghenghuo <zhenghenghuo@zju.edu.cn>
Zhenhai Gao <gaozh1988@live.com>
Zhenkun Bi <bi.zhenkun@zte.com.cn>
zhipengzuo <zuozhipeng@baidu.com>
Zhou Hao <zhouhao@cn.fujitsu.com>
Zhoulin Xie <zhoulin.xie@daocloud.io>
Zhu Guihua <zhugh.fnst@cn.fujitsu.com>
Zhu Kunjia <zhu.kunjia@zte.com.cn>
Zhuoyun Wei <wzyboy@wzyboy.org>
Ziheng Liu <lzhfromustc@gmail.com>
Zilin Du <zilin.du@gmail.com>
zimbatm <zimbatm@zimbatm.com>
Ziming Dong <bnudzm@foxmail.com>
@@ -2004,12 +2162,13 @@ zmarouf <zeid.marouf@gmail.com>
Zoltan Tombol <zoltan.tombol@gmail.com>
Zou Yu <zouyu7@huawei.com>
zqh <zqhxuyuan@gmail.com>
Zuhayr Elahi <elahi.zuhayr@gmail.com>
Zuhayr Elahi <zuhayr.elahi@docker.com>
Zunayed Ali <zunayed@gmail.com>
Álex González <agonzalezro@gmail.com>
Álvaro Lázaro <alvaro.lazaro.g@gmail.com>
Átila Camurça Alves <camurca.home@gmail.com>
尹吉峰 <jifeng.yin@gmail.com>
屈骏 <qujun@tiduyun.com>
徐俊杰 <paco.xu@daocloud.io>
慕陶 <jihui.xjh@alibaba-inc.com>
搏通 <yufeng.pyf@alibaba-inc.com>
+1 -1
View File
@@ -3,7 +3,7 @@ Copyright 2012-2017 Docker, Inc.
This product includes software developed at Docker, Inc. (https://www.docker.com).
This product contains software (https://github.com/kr/pty) developed
This product contains software (https://github.com/creack/pty) developed
by Keith Rarick, licensed under the MIT License.
The following is courtesy of our legal counsel:
+1 -1
View File
@@ -3,7 +3,7 @@ package api // import "github.com/docker/docker/api"
// Common constants for daemon and client.
const (
// DefaultVersion of Current REST API
DefaultVersion = "1.40"
DefaultVersion = "1.41"
// NoBaseImageSpecifier is the symbol used by the FROM
// command to specify that no base image is to be used.
+1584 -596
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -30,7 +30,7 @@ type ContainerAttachConfig struct {
// expectation is for the logger endpoints to assemble the chunks using this
// metadata.
type PartialLogMetaData struct {
Last bool //true if this message is last of a partial
Last bool // true if this message is last of a partial
ID string // identifies group of messages comprising a single record
Ordinal int // ordering of message in partial group
}
@@ -73,6 +73,7 @@ type LogSelector struct {
// behavior of a backend.ContainerStats() call.
type ContainerStatsConfig struct {
Stream bool
OneShot bool
OutStream io.Writer
Version string
}
+7 -3
View File
@@ -50,7 +50,7 @@ type ContainerCommitOptions struct {
// ContainerExecInspect holds information returned by exec inspect.
type ContainerExecInspect struct {
ExecID string
ExecID string `json:"ID"`
ContainerID string
Running bool
ExitCode int
@@ -205,7 +205,7 @@ const (
// BuilderV1 is the first generation builder in docker daemon
BuilderV1 BuilderVersion = "1"
// BuilderBuildKit is builder based on moby/buildkit project
BuilderBuildKit = "2"
BuilderBuildKit BuilderVersion = "2"
)
// ImageBuildResponse holds information
@@ -265,7 +265,7 @@ type ImagePullOptions struct {
// if the privilege request fails.
type RequestPrivilegeFunc func() (string, error)
//ImagePushOptions holds information to push images.
// ImagePushOptions holds information to push images.
type ImagePushOptions ImagePullOptions
// ImageRemoveOptions holds parameters to remove images.
@@ -363,6 +363,10 @@ type ServiceUpdateOptions struct {
// ServiceListOptions holds parameters to list services with.
type ServiceListOptions struct {
Filters filters.Args
// Status indicates whether the server should include the service task
// count of running and desired tasks.
Status bool
}
// ServiceInspectOptions holds parameters related to the "service inspect"
+2
View File
@@ -3,6 +3,7 @@ package types // import "github.com/docker/docker/api/types"
import (
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
specs "github.com/opencontainers/image-spec/specs-go/v1"
)
// configs holds structs used for internal communication between the
@@ -15,6 +16,7 @@ type ContainerCreateConfig struct {
Config *container.Config
HostConfig *container.HostConfig
NetworkingConfig *network.NetworkingConfig
Platform *specs.Platform
AdjustCPUShares bool
}
+1 -1
View File
@@ -54,7 +54,7 @@ type Config struct {
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)
ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (meaning treat as a command line) (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
+2 -3
View File
@@ -1,8 +1,7 @@
package container
package container // import "github.com/docker/docker/api/types/container"
// ----------------------------------------------------------------------------
// DO NOT EDIT THIS FILE
// This file was generated by `swagger generate operation`
// Code generated by `swagger generate operation`. DO NOT EDIT.
//
// See hack/generate-swagger-api.sh
// ----------------------------------------------------------------------------
+2 -3
View File
@@ -1,8 +1,7 @@
package container
package container // import "github.com/docker/docker/api/types/container"
// ----------------------------------------------------------------------------
// DO NOT EDIT THIS FILE
// This file was generated by `swagger generate operation`
// Code generated by `swagger generate operation`. DO NOT EDIT.
//
// See hack/generate-swagger-api.sh
// ----------------------------------------------------------------------------
+5 -4
View File
@@ -1,8 +1,7 @@
package container
package container // import "github.com/docker/docker/api/types/container"
// ----------------------------------------------------------------------------
// DO NOT EDIT THIS FILE
// This file was generated by `swagger generate operation`
// Code generated by `swagger generate operation`. DO NOT EDIT.
//
// See hack/generate-swagger-api.sh
// ----------------------------------------------------------------------------
@@ -11,7 +10,9 @@ package container
// swagger:model ContainerTopOKBody
type ContainerTopOKBody struct {
// Each process running in the container, where each is process is an array of values corresponding to the titles
// Each process running in the container, where each is process
// is an array of values corresponding to the titles.
//
// Required: true
Processes [][]string `json:"Processes"`
+2 -3
View File
@@ -1,8 +1,7 @@
package container
package container // import "github.com/docker/docker/api/types/container"
// ----------------------------------------------------------------------------
// DO NOT EDIT THIS FILE
// This file was generated by `swagger generate operation`
// Code generated by `swagger generate operation`. DO NOT EDIT.
//
// See hack/generate-swagger-api.sh
// ----------------------------------------------------------------------------
+2 -3
View File
@@ -1,8 +1,7 @@
package container
package container // import "github.com/docker/docker/api/types/container"
// ----------------------------------------------------------------------------
// DO NOT EDIT THIS FILE
// This file was generated by `swagger generate operation`
// Code generated by `swagger generate operation`. DO NOT EDIT.
//
// See hack/generate-swagger-api.sh
// ----------------------------------------------------------------------------
+30 -8
View File
@@ -7,9 +7,32 @@ import (
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/strslice"
"github.com/docker/go-connections/nat"
"github.com/docker/go-units"
units "github.com/docker/go-units"
)
// CgroupnsMode represents the cgroup namespace mode of the container
type CgroupnsMode string
// IsPrivate indicates whether the container uses its own private cgroup namespace
func (c CgroupnsMode) IsPrivate() bool {
return c == "private"
}
// IsHost indicates whether the container shares the host's cgroup namespace
func (c CgroupnsMode) IsHost() bool {
return c == "host"
}
// IsEmpty indicates whether the container cgroup namespace mode is unset
func (c CgroupnsMode) IsEmpty() bool {
return c == ""
}
// Valid indicates whether the cgroup namespace mode is valid
func (c CgroupnsMode) Valid() bool {
return c.IsEmpty() || c.IsPrivate() || c.IsHost()
}
// Isolation represents the isolation technology of a container. The supported
// values are platform specific
type Isolation string
@@ -122,7 +145,7 @@ func (n NetworkMode) ConnectedContainer() string {
return ""
}
//UserDefined indicates user-created network
// UserDefined indicates user-created network
func (n NetworkMode) UserDefined() string {
if n.IsUserDefined() {
return string(n)
@@ -338,8 +361,7 @@ type Resources struct {
Devices []DeviceMapping // List of devices to map inside the container
DeviceCgroupRules []string // List of rule to be added to the device cgroup
DeviceRequests []DeviceRequest // List of device requests for device drivers
DiskQuota int64 // Disk limit (in bytes)
KernelMemory int64 // Kernel memory limit (in bytes)
KernelMemory int64 // Kernel memory limit (in bytes), Deprecated: kernel 5.4 deprecated kmem.limit_in_bytes
KernelMemoryTCP int64 // Hard limit for kernel TCP buffer memory (in bytes)
MemoryReservation int64 // Memory soft limit (in bytes)
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap
@@ -381,10 +403,10 @@ type HostConfig struct {
// Applicable to UNIX platforms
CapAdd strslice.StrSlice // List of kernel capabilities to add to the container
CapDrop strslice.StrSlice // List of kernel capabilities to remove from the container
Capabilities []string `json:"Capabilities"` // List of kernel capabilities to be available for container (this overrides the default set)
DNS []string `json:"Dns"` // List of DNS server to lookup
DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for
DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for
CgroupnsMode CgroupnsMode // Cgroup namespace mode to use for the container
DNS []string `json:"Dns"` // List of DNS server to lookup
DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for
DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for
ExtraHosts []string // List of extra hosts
GroupAdd []string // List of additional groups that the container process will run as
IpcMode IpcMode // IPC namespace to use for the container
+6
View File
@@ -0,0 +1,6 @@
package types
// Error returns the error message
func (e ErrorResponse) Error() string {
return e.Message
}
+2
View File
@@ -1,6 +1,8 @@
package events // import "github.com/docker/docker/api/types/events"
const (
// BuilderEventType is the event type that the builder generates
BuilderEventType = "builder"
// ContainerEventType is the event type that containers generate
ContainerEventType = "container"
// DaemonEventType is the event type that daemon generate
+10 -52
View File
@@ -5,7 +5,6 @@ package filters // import "github.com/docker/docker/api/types/filters"
import (
"encoding/json"
"errors"
"regexp"
"strings"
@@ -37,39 +36,13 @@ func NewArgs(initialArgs ...KeyValuePair) Args {
return args
}
// ParseFlag parses a key=value string and adds it to an Args.
//
// Deprecated: Use Args.Add()
func ParseFlag(arg string, prev Args) (Args, error) {
filters := prev
if len(arg) == 0 {
return filters, nil
// Keys returns all the keys in list of Args
func (args Args) Keys() []string {
keys := make([]string, 0, len(args.fields))
for k := range args.fields {
keys = append(keys, k)
}
if !strings.Contains(arg, "=") {
return filters, ErrBadFormat
}
f := strings.SplitN(arg, "=", 2)
name := strings.ToLower(strings.TrimSpace(f[0]))
value := strings.TrimSpace(f[1])
filters.Add(name, value)
return filters, nil
}
// ErrBadFormat is an error returned when a filter is not in the form key=value
//
// Deprecated: this error will be removed in a future version
var ErrBadFormat = errors.New("bad format of filter (expected name=value)")
// ToParam encodes the Args as args JSON encoded string
//
// Deprecated: use ToJSON
func ToParam(a Args) (string, error) {
return ToJSON(a)
return keys
}
// MarshalJSON returns a JSON byte representation of the Args
@@ -93,7 +66,7 @@ func ToJSON(a Args) (string, error) {
// then the encoded format will use an older legacy format where the values are a
// list of strings, instead of a set.
//
// Deprecated: Use ToJSON
// Deprecated: do not use in any new code; use ToJSON instead
func ToParamWithVersion(version string, a Args) (string, error) {
if a.Len() == 0 {
return "", nil
@@ -107,13 +80,6 @@ func ToParamWithVersion(version string, a Args) (string, error) {
return ToJSON(a)
}
// FromParam decodes a JSON encoded string into Args
//
// Deprecated: use FromJSON
func FromParam(p string) (Args, error) {
return FromJSON(p)
}
// FromJSON decodes a JSON encoded string into Args
func FromJSON(p string) (Args, error) {
args := NewArgs()
@@ -188,7 +154,7 @@ func (args Args) Len() int {
func (args Args) MatchKVList(key string, sources map[string]string) bool {
fieldValues := args.fields[key]
//do not filter if there is no filter set or cannot determine filter
// do not filter if there is no filter set or cannot determine filter
if len(fieldValues) == 0 {
return true
}
@@ -234,7 +200,7 @@ func (args Args) Match(field, source string) bool {
// ExactMatch returns true if the source matches exactly one of the values.
func (args Args) ExactMatch(key, source string) bool {
fieldValues, ok := args.fields[key]
//do not filter if there is no filter set or cannot determine filter
// do not filter if there is no filter set or cannot determine filter
if !ok || len(fieldValues) == 0 {
return true
}
@@ -247,7 +213,7 @@ func (args Args) ExactMatch(key, source string) bool {
// matches exactly the value.
func (args Args) UniqueExactMatch(key, source string) bool {
fieldValues := args.fields[key]
//do not filter if there is no filter set or cannot determine filter
// do not filter if there is no filter set or cannot determine filter
if len(fieldValues) == 0 {
return true
}
@@ -275,14 +241,6 @@ func (args Args) FuzzyMatch(key, source string) bool {
return false
}
// Include returns true if the key exists in the mapping
//
// Deprecated: use Contains
func (args Args) Include(field string) bool {
_, ok := args.fields[field]
return ok
}
// Contains returns true if the key exists in the mapping
func (args Args) Contains(field string) bool {
_, ok := args.fields[field]
+2 -3
View File
@@ -1,8 +1,7 @@
package image
package image // import "github.com/docker/docker/api/types/image"
// ----------------------------------------------------------------------------
// DO NOT EDIT THIS FILE
// This file was generated by `swagger generate operation`
// Code generated by `swagger generate operation`. DO NOT EDIT.
//
// See hack/generate-swagger-api.sh
// ----------------------------------------------------------------------------
+1 -1
View File
@@ -113,7 +113,7 @@ type TmpfsOptions struct {
// TODO(stevvooe): There are several more tmpfs flags, specified in the
// daemon, that are accepted. Only the most basic are added for now.
//
// From docker/docker/pkg/mount/flags.go:
// From https://github.com/moby/sys/blob/mount/v0.1.1/mount/flags.go#L47-L56
//
// var validFlags = map[string]bool{
// "": true,
+2 -3
View File
@@ -1,7 +1,6 @@
package network // import "github.com/docker/docker/api/types/network"
import (
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/errdefs"
)
// Address represents an IP address
@@ -13,7 +12,7 @@ type Address struct {
// IPAM represents IP Address Management
type IPAM struct {
Driver string
Options map[string]string //Per network IPAM driver options
Options map[string]string // Per network IPAM driver options
Config []IPAMConfig
}
@@ -123,5 +122,5 @@ var acceptedFilters = map[string]bool{
// ValidateFilters validates the list of filter args with the available filters.
func ValidateFilters(filter filters.Args) error {
return errdefs.InvalidParameter(filter.Validate(acceptedFilters))
return filter.Validate(acceptedFilters)
}
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"encoding/json"
"net"
"github.com/opencontainers/image-spec/specs-go/v1"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
)
// ServiceConfig stores daemon registry services configuration.
-94
View File
@@ -1,94 +0,0 @@
package types // import "github.com/docker/docker/api/types"
// Seccomp represents the config for a seccomp profile for syscall restriction.
type Seccomp struct {
DefaultAction Action `json:"defaultAction"`
// Architectures is kept to maintain backward compatibility with the old
// seccomp profile.
Architectures []Arch `json:"architectures,omitempty"`
ArchMap []Architecture `json:"archMap,omitempty"`
Syscalls []*Syscall `json:"syscalls"`
}
// Architecture is used to represent a specific architecture
// and its sub-architectures
type Architecture struct {
Arch Arch `json:"architecture"`
SubArches []Arch `json:"subArchitectures"`
}
// Arch used for architectures
type Arch string
// Additional architectures permitted to be used for system calls
// By default only the native architecture of the kernel is permitted
const (
ArchX86 Arch = "SCMP_ARCH_X86"
ArchX86_64 Arch = "SCMP_ARCH_X86_64"
ArchX32 Arch = "SCMP_ARCH_X32"
ArchARM Arch = "SCMP_ARCH_ARM"
ArchAARCH64 Arch = "SCMP_ARCH_AARCH64"
ArchMIPS Arch = "SCMP_ARCH_MIPS"
ArchMIPS64 Arch = "SCMP_ARCH_MIPS64"
ArchMIPS64N32 Arch = "SCMP_ARCH_MIPS64N32"
ArchMIPSEL Arch = "SCMP_ARCH_MIPSEL"
ArchMIPSEL64 Arch = "SCMP_ARCH_MIPSEL64"
ArchMIPSEL64N32 Arch = "SCMP_ARCH_MIPSEL64N32"
ArchPPC Arch = "SCMP_ARCH_PPC"
ArchPPC64 Arch = "SCMP_ARCH_PPC64"
ArchPPC64LE Arch = "SCMP_ARCH_PPC64LE"
ArchS390 Arch = "SCMP_ARCH_S390"
ArchS390X Arch = "SCMP_ARCH_S390X"
)
// Action taken upon Seccomp rule match
type Action string
// Define actions for Seccomp rules
const (
ActKill Action = "SCMP_ACT_KILL"
ActTrap Action = "SCMP_ACT_TRAP"
ActErrno Action = "SCMP_ACT_ERRNO"
ActTrace Action = "SCMP_ACT_TRACE"
ActAllow Action = "SCMP_ACT_ALLOW"
)
// Operator used to match syscall arguments in Seccomp
type Operator string
// Define operators for syscall arguments in Seccomp
const (
OpNotEqual Operator = "SCMP_CMP_NE"
OpLessThan Operator = "SCMP_CMP_LT"
OpLessEqual Operator = "SCMP_CMP_LE"
OpEqualTo Operator = "SCMP_CMP_EQ"
OpGreaterEqual Operator = "SCMP_CMP_GE"
OpGreaterThan Operator = "SCMP_CMP_GT"
OpMaskedEqual Operator = "SCMP_CMP_MASKED_EQ"
)
// Arg used for matching specific syscall arguments in Seccomp
type Arg struct {
Index uint `json:"index"`
Value uint64 `json:"value"`
ValueTwo uint64 `json:"valueTwo"`
Op Operator `json:"op"`
}
// Filter is used to conditionally apply Seccomp rules
type Filter struct {
Caps []string `json:"caps,omitempty"`
Arches []string `json:"arches,omitempty"`
MinKernel string `json:"minKernel,omitempty"`
}
// Syscall is used to match a group of syscalls in Seccomp
type Syscall struct {
Name string `json:"name,omitempty"`
Names []string `json:"names,omitempty"`
Action Action `json:"action"`
Args []*Arg `json:"args"`
Comment string `json:"comment"`
Includes Filter `json:"includes"`
Excludes Filter `json:"excludes"`
}
+10 -6
View File
@@ -5,6 +5,7 @@ import (
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount"
"github.com/docker/go-units"
)
// DNSConfig specifies DNS related configurations in resolver configuration file (resolv.conf)
@@ -67,10 +68,13 @@ type ContainerSpec struct {
// The format of extra hosts on swarmkit is specified in:
// http://man7.org/linux/man-pages/man5/hosts.5.html
// IP_address canonical_hostname [aliases...]
Hosts []string `json:",omitempty"`
DNSConfig *DNSConfig `json:",omitempty"`
Secrets []*SecretReference `json:",omitempty"`
Configs []*ConfigReference `json:",omitempty"`
Isolation container.Isolation `json:",omitempty"`
Sysctls map[string]string `json:",omitempty"`
Hosts []string `json:",omitempty"`
DNSConfig *DNSConfig `json:",omitempty"`
Secrets []*SecretReference `json:",omitempty"`
Configs []*ConfigReference `json:",omitempty"`
Isolation container.Isolation `json:",omitempty"`
Sysctls map[string]string `json:",omitempty"`
CapabilityAdd []string `json:",omitempty"`
CapabilityDrop []string `json:",omitempty"`
Ulimits []*units.Ulimit `json:",omitempty"`
}
+76 -34
View File
@@ -1,6 +1,5 @@
// Code generated by protoc-gen-gogo.
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: plugin.proto
// DO NOT EDIT!
/*
Package runtime is a generated protocol buffer package.
@@ -38,6 +37,7 @@ type PluginSpec struct {
Remote string `protobuf:"bytes,2,opt,name=remote,proto3" json:"remote,omitempty"`
Privileges []*PluginPrivilege `protobuf:"bytes,3,rep,name=privileges" json:"privileges,omitempty"`
Disabled bool `protobuf:"varint,4,opt,name=disabled,proto3" json:"disabled,omitempty"`
Env []string `protobuf:"bytes,5,rep,name=env" json:"env,omitempty"`
}
func (m *PluginSpec) Reset() { *m = PluginSpec{} }
@@ -73,6 +73,13 @@ func (m *PluginSpec) GetDisabled() bool {
return false
}
func (m *PluginSpec) GetEnv() []string {
if m != nil {
return m.Env
}
return nil
}
// PluginPrivilege describes a permission the user has to accept
// upon installing a plugin.
type PluginPrivilege struct {
@@ -160,6 +167,21 @@ func (m *PluginSpec) MarshalTo(dAtA []byte) (int, error) {
}
i++
}
if len(m.Env) > 0 {
for _, s := range m.Env {
dAtA[i] = 0x2a
i++
l = len(s)
for l >= 1<<7 {
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
l >>= 7
i++
}
dAtA[i] = uint8(l)
i++
i += copy(dAtA[i:], s)
}
}
return i, nil
}
@@ -208,24 +230,6 @@ func (m *PluginPrivilege) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
func encodeFixed64Plugin(dAtA []byte, offset int, v uint64) int {
dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8)
dAtA[offset+2] = uint8(v >> 16)
dAtA[offset+3] = uint8(v >> 24)
dAtA[offset+4] = uint8(v >> 32)
dAtA[offset+5] = uint8(v >> 40)
dAtA[offset+6] = uint8(v >> 48)
dAtA[offset+7] = uint8(v >> 56)
return offset + 8
}
func encodeFixed32Plugin(dAtA []byte, offset int, v uint32) int {
dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8)
dAtA[offset+2] = uint8(v >> 16)
dAtA[offset+3] = uint8(v >> 24)
return offset + 4
}
func encodeVarintPlugin(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
@@ -255,6 +259,12 @@ func (m *PluginSpec) Size() (n int) {
if m.Disabled {
n += 2
}
if len(m.Env) > 0 {
for _, s := range m.Env {
l = len(s)
n += 1 + l + sovPlugin(uint64(l))
}
}
return n
}
@@ -429,6 +439,35 @@ func (m *PluginSpec) Unmarshal(dAtA []byte) error {
}
}
m.Disabled = bool(v != 0)
case 5:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Env", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPlugin
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthPlugin
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Env = append(m.Env, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipPlugin(dAtA[iNdEx:])
@@ -695,18 +734,21 @@ var (
func init() { proto.RegisterFile("plugin.proto", fileDescriptorPlugin) }
var fileDescriptorPlugin = []byte{
// 196 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0xc8, 0x29, 0x4d,
0xcf, 0xcc, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x6a, 0x63, 0xe4, 0xe2, 0x0a, 0x00, 0x0b,
0x04, 0x17, 0xa4, 0x26, 0x0b, 0x09, 0x71, 0xb1, 0xe4, 0x25, 0xe6, 0xa6, 0x4a, 0x30, 0x2a, 0x30,
0x6a, 0x70, 0x06, 0x81, 0xd9, 0x42, 0x62, 0x5c, 0x6c, 0x45, 0xa9, 0xb9, 0xf9, 0x25, 0xa9, 0x12,
0x4c, 0x60, 0x51, 0x28, 0x4f, 0xc8, 0x80, 0x8b, 0xab, 0xa0, 0x28, 0xb3, 0x2c, 0x33, 0x27, 0x35,
0x3d, 0xb5, 0x58, 0x82, 0x59, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x40, 0x0f, 0x62, 0x58, 0x00, 0x4c,
0x22, 0x08, 0x49, 0x8d, 0x90, 0x14, 0x17, 0x47, 0x4a, 0x66, 0x71, 0x62, 0x52, 0x4e, 0x6a, 0x8a,
0x04, 0x8b, 0x02, 0xa3, 0x06, 0x47, 0x10, 0x9c, 0xaf, 0x14, 0xcb, 0xc5, 0x8f, 0xa6, 0x15, 0xab,
0x63, 0x14, 0xb8, 0xb8, 0x53, 0x52, 0x8b, 0x93, 0x8b, 0x32, 0x0b, 0x4a, 0x32, 0xf3, 0xf3, 0xa0,
0x2e, 0x42, 0x16, 0x12, 0x12, 0xe1, 0x62, 0x2d, 0x4b, 0xcc, 0x29, 0x4d, 0x05, 0xbb, 0x88, 0x33,
0x08, 0xc2, 0x71, 0xe2, 0x39, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4,
0x18, 0x93, 0xd8, 0xc0, 0x9e, 0x37, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xb8, 0x84, 0xad, 0x79,
0x0c, 0x01, 0x00, 0x00,
// 256 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0x4d, 0x4b, 0xc3, 0x30,
0x18, 0xc7, 0x89, 0xdd, 0xc6, 0xfa, 0x4c, 0x70, 0x04, 0x91, 0xe2, 0xa1, 0x94, 0x9d, 0x7a, 0x6a,
0x45, 0x2f, 0x82, 0x37, 0x0f, 0x9e, 0x47, 0xbc, 0x09, 0x1e, 0xd2, 0xf6, 0xa1, 0x06, 0x9b, 0x17,
0x92, 0xb4, 0xe2, 0x37, 0xf1, 0x23, 0x79, 0xf4, 0x23, 0x48, 0x3f, 0x89, 0x98, 0x75, 0x32, 0x64,
0xa7, 0xff, 0x4b, 0xc2, 0x9f, 0x1f, 0x0f, 0x9c, 0x9a, 0xae, 0x6f, 0x85, 0x2a, 0x8c, 0xd5, 0x5e,
0x6f, 0x3e, 0x08, 0xc0, 0x36, 0x14, 0x8f, 0x06, 0x6b, 0x4a, 0x61, 0xa6, 0xb8, 0xc4, 0x84, 0x64,
0x24, 0x8f, 0x59, 0xf0, 0xf4, 0x02, 0x16, 0x16, 0xa5, 0xf6, 0x98, 0x9c, 0x84, 0x76, 0x4a, 0xf4,
0x0a, 0xc0, 0x58, 0x31, 0x88, 0x0e, 0x5b, 0x74, 0x49, 0x94, 0x45, 0xf9, 0xea, 0x7a, 0x5d, 0xec,
0xc6, 0xb6, 0xfb, 0x07, 0x76, 0xf0, 0x87, 0x5e, 0xc2, 0xb2, 0x11, 0x8e, 0x57, 0x1d, 0x36, 0xc9,
0x2c, 0x23, 0xf9, 0x92, 0xfd, 0x65, 0xba, 0x86, 0x08, 0xd5, 0x90, 0xcc, 0xb3, 0x28, 0x8f, 0xd9,
0xaf, 0xdd, 0x3c, 0xc3, 0xd9, 0xbf, 0xb1, 0xa3, 0x78, 0x19, 0xac, 0x1a, 0x74, 0xb5, 0x15, 0xc6,
0x0b, 0xad, 0x26, 0xc6, 0xc3, 0x8a, 0x9e, 0xc3, 0x7c, 0xe0, 0x5d, 0x8f, 0x81, 0x31, 0x66, 0xbb,
0x70, 0xff, 0xf0, 0x39, 0xa6, 0xe4, 0x6b, 0x4c, 0xc9, 0xf7, 0x98, 0x92, 0xa7, 0xdb, 0x56, 0xf8,
0x97, 0xbe, 0x2a, 0x6a, 0x2d, 0xcb, 0x46, 0xd7, 0xaf, 0x68, 0xf7, 0xc2, 0x8d, 0x28, 0xfd, 0xbb,
0x41, 0x57, 0xba, 0x37, 0x6e, 0x65, 0x69, 0x7b, 0xe5, 0x85, 0xc4, 0xbb, 0x49, 0xab, 0x45, 0x38,
0xe4, 0xcd, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x99, 0xa8, 0xd9, 0x9b, 0x58, 0x01, 0x00, 0x00,
}
+1
View File
@@ -9,6 +9,7 @@ message PluginSpec {
string remote = 2;
repeated PluginPrivilege privileges = 3;
bool disabled = 4;
repeated string env = 5;
}
// PluginPrivilege describes a permission the user has to accept
+80 -2
View File
@@ -10,6 +10,17 @@ type Service struct {
PreviousSpec *ServiceSpec `json:",omitempty"`
Endpoint Endpoint `json:",omitempty"`
UpdateStatus *UpdateStatus `json:",omitempty"`
// ServiceStatus is an optional, extra field indicating the number of
// desired and running tasks. It is provided primarily as a shortcut to
// calculating these values client-side, which otherwise would require
// listing all tasks for a service, an operation that could be
// computation and network expensive.
ServiceStatus *ServiceStatus `json:",omitempty"`
// JobStatus is the status of a Service which is in one of ReplicatedJob or
// GlobalJob modes. It is absent on Replicated and Global services.
JobStatus *JobStatus `json:",omitempty"`
}
// ServiceSpec represents the spec of a service.
@@ -32,8 +43,10 @@ type ServiceSpec struct {
// ServiceMode represents the mode of a service.
type ServiceMode struct {
Replicated *ReplicatedService `json:",omitempty"`
Global *GlobalService `json:",omitempty"`
Replicated *ReplicatedService `json:",omitempty"`
Global *GlobalService `json:",omitempty"`
ReplicatedJob *ReplicatedJob `json:",omitempty"`
GlobalJob *GlobalJob `json:",omitempty"`
}
// UpdateState is the state of a service update.
@@ -70,6 +83,32 @@ type ReplicatedService struct {
// GlobalService is a kind of ServiceMode.
type GlobalService struct{}
// ReplicatedJob is the a type of Service which executes a defined Tasks
// in parallel until the specified number of Tasks have succeeded.
type ReplicatedJob struct {
// MaxConcurrent indicates the maximum number of Tasks that should be
// executing simultaneously for this job at any given time. There may be
// fewer Tasks that MaxConcurrent executing simultaneously; for example, if
// there are fewer than MaxConcurrent tasks needed to reach
// TotalCompletions.
//
// If this field is empty, it will default to a max concurrency of 1.
MaxConcurrent *uint64 `json:",omitempty"`
// TotalCompletions is the total number of Tasks desired to run to
// completion.
//
// If this field is empty, the value of MaxConcurrent will be used.
TotalCompletions *uint64 `json:",omitempty"`
}
// GlobalJob is the type of a Service which executes a Task on every Node
// matching the Service's placement constraints. These tasks run to completion
// and then exit.
//
// This type is deliberately empty.
type GlobalJob struct{}
const (
// UpdateFailureActionPause PAUSE
UpdateFailureActionPause = "pause"
@@ -122,3 +161,42 @@ type UpdateConfig struct {
// started, or the new task is started before the old task is shut down.
Order string
}
// ServiceStatus represents the number of running tasks in a service and the
// number of tasks desired to be running.
type ServiceStatus struct {
// RunningTasks is the number of tasks for the service actually in the
// Running state
RunningTasks uint64
// DesiredTasks is the number of tasks desired to be running by the
// service. For replicated services, this is the replica count. For global
// services, this is computed by taking the number of tasks with desired
// state of not-Shutdown.
DesiredTasks uint64
// CompletedTasks is the number of tasks in the state Completed, if this
// service is in ReplicatedJob or GlobalJob mode. This field must be
// cross-referenced with the service type, because the default value of 0
// may mean that a service is not in a job mode, or it may mean that the
// job has yet to complete any tasks.
CompletedTasks uint64
}
// JobStatus is the status of a job-type service.
type JobStatus struct {
// JobIteration is a value increased each time a Job is executed,
// successfully or otherwise. "Executed", in this case, means the job as a
// whole has been started, not that an individual Task has been launched. A
// job is "Executed" when its ServiceSpec is updated. JobIteration can be
// used to disambiguate Tasks belonging to different executions of a job.
//
// Though JobIteration will increase with each subsequent execution, it may
// not necessarily increase by 1, and so JobIteration should not be used to
// keep track of the number of times a job has been executed.
JobIteration Version
// LastExecution is the time that the job was last executed, as observed by
// Swarm manager.
LastExecution time.Time `json:",omitempty"`
}
+16 -2
View File
@@ -56,6 +56,12 @@ type Task struct {
DesiredState TaskState `json:",omitempty"`
NetworksAttachments []NetworkAttachment `json:",omitempty"`
GenericResources []GenericResource `json:",omitempty"`
// JobIteration is the JobIteration of the Service that this Task was
// spawned from, if the Service is a ReplicatedJob or GlobalJob. This is
// used to determine which Tasks belong to which run of the job. This field
// is absent if the Service mode is Replicated or Global.
JobIteration *Version `json:",omitempty"`
}
// TaskSpec represents the spec of a task.
@@ -85,13 +91,21 @@ type TaskSpec struct {
Runtime RuntimeType `json:",omitempty"`
}
// Resources represents resources (CPU/Memory).
// Resources represents resources (CPU/Memory) which can be advertised by a
// node and requested to be reserved for a task.
type Resources struct {
NanoCPUs int64 `json:",omitempty"`
MemoryBytes int64 `json:",omitempty"`
GenericResources []GenericResource `json:",omitempty"`
}
// Limit describes limits on resources which can be requested by a task.
type Limit struct {
NanoCPUs int64 `json:",omitempty"`
MemoryBytes int64 `json:",omitempty"`
Pids int64 `json:",omitempty"`
}
// GenericResource represents a "user defined" resource which can
// be either an integer (e.g: SSD=3) or a string (e.g: SSD=sda1)
type GenericResource struct {
@@ -119,7 +133,7 @@ type DiscreteGenericResource struct {
// ResourceRequirements represents resources requirements.
type ResourceRequirements struct {
Limits *Resources `json:",omitempty"`
Limits *Limit `json:",omitempty"`
Reservations *Resources `json:",omitempty"`
}
+35 -15
View File
@@ -39,6 +39,7 @@ type ImageInspect struct {
Author string
Config *container.Config
Architecture string
Variant string `json:",omitempty"`
Os string
OsVersion string `json:",omitempty"`
Size int64
@@ -153,11 +154,11 @@ type Info struct {
Images int
Driver string
DriverStatus [][2]string
SystemStatus [][2]string
SystemStatus [][2]string `json:",omitempty"` // SystemStatus is only propagated by the Swarm standalone API
Plugins PluginsInfo
MemoryLimit bool
SwapLimit bool
KernelMemory bool
KernelMemory bool // Deprecated: kernel 5.4 deprecated kmem.limit_in_bytes
KernelMemoryTCP bool
CPUCfsPeriod bool `json:"CpuCfsPeriod"`
CPUCfsQuota bool `json:"CpuCfsQuota"`
@@ -174,9 +175,11 @@ type Info struct {
SystemTime string
LoggingDriver string
CgroupDriver string
CgroupVersion string `json:",omitempty"`
NEventsListener int
KernelVersion string
OperatingSystem string
OSVersion string
OSType string
Architecture string
IndexServerAddress string
@@ -192,23 +195,24 @@ type Info struct {
Labels []string
ExperimentalBuild bool
ServerVersion string
ClusterStore string
ClusterAdvertise string
ClusterStore string `json:",omitempty"` // Deprecated: host-discovery and overlay networks with external k/v stores are deprecated
ClusterAdvertise string `json:",omitempty"` // Deprecated: host-discovery and overlay networks with external k/v stores are deprecated
Runtimes map[string]Runtime
DefaultRuntime string
Swarm swarm.Info
// LiveRestoreEnabled determines whether containers should be kept
// running when the daemon is shutdown or upon daemon start if
// running containers are detected
LiveRestoreEnabled bool
Isolation container.Isolation
InitBinary string
ContainerdCommit Commit
RuncCommit Commit
InitCommit Commit
SecurityOptions []string
ProductLicense string `json:",omitempty"`
Warnings []string
LiveRestoreEnabled bool
Isolation container.Isolation
InitBinary string
ContainerdCommit Commit
RuncCommit Commit
InitCommit Commit
SecurityOptions []string
ProductLicense string `json:",omitempty"`
DefaultAddressPools []NetworkAddressPool `json:",omitempty"`
Warnings []string
}
// KeyValue holds a key/value pair
@@ -216,6 +220,12 @@ type KeyValue struct {
Key, Value string
}
// NetworkAddressPool is a temp struct used by Info struct
type NetworkAddressPool struct {
Base string
Size int
}
// SecurityOpt contains the name and options of a security option
type SecurityOpt struct {
Name string
@@ -316,7 +326,7 @@ type ContainerState struct {
}
// ContainerNode stores information about the node that a container
// is running on. It's only available in Docker Swarm
// is running on. It's only used by the Docker Swarm standalone API
type ContainerNode struct {
ID string
IPAddress string `json:"IP"`
@@ -340,7 +350,7 @@ type ContainerJSONBase struct {
HostnamePath string
HostsPath string
LogPath string
Node *ContainerNode `json:",omitempty"`
Node *ContainerNode `json:",omitempty"` // Node is only propagated by Docker Swarm standalone API
Name string
RestartCount int
Driver string
@@ -508,6 +518,16 @@ type Checkpoint struct {
type Runtime struct {
Path string `json:"path"`
Args []string `json:"runtimeArgs,omitempty"`
// This is exposed here only for internal use
// It is not currently supported to specify custom shim configs
Shim *ShimConfig `json:"-"`
}
// ShimConfig is used by runtime to configure containerd shims
type ShimConfig struct {
Binary string
Opts interface{}
}
// DiskUsage contains response of Engine API:
+4 -1
View File
@@ -27,10 +27,13 @@ type Volume struct {
Name string `json:"Name"`
// The driver specific options used when creating the volume.
//
// Required: true
Options map[string]string `json:"Options"`
// The level at which the volume exists. Either `global` for cluster-wide, or `local` for machine level.
// The level at which the volume exists. Either `global` for cluster-wide,
// or `local` for machine level.
//
// Required: true
Scope string `json:"Scope"`
+6 -4
View File
@@ -1,8 +1,7 @@
package volume
package volume // import "github.com/docker/docker/api/types/volume"
// ----------------------------------------------------------------------------
// DO NOT EDIT THIS FILE
// This file was generated by `swagger generate operation`
// Code generated by `swagger generate operation`. DO NOT EDIT.
//
// See hack/generate-swagger-api.sh
// ----------------------------------------------------------------------------
@@ -15,7 +14,9 @@ type VolumeCreateBody struct {
// Required: true
Driver string `json:"Driver"`
// A mapping of driver options and values. These options are passed directly to the driver and are driver specific.
// A mapping of driver options and values. These options are
// passed directly to the driver and are driver specific.
//
// Required: true
DriverOpts map[string]string `json:"DriverOpts"`
@@ -24,6 +25,7 @@ type VolumeCreateBody struct {
Labels map[string]string `json:"Labels"`
// The new volume's name. If not specified, Docker generates a name.
//
// Required: true
Name string `json:"Name"`
}
+4 -4
View File
@@ -1,8 +1,7 @@
package volume
package volume // import "github.com/docker/docker/api/types/volume"
// ----------------------------------------------------------------------------
// DO NOT EDIT THIS FILE
// This file was generated by `swagger generate operation`
// Code generated by `swagger generate operation`. DO NOT EDIT.
//
// See hack/generate-swagger-api.sh
// ----------------------------------------------------------------------------
@@ -17,7 +16,8 @@ type VolumeListOKBody struct {
// Required: true
Volumes []*types.Volume `json:"Volumes"`
// Warnings that occurred when fetching the list of volumes
// Warnings that occurred when fetching the list of volumes.
//
// Required: true
Warnings []string `json:"Warnings"`
}
+2 -2
View File
@@ -60,8 +60,8 @@ type ImageBackend interface {
type ExecBackend interface {
// ContainerAttachRaw attaches to container.
ContainerAttachRaw(cID string, stdin io.ReadCloser, stdout, stderr io.Writer, stream bool, attached chan struct{}) error
// ContainerCreate creates a new Docker container and returns potential warnings
ContainerCreate(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error)
// ContainerCreateIgnoreImagesArgsEscaped creates a new Docker container and returns potential warnings
ContainerCreateIgnoreImagesArgsEscaped(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error)
// ContainerRm removes a container specified by `id`.
ContainerRm(name string, config *types.ContainerRmConfig) error
// ContainerKill stops the container execution abruptly.
+7 -58
View File
@@ -8,14 +8,12 @@ import (
"io/ioutil"
"sort"
"strings"
"time"
"github.com/containerd/containerd/platforms"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/builder"
"github.com/docker/docker/builder/fscache"
"github.com/docker/docker/builder/remotecontext"
"github.com/docker/docker/errdefs"
"github.com/docker/docker/pkg/idtools"
@@ -25,7 +23,6 @@ import (
"github.com/moby/buildkit/frontend/dockerfile/instructions"
"github.com/moby/buildkit/frontend/dockerfile/parser"
"github.com/moby/buildkit/frontend/dockerfile/shell"
"github.com/moby/buildkit/session"
specs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -49,31 +46,19 @@ const (
stepFormat = "Step %d/%d : %v"
)
// SessionGetter is object used to get access to a session by uuid
type SessionGetter interface {
Get(ctx context.Context, uuid string) (session.Caller, error)
}
// BuildManager is shared across all Builder objects
type BuildManager struct {
idMapping *idtools.IdentityMapping
backend builder.Backend
pathCache pathCache // TODO: make this persistent
sg SessionGetter
fsCache *fscache.FSCache
}
// NewBuildManager creates a BuildManager
func NewBuildManager(b builder.Backend, sg SessionGetter, fsCache *fscache.FSCache, identityMapping *idtools.IdentityMapping) (*BuildManager, error) {
func NewBuildManager(b builder.Backend, identityMapping *idtools.IdentityMapping) (*BuildManager, error) {
bm := &BuildManager{
backend: b,
pathCache: &syncmap.Map{},
sg: sg,
idMapping: identityMapping,
fsCache: fsCache,
}
if err := fsCache.RegisterTransport(remotecontext.ClientSessionRemote, NewClientSessionTransport()); err != nil {
return nil, err
}
return bm, nil
}
@@ -100,12 +85,6 @@ func (bm *BuildManager) Build(ctx context.Context, config backend.BuildConfig) (
ctx, cancel := context.WithCancel(ctx)
defer cancel()
if src, err := bm.initializeClientSession(ctx, cancel, config.Options); err != nil {
return nil, err
} else if src != nil {
source = src
}
builderOptions := builderOptions{
Options: config.Options,
ProgressWriter: config.ProgressWriter,
@@ -120,39 +99,6 @@ func (bm *BuildManager) Build(ctx context.Context, config backend.BuildConfig) (
return b.build(source, dockerfile)
}
func (bm *BuildManager) initializeClientSession(ctx context.Context, cancel func(), options *types.ImageBuildOptions) (builder.Source, error) {
if options.SessionID == "" || bm.sg == nil {
return nil, nil
}
logrus.Debug("client is session enabled")
connectCtx, cancelCtx := context.WithTimeout(ctx, sessionConnectTimeout)
defer cancelCtx()
c, err := bm.sg.Get(connectCtx, options.SessionID)
if err != nil {
return nil, err
}
go func() {
<-c.Context().Done()
cancel()
}()
if options.RemoteContext == remotecontext.ClientSessionRemote {
st := time.Now()
csi, err := NewClientSessionSourceIdentifier(ctx, bm.sg, options.SessionID)
if err != nil {
return nil, err
}
src, err := bm.fsCache.SyncFrom(ctx, csi)
if err != nil {
return nil, err
}
logrus.Debugf("sync-time: %v", time.Since(st))
return src, nil
}
return nil, nil
}
// builderOptions are the dependencies required by the builder
type builderOptions struct {
Options *types.ImageBuildOptions
@@ -244,7 +190,8 @@ func (b *Builder) build(source builder.Source, dockerfile *parser.Result) (*buil
stages, metaArgs, err := instructions.Parse(dockerfile.AST)
if err != nil {
if instructions.IsUnknownInstruction(err) {
var uiErr *instructions.UnknownInstruction
if errors.As(err, &uiErr) {
buildsFailed.WithValues(metricsUnknownInstructionError).Inc()
}
return nil, errdefs.InvalidParameter(err)
@@ -288,8 +235,10 @@ func processMetaArg(meta instructions.ArgCommand, shlex *shell.Lex, args *BuildA
}); err != nil {
return err
}
args.AddArg(meta.Key, meta.Value)
args.AddMetaArg(meta.Key, meta.Value)
for _, arg := range meta.Args {
args.AddArg(arg.Key, arg.Value)
args.AddMetaArg(arg.Key, arg.Value)
}
return nil
}
-76
View File
@@ -1,76 +0,0 @@
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
import (
"context"
"time"
"github.com/docker/docker/builder/fscache"
"github.com/docker/docker/builder/remotecontext"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/filesync"
"github.com/pkg/errors"
)
const sessionConnectTimeout = 5 * time.Second
// ClientSessionTransport is a transport for copying files from docker client
// to the daemon.
type ClientSessionTransport struct{}
// NewClientSessionTransport returns new ClientSessionTransport instance
func NewClientSessionTransport() *ClientSessionTransport {
return &ClientSessionTransport{}
}
// Copy data from a remote to a destination directory.
func (cst *ClientSessionTransport) Copy(ctx context.Context, id fscache.RemoteIdentifier, dest string, cu filesync.CacheUpdater) error {
csi, ok := id.(*ClientSessionSourceIdentifier)
if !ok {
return errors.New("invalid identifier for client session")
}
return filesync.FSSync(ctx, csi.caller, filesync.FSSendRequestOpt{
IncludePatterns: csi.includePatterns,
DestDir: dest,
CacheUpdater: cu,
})
}
// ClientSessionSourceIdentifier is an identifier that can be used for requesting
// files from remote client
type ClientSessionSourceIdentifier struct {
includePatterns []string
caller session.Caller
uuid string
}
// NewClientSessionSourceIdentifier returns new ClientSessionSourceIdentifier instance
func NewClientSessionSourceIdentifier(ctx context.Context, sg SessionGetter, uuid string) (*ClientSessionSourceIdentifier, error) {
csi := &ClientSessionSourceIdentifier{
uuid: uuid,
}
caller, err := sg.Get(ctx, uuid)
if err != nil {
return nil, errors.Wrapf(err, "failed to get session for %s", uuid)
}
csi.caller = caller
return csi, nil
}
// Transport returns transport identifier for remote identifier
func (csi *ClientSessionSourceIdentifier) Transport() string {
return remotecontext.ClientSessionRemote
}
// SharedKey returns shared key for remote identifier. Shared key is used
// for finding the base for a repeated transfer.
func (csi *ClientSessionSourceIdentifier) SharedKey() string {
return csi.caller.SharedKey()
}
// Key returns unique key for remote identifier. Requests with same key return
// same data.
func (csi *ClientSessionSourceIdentifier) Key() string {
return csi.uuid
}
+2 -2
View File
@@ -29,7 +29,7 @@ func newContainerManager(docker builder.ExecBackend) *containerManager {
// Create a container
func (c *containerManager) Create(runConfig *container.Config, hostConfig *container.HostConfig) (container.ContainerCreateCreatedBody, error) {
container, err := c.backend.ContainerCreate(types.ContainerCreateConfig{
container, err := c.backend.ContainerCreateIgnoreImagesArgsEscaped(types.ContainerCreateConfig{
Config: runConfig,
HostConfig: hostConfig,
})
@@ -45,7 +45,7 @@ var errCancelled = errors.New("build cancelled")
// Run a container by ID
func (c *containerManager) Run(ctx context.Context, cID string, stdout, stderr io.Writer) (err error) {
attached := make(chan struct{})
errCh := make(chan error)
errCh := make(chan error, 1)
go func() {
errCh <- c.backend.ContainerAttachRaw(cID, nil, stdout, stderr, true, attached)
}()
+35 -11
View File
@@ -64,6 +64,7 @@ type copyInstruction struct {
dest string
chownStr string
allowLocalDecompression bool
preserveOwnership bool
}
// copier reads a raw COPY or ADD command, fetches remote sources using a downloader,
@@ -241,6 +242,8 @@ func (o *copier) calcCopyInfo(origPath string, allowWildcards bool) ([]copyInfo,
// Deal with the single file case
copyInfo, err := copyInfoForFile(o.source, origPath)
switch {
case imageSource == nil && errors.Is(err, os.ErrNotExist):
return nil, errors.Wrapf(err, "file not found in build context or excluded by .dockerignore")
case err != nil:
return nil, err
case copyInfo.hash != "":
@@ -314,6 +317,10 @@ func (o *copier) copyWithWildcards(origPath string) ([]copyInfo, error) {
func copyInfoForFile(source builder.Source, path string) (copyInfo, error) {
fi, err := remotecontext.StatAt(source, path)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
// return the relative path in the error, which is more user-friendly than the full path to the tmp-dir
return copyInfo{}, errors.WithStack(&os.PathError{Op: "stat", Path: path, Err: os.ErrNotExist})
}
return copyInfo{}, err
}
@@ -466,7 +473,7 @@ func downloadSource(output io.Writer, stdout io.Writer, srcURL string) (remote b
type copyFileOptions struct {
decompress bool
identity idtools.Identity
identity *idtools.Identity
archiver Archiver
}
@@ -532,7 +539,7 @@ func isArchivePath(driver containerfs.ContainerFS, path string) bool {
return err == nil
}
func copyDirectory(archiver Archiver, source, dest *copyEndpoint, identity idtools.Identity) error {
func copyDirectory(archiver Archiver, source, dest *copyEndpoint, identity *idtools.Identity) error {
destExists, err := isExistingDirectory(dest)
if err != nil {
return errors.Wrapf(err, "failed to query destination path")
@@ -541,28 +548,45 @@ func copyDirectory(archiver Archiver, source, dest *copyEndpoint, identity idtoo
if err := archiver.CopyWithTar(source.path, dest.path); err != nil {
return errors.Wrapf(err, "failed to copy directory")
}
// TODO: @gupta-ak. Investigate how LCOW permission mappings will work.
return fixPermissions(source.path, dest.path, identity, !destExists)
if identity != nil {
// TODO: @gupta-ak. Investigate how LCOW permission mappings will work.
return fixPermissions(source.path, dest.path, *identity, !destExists)
}
return nil
}
func copyFile(archiver Archiver, source, dest *copyEndpoint, identity idtools.Identity) error {
func copyFile(archiver Archiver, source, dest *copyEndpoint, identity *idtools.Identity) error {
if runtime.GOOS == "windows" && dest.driver.OS() == "linux" {
// LCOW
if err := dest.driver.MkdirAll(dest.driver.Dir(dest.path), 0755); err != nil {
return errors.Wrapf(err, "failed to create new directory")
}
} else {
if err := idtools.MkdirAllAndChownNew(filepath.Dir(dest.path), 0755, identity); err != nil {
// Normal containers
return errors.Wrapf(err, "failed to create new directory")
// Normal containers
if identity == nil {
// Use system.MkdirAll here, which is a custom version of os.MkdirAll
// modified for use on Windows to handle volume GUID paths. These paths
// are of the form \\?\Volume{<GUID>}\<path>. An example would be:
// \\?\Volume{dae8d3ac-b9a1-11e9-88eb-e8554b2ba1db}\bin\busybox.exe
if err := system.MkdirAll(filepath.Dir(dest.path), 0755); err != nil {
return err
}
} else {
if err := idtools.MkdirAllAndChownNew(filepath.Dir(dest.path), 0755, *identity); err != nil {
return errors.Wrapf(err, "failed to create new directory")
}
}
}
if err := archiver.CopyFileWithTar(source.path, dest.path); err != nil {
return errors.Wrapf(err, "failed to copy file")
}
// TODO: @gupta-ak. Investigate how LCOW permission mappings will work.
return fixPermissions(source.path, dest.path, identity, false)
if identity != nil {
// TODO: @gupta-ak. Investigate how LCOW permission mappings will work.
return fixPermissions(source.path, dest.path, *identity, false)
}
return nil
}
func endsInSlash(driver containerfs.Driver, path string) bool {
@@ -573,7 +597,7 @@ func endsInSlash(driver containerfs.Driver, path string) bool {
func isExistingDirectory(point *copyEndpoint) (bool, error) {
destStat, err := point.driver.Stat(point.path)
switch {
case os.IsNotExist(err):
case errors.Is(err, os.ErrNotExist):
return false, nil
case err != nil:
return false, err
+1 -1
View File
@@ -25,7 +25,7 @@ func fixPermissions(source, destination string, identity idtools.Identity, overr
// We Walk on the source rather than on the destination because we don't
// want to change permissions on things we haven't created or modified.
return filepath.Walk(source, func(fullpath string, info os.FileInfo, err error) error {
return filepath.Walk(source, func(fullpath string, _ os.FileInfo, _ error) error {
// Do not alter the walk root iff. it existed before, as it doesn't fall under
// the domain of "things we should chown".
if skipChownRoot && source == fullpath {
+6 -10
View File
@@ -6,7 +6,7 @@ import (
"path/filepath"
"strings"
"github.com/Microsoft/go-winio"
winio "github.com/Microsoft/go-winio"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/reexec"
"github.com/docker/docker/pkg/system"
@@ -14,7 +14,7 @@ import (
"golang.org/x/sys/windows"
)
var pathBlacklist = map[string]bool{
var pathDenyList = map[string]bool{
"c:\\": true,
"c:\\windows": true,
}
@@ -67,21 +67,17 @@ func fixPermissionsWindows(source, destination, SID string) error {
sddlString := system.SddlAdministratorsLocalSystem
sddlString += "(A;OICI;GRGWGXRCWDSD;;;" + SID + ")"
securityDescriptor, err := winio.SddlToSecurityDescriptor(sddlString)
securityDescriptor, err := windows.SecurityDescriptorFromString(sddlString)
if err != nil {
return err
}
var daclPresent uint32
var daclDefaulted uint32
var dacl *byte
err = system.GetSecurityDescriptorDacl(&securityDescriptor[0], &daclPresent, &dacl, &daclDefaulted)
dacl, _, err := securityDescriptor.DACL()
if err != nil {
return err
}
return system.SetNamedSecurityInfo(windows.StringToUTF16Ptr(destination), system.SE_FILE_OBJECT, system.OWNER_SECURITY_INFORMATION|system.DACL_SECURITY_INFORMATION, sid, nil, dacl, nil)
return windows.SetNamedSecurityInfo(destination, windows.SE_FILE_OBJECT, windows.OWNER_SECURITY_INFORMATION|windows.DACL_SECURITY_INFORMATION, sid, nil, dacl, nil)
}
func validateCopySourcePath(imageSource *imageMount, origPath, platform string) error {
@@ -102,7 +98,7 @@ func validateCopySourcePath(imageSource *imageMount, origPath, platform string)
p = filepath.Join("c:\\", p)
}
}
if _, blacklisted := pathBlacklist[p]; blacklisted {
if _, ok := pathDenyList[p]; ok {
return errors.New("copy from c:\\ or c:\\windows is not allowed on windows")
}
return nil
+66 -26
View File
@@ -16,7 +16,6 @@ import (
"github.com/containerd/containerd/platforms"
"github.com/docker/docker/api"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/strslice"
"github.com/docker/docker/builder"
"github.com/docker/docker/errdefs"
@@ -93,6 +92,9 @@ func dispatchLabel(d dispatchRequest, c *instructions.LabelCommand) error {
// exist here. If you do not wish to have this automatic handling, use COPY.
//
func dispatchAdd(d dispatchRequest, c *instructions.AddCommand) error {
if c.Chmod != "" {
return errors.New("the --chmod option requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled")
}
downloader := newRemoteSourceDownloader(d.builder.Output, d.builder.Stdout)
copier := copierFromDispatchRequest(d, downloader, nil)
defer copier.Cleanup()
@@ -112,6 +114,9 @@ func dispatchAdd(d dispatchRequest, c *instructions.AddCommand) error {
// Same as 'ADD' but without the tar and remote url handling.
//
func dispatchCopy(d dispatchRequest, c *instructions.CopyCommand) error {
if c.Chmod != "" {
return errors.New("the --chmod option requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled")
}
var im *imageMount
var err error
if c.From != "" {
@@ -127,7 +132,9 @@ func dispatchCopy(d dispatchRequest, c *instructions.CopyCommand) error {
return err
}
copyInstruction.chownStr = c.Chown
if c.From != "" && copyInstruction.chownStr == "" {
copyInstruction.preserveOwnership = true
}
return d.builder.performCopy(d, copyInstruction)
}
@@ -204,7 +211,8 @@ func dispatchTriggeredOnBuild(d dispatchRequest, triggers []string) error {
}
cmd, err := instructions.ParseCommand(ast.AST.Children[0])
if err != nil {
if instructions.IsUnknownInstruction(err) {
var uiErr *instructions.UnknownInstruction
if errors.As(err, &uiErr) {
buildsFailed.WithValues(metricsUnknownInstructionError).Inc()
}
return err
@@ -330,14 +338,6 @@ func dispatchWorkdir(d dispatchRequest, c *instructions.WorkdirCommand) error {
return d.builder.commitContainer(d.state, containerID, runConfigWithCommentCmd)
}
func resolveCmdLine(cmd instructions.ShellDependantCmdLine, runConfig *container.Config, os string) []string {
result := cmd.CmdLine
if cmd.PrependShell && result != nil {
result = append(getShell(runConfig, os), result...)
}
return result
}
// RUN some command yo
//
// run a command and commit the image. Args are automatically prepended with
@@ -352,8 +352,14 @@ func dispatchRun(d dispatchRequest, c *instructions.RunCommand) error {
if !system.IsOSSupported(d.state.operatingSystem) {
return system.ErrNotSupportedOperatingSystem
}
if len(c.FlagsUsed) > 0 {
// classic builder RUN currently does not support any flags, so fail on the first one
return errors.Errorf("the --%s option requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled", c.FlagsUsed[0])
}
stateRunConfig := d.state.runConfig
cmdFromArgs := resolveCmdLine(c.ShellDependantCmdLine, stateRunConfig, d.state.operatingSystem)
cmdFromArgs, argsEscaped := resolveCmdLine(c.ShellDependantCmdLine, stateRunConfig, d.state.operatingSystem, c.Name(), c.String())
buildArgs := d.state.buildArgs.FilterAllowed(stateRunConfig.Env)
saveCmd := cmdFromArgs
@@ -363,6 +369,7 @@ func dispatchRun(d dispatchRequest, c *instructions.RunCommand) error {
runConfigForCacheProbe := copyRunConfig(stateRunConfig,
withCmd(saveCmd),
withArgsEscaped(argsEscaped),
withEntrypointOverride(saveCmd, nil))
if hit, err := d.builder.probeCache(d.state, runConfigForCacheProbe); err != nil || hit {
return err
@@ -370,13 +377,11 @@ func dispatchRun(d dispatchRequest, c *instructions.RunCommand) error {
runConfig := copyRunConfig(stateRunConfig,
withCmd(cmdFromArgs),
withArgsEscaped(argsEscaped),
withEnv(append(stateRunConfig.Env, buildArgs...)),
withEntrypointOverride(saveCmd, strslice.StrSlice{""}),
withoutHealthcheck())
// set config as already being escaped, this prevents double escaping on windows
runConfig.ArgsEscaped = true
cID, err := d.builder.create(runConfig)
if err != nil {
return err
@@ -399,6 +404,12 @@ func dispatchRun(d dispatchRequest, c *instructions.RunCommand) error {
return err
}
// Don't persist the argsEscaped value in the committed image. Use the original
// from previous build steps (only CMD and ENTRYPOINT persist this).
if d.state.operatingSystem == "windows" {
runConfigForCacheProbe.ArgsEscaped = stateRunConfig.ArgsEscaped
}
return d.builder.commitContainer(d.state, cID, runConfigForCacheProbe)
}
@@ -434,15 +445,23 @@ func prependEnvOnCmd(buildArgs *BuildArgs, buildArgVars []string, cmd strslice.S
//
func dispatchCmd(d dispatchRequest, c *instructions.CmdCommand) error {
runConfig := d.state.runConfig
cmd := resolveCmdLine(c.ShellDependantCmdLine, runConfig, d.state.operatingSystem)
cmd, argsEscaped := resolveCmdLine(c.ShellDependantCmdLine, runConfig, d.state.operatingSystem, c.Name(), c.String())
// We warn here as Windows shell processing operates differently to Linux.
// Linux: /bin/sh -c "echo hello" world --> hello
// Windows: cmd /s /c "echo hello" world --> hello world
if d.state.operatingSystem == "windows" &&
len(runConfig.Entrypoint) > 0 &&
d.state.runConfig.ArgsEscaped != argsEscaped {
fmt.Fprintf(d.builder.Stderr, " ---> [Warning] Shell-form ENTRYPOINT and exec-form CMD may have unexpected results\n")
}
runConfig.Cmd = cmd
// set config as already being escaped, this prevents double escaping on windows
runConfig.ArgsEscaped = true
runConfig.ArgsEscaped = argsEscaped
if err := d.builder.commit(d.state, fmt.Sprintf("CMD %q", cmd)); err != nil {
return err
}
if len(c.ShellDependantCmdLine.CmdLine) != 0 {
d.state.cmdSet = true
}
@@ -477,8 +496,22 @@ func dispatchHealthcheck(d dispatchRequest, c *instructions.HealthCheckCommand)
//
func dispatchEntrypoint(d dispatchRequest, c *instructions.EntrypointCommand) error {
runConfig := d.state.runConfig
cmd := resolveCmdLine(c.ShellDependantCmdLine, runConfig, d.state.operatingSystem)
cmd, argsEscaped := resolveCmdLine(c.ShellDependantCmdLine, runConfig, d.state.operatingSystem, c.Name(), c.String())
// This warning is a little more complex than in dispatchCmd(), as the Windows base images (similar
// universally to almost every Linux image out there) have a single .Cmd field populated so that
// `docker run --rm image` starts the default shell which would typically be sh on Linux,
// or cmd on Windows. The catch to this is that if a dockerfile had `CMD ["c:\\windows\\system32\\cmd.exe"]`,
// we wouldn't be able to tell the difference. However, that would be highly unlikely, and besides, this
// is only trying to give a helpful warning of possibly unexpected results.
if d.state.operatingSystem == "windows" &&
d.state.runConfig.ArgsEscaped != argsEscaped &&
((len(runConfig.Cmd) == 1 && strings.ToLower(runConfig.Cmd[0]) != `c:\windows\system32\cmd.exe` && len(runConfig.Shell) == 0) || (len(runConfig.Cmd) > 1)) {
fmt.Fprintf(d.builder.Stderr, " ---> [Warning] Shell-form CMD and exec-form ENTRYPOINT may have unexpected results\n")
}
runConfig.Entrypoint = cmd
runConfig.ArgsEscaped = argsEscaped
if !d.state.cmdSet {
runConfig.Cmd = nil
}
@@ -566,14 +599,21 @@ func dispatchStopSignal(d dispatchRequest, c *instructions.StopSignalCommand) er
// to builder using the --build-arg flag for expansion/substitution or passing to 'run'.
// Dockerfile author may optionally set a default value of this variable.
func dispatchArg(d dispatchRequest, c *instructions.ArgCommand) error {
commitStr := "ARG " + c.Key
if c.Value != nil {
commitStr += "=" + *c.Value
var commitStr strings.Builder
commitStr.WriteString("ARG ")
for i, arg := range c.Args {
if i > 0 {
commitStr.WriteString(" ")
}
commitStr.WriteString(arg.Key)
if arg.Value != nil {
commitStr.WriteString("=")
commitStr.WriteString(*arg.Value)
}
d.state.buildArgs.AddArg(arg.Key, arg.Value)
}
d.state.buildArgs.AddArg(c.Key, c.Value)
return d.builder.commit(d.state, commitStr)
return d.builder.commit(d.state, commitStr.String())
}
// SHELL powershell -command
+13
View File
@@ -6,6 +6,9 @@ import (
"errors"
"os"
"path/filepath"
"github.com/docker/docker/api/types/container"
"github.com/moby/buildkit/frontend/dockerfile/instructions"
)
// normalizeWorkdir normalizes a user requested working directory in a
@@ -21,3 +24,13 @@ func normalizeWorkdir(_ string, current string, requested string) (string, error
}
return requested, nil
}
// resolveCmdLine takes a command line arg set and optionally prepends a platform-specific
// shell in front of it.
func resolveCmdLine(cmd instructions.ShellDependantCmdLine, runConfig *container.Config, os, _, _ string) ([]string, bool) {
result := cmd.CmdLine
if cmd.PrependShell && result != nil {
result = append(getShell(runConfig, os), result...)
}
return result, false
}
@@ -9,7 +9,9 @@ import (
"regexp"
"strings"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/system"
"github.com/moby/buildkit/frontend/dockerfile/instructions"
)
var pattern = regexp.MustCompile(`^[a-zA-Z]:\.$`)
@@ -93,3 +95,47 @@ func normalizeWorkdirWindows(current string, requested string) (string, error) {
// Upper-case drive letter
return (strings.ToUpper(string(requested[0])) + requested[1:]), nil
}
// resolveCmdLine takes a command line arg set and optionally prepends a platform-specific
// shell in front of it. It returns either an array of arguments and an indication that
// the arguments are not yet escaped; Or, an array containing a single command line element
// along with an indication that the arguments are escaped so the runtime shouldn't escape.
//
// A better solution could be made, but it would be exceptionally invasive throughout
// many parts of the daemon which are coded assuming Linux args array only only, not taking
// account of Windows-natural command line semantics and it's argv handling. Put another way,
// while what is here is good-enough, it could be improved, but would be highly invasive.
//
// The commands when this function is called are RUN, ENTRYPOINT and CMD.
func resolveCmdLine(cmd instructions.ShellDependantCmdLine, runConfig *container.Config, os, command, original string) ([]string, bool) {
// Make sure we return an empty array if there is no cmd.CmdLine
if len(cmd.CmdLine) == 0 {
return []string{}, runConfig.ArgsEscaped
}
if os == "windows" { // ie WCOW
if cmd.PrependShell {
// WCOW shell-form. Return a single-element array containing the original command line prepended with the shell.
// Also indicate that it has not been escaped (so will be passed through directly to HCS). Note that
// we go back to the original un-parsed command line in the dockerfile line, strip off both the command part of
// it (RUN/ENTRYPOINT/CMD), and also strip any leading white space. IOW, we deliberately ignore any prior parsing
// so as to ensure it is treated exactly as a command line. For those interested, `RUN mkdir "c:/foo"` is a particularly
// good example of why this is necessary if you fancy debugging how cmd.exe and its builtin mkdir works. (Windows
// doesn't have a mkdir.exe, and I'm guessing cmd.exe has some very long unavoidable and unchangeable historical
// design decisions over how both its built-in echo and mkdir are coded. Probably more too.)
original = original[len(command):] // Strip off the command
original = strings.TrimLeft(original, " \t\v\n") // Strip of leading whitespace
return []string{strings.Join(getShell(runConfig, os), " ") + " " + original}, true
}
// WCOW JSON/"exec" form.
return cmd.CmdLine, false
}
// LCOW - use args as an array, same as LCOL.
if cmd.PrependShell && cmd.CmdLine != nil {
return append(getShell(runConfig, os), cmd.CmdLine...), false
}
return cmd.CmdLine, false
}
+18 -8
View File
@@ -4,6 +4,7 @@ import (
"context"
"runtime"
"github.com/containerd/containerd/platforms"
"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/builder"
dockerimage "github.com/docker/docker/image"
@@ -56,7 +57,7 @@ func (m *imageSources) Get(idOrRef string, localOnly bool, platform *specs.Platf
return nil, err
}
im := newImageMount(image, layer)
m.Add(im)
m.Add(im, platform)
return im, nil
}
@@ -70,16 +71,26 @@ func (m *imageSources) Unmount() (retErr error) {
return
}
func (m *imageSources) Add(im *imageMount) {
func (m *imageSources) Add(im *imageMount, platform *specs.Platform) {
switch im.image {
case nil:
// set the OS for scratch images
os := runtime.GOOS
// Set the platform for scratch images
if platform == nil {
p := platforms.DefaultSpec()
platform = &p
}
// Windows does not support scratch except for LCOW
os := platform.OS
if runtime.GOOS == "windows" {
os = "linux"
}
im.image = &dockerimage.Image{V1Image: dockerimage.V1Image{OS: os}}
im.image = &dockerimage.Image{V1Image: dockerimage.V1Image{
OS: os,
Architecture: platform.Architecture,
Variant: platform.Variant,
}}
default:
m.byImageID[im.image.ImageID()] = im
}
@@ -88,9 +99,8 @@ func (m *imageSources) Add(im *imageMount) {
// imageMount is a reference to an image that can be used as a builder.Source
type imageMount struct {
image builder.Image
source builder.Source
layer builder.ROLayer
image builder.Image
layer builder.ROLayer
}
func newImageMount(image builder.Image, layer builder.ROLayer) *imageMount {
+21 -6
View File
@@ -26,6 +26,7 @@ import (
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/system"
"github.com/docker/go-connections/nat"
specs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -117,15 +118,21 @@ func (b *Builder) exportImage(state *dispatchState, layer builder.RWLayer, paren
return err
}
// add an image mount without an image so the layer is properly unmounted
// if there is an error before we can add the full mount with image
b.imageSources.Add(newImageMount(nil, newLayer))
parentImage, ok := parent.(*image.Image)
if !ok {
return errors.Errorf("unexpected image type")
}
platform := &specs.Platform{
OS: parentImage.OS,
Architecture: parentImage.Architecture,
Variant: parentImage.Variant,
}
// add an image mount without an image so the layer is properly unmounted
// if there is an error before we can add the full mount with image
b.imageSources.Add(newImageMount(nil, newLayer), platform)
newImage := image.NewChildImage(parentImage, image.ChildConfig{
Author: state.maintainer,
ContainerConfig: runConfig,
@@ -146,7 +153,7 @@ func (b *Builder) exportImage(state *dispatchState, layer builder.RWLayer, paren
}
state.imageID = exportedImage.ImageID()
b.imageSources.Add(newImageMount(exportedImage, newLayer))
b.imageSources.Add(newImageMount(exportedImage, newLayer), platform)
return nil
}
@@ -204,7 +211,9 @@ func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
opts := copyFileOptions{
decompress: inst.allowLocalDecompression,
archiver: b.getArchiver(info.root, destInfo.root),
identity: identity,
}
if !inst.preserveOwnership {
opts.identity = &identity
}
if err := performCopyForInfo(destInfo, info, opts); err != nil {
return errors.Wrapf(err, "failed to copy files")
@@ -308,6 +317,12 @@ func withCmd(cmd []string) runConfigModifier {
}
}
func withArgsEscaped(argsEscaped bool) runConfigModifier {
return func(runConfig *container.Config) {
runConfig.ArgsEscaped = argsEscaped
}
}
// withCmdComment sets Cmd to a nop comment string. See withCmdCommentString for
// why there are two almost identical versions of this.
func withCmdComment(comment string, platform string) runConfigModifier {
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"strings"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/symlink"
"github.com/moby/sys/symlink"
lcUser "github.com/opencontainers/runc/libcontainer/user"
"github.com/pkg/errors"
)
+2 -16
View File
@@ -12,7 +12,6 @@ import (
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/pkg/system"
"github.com/pkg/errors"
"golang.org/x/sys/windows"
)
@@ -31,13 +30,7 @@ func getAccountIdentity(builder *Builder, accountName string, ctrRootPath string
sid, err := windows.StringToSid(accountName)
if err == nil {
accountSid, err := sid.String()
if err != nil {
return idtools.Identity{SID: ""}, errors.Wrapf(err, "error converting SID to string")
}
return idtools.Identity{SID: accountSid}, nil
return idtools.Identity{SID: sid.String()}, nil
}
}
@@ -46,13 +39,7 @@ func getAccountIdentity(builder *Builder, accountName string, ctrRootPath string
// If this is a SID that is built-in and hence the same across all systems then use that.
if err == nil && (accType == windows.SidTypeAlias || accType == windows.SidTypeWellKnownGroup) {
accountSid, err := sid.String()
if err != nil {
return idtools.Identity{SID: ""}, errors.Wrapf(err, "error converting SID to string")
}
return idtools.Identity{SID: accountSid}, nil
return idtools.Identity{SID: sid.String()}, nil
}
// Check if the account name is one unique to containers.
@@ -83,7 +70,6 @@ func lookupNTAccount(builder *Builder, accountName string, state *dispatchState)
runConfig := copyRunConfig(state.runConfig,
withCmdCommentString("internal run to obtain NT account information.", optionsPlatform.OS))
runConfig.ArgsEscaped = true
runConfig.Cmd = []string{targetExecutable, "getaccountsid", accountName}
hostConfig := &container.HostConfig{Mounts: []mount.Mount{
+1 -1
View File
@@ -1,7 +1,7 @@
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
import (
"github.com/docker/go-metrics"
metrics "github.com/docker/go-metrics"
)
var (
+17
View File
@@ -0,0 +1,17 @@
// Package dockerignore is deprecated. Use github.com/moby/buildkit/frontend/dockerfile/dockerignore instead.
package dockerignore
import (
"io"
"github.com/moby/buildkit/frontend/dockerfile/dockerignore"
)
// ReadAll reads a .dockerignore file and returns the list of file patterns
// to ignore. Note this will trim whitespace from each line as well
// as use GO's "clean" func to get the shortest/cleanest path for each.
//
// Deprecated: use github.com/moby/buildkit/frontend/dockerfile/dockerignore.ReadAll instead.
func ReadAll(reader io.Reader) ([]string, error) {
return dockerignore.ReadAll(reader)
}
-64
View File
@@ -1,64 +0,0 @@
package dockerignore // import "github.com/docker/docker/builder/dockerignore"
import (
"bufio"
"bytes"
"fmt"
"io"
"path/filepath"
"strings"
)
// ReadAll reads a .dockerignore file and returns the list of file patterns
// to ignore. Note this will trim whitespace from each line as well
// as use GO's "clean" func to get the shortest/cleanest path for each.
func ReadAll(reader io.Reader) ([]string, error) {
if reader == nil {
return nil, nil
}
scanner := bufio.NewScanner(reader)
var excludes []string
currentLine := 0
utf8bom := []byte{0xEF, 0xBB, 0xBF}
for scanner.Scan() {
scannedBytes := scanner.Bytes()
// We trim UTF8 BOM
if currentLine == 0 {
scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom)
}
pattern := string(scannedBytes)
currentLine++
// Lines starting with # (comments) are ignored before processing
if strings.HasPrefix(pattern, "#") {
continue
}
pattern = strings.TrimSpace(pattern)
if pattern == "" {
continue
}
// normalize absolute paths to paths relative to the context
// (taking care of '!' prefix)
invert := pattern[0] == '!'
if invert {
pattern = strings.TrimSpace(pattern[1:])
}
if len(pattern) > 0 {
pattern = filepath.Clean(pattern)
pattern = filepath.ToSlash(pattern)
if len(pattern) > 1 && pattern[0] == '/' {
pattern = pattern[1:]
}
}
if invert {
pattern = "!" + pattern
}
excludes = append(excludes, pattern)
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("Error reading .dockerignore: %v", err)
}
return excludes, nil
}
-653
View File
@@ -1,653 +0,0 @@
package fscache // import "github.com/docker/docker/builder/fscache"
import (
"archive/tar"
"context"
"crypto/sha256"
"encoding/json"
"hash"
"os"
"path/filepath"
"sort"
"sync"
"time"
"github.com/docker/docker/builder"
"github.com/docker/docker/builder/remotecontext"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/directory"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/tarsum"
"github.com/moby/buildkit/session/filesync"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/tonistiigi/fsutil"
fsutiltypes "github.com/tonistiigi/fsutil/types"
bolt "go.etcd.io/bbolt"
"golang.org/x/sync/singleflight"
)
const dbFile = "fscache.db"
const cacheKey = "cache"
const metaKey = "meta"
// Backend is a backing implementation for FSCache
type Backend interface {
Get(id string) (string, error)
Remove(id string) error
}
// FSCache allows syncing remote resources to cached snapshots
type FSCache struct {
opt Opt
transports map[string]Transport
mu sync.Mutex
g singleflight.Group
store *fsCacheStore
}
// Opt defines options for initializing FSCache
type Opt struct {
Backend Backend
Root string // for storing local metadata
GCPolicy GCPolicy
}
// GCPolicy defines policy for garbage collection
type GCPolicy struct {
MaxSize uint64
MaxKeepDuration time.Duration
}
// NewFSCache returns new FSCache object
func NewFSCache(opt Opt) (*FSCache, error) {
store, err := newFSCacheStore(opt)
if err != nil {
return nil, err
}
return &FSCache{
store: store,
opt: opt,
transports: make(map[string]Transport),
}, nil
}
// Transport defines a method for syncing remote data to FSCache
type Transport interface {
Copy(ctx context.Context, id RemoteIdentifier, dest string, cs filesync.CacheUpdater) error
}
// RemoteIdentifier identifies a transfer request
type RemoteIdentifier interface {
Key() string
SharedKey() string
Transport() string
}
// RegisterTransport registers a new transport method
func (fsc *FSCache) RegisterTransport(id string, transport Transport) error {
fsc.mu.Lock()
defer fsc.mu.Unlock()
if _, ok := fsc.transports[id]; ok {
return errors.Errorf("transport %v already exists", id)
}
fsc.transports[id] = transport
return nil
}
// SyncFrom returns a source based on a remote identifier
func (fsc *FSCache) SyncFrom(ctx context.Context, id RemoteIdentifier) (builder.Source, error) { // cacheOpt
trasportID := id.Transport()
fsc.mu.Lock()
transport, ok := fsc.transports[id.Transport()]
if !ok {
fsc.mu.Unlock()
return nil, errors.Errorf("invalid transport %s", trasportID)
}
logrus.Debugf("SyncFrom %s %s", id.Key(), id.SharedKey())
fsc.mu.Unlock()
sourceRef, err, _ := fsc.g.Do(id.Key(), func() (interface{}, error) {
var sourceRef *cachedSourceRef
sourceRef, err := fsc.store.Get(id.Key())
if err == nil {
return sourceRef, nil
}
// check for unused shared cache
sharedKey := id.SharedKey()
if sharedKey != "" {
r, err := fsc.store.Rebase(sharedKey, id.Key())
if err == nil {
sourceRef = r
}
}
if sourceRef == nil {
var err error
sourceRef, err = fsc.store.New(id.Key(), sharedKey)
if err != nil {
return nil, errors.Wrap(err, "failed to create remote context")
}
}
if err := syncFrom(ctx, sourceRef, transport, id); err != nil {
sourceRef.Release()
return nil, err
}
if err := sourceRef.resetSize(-1); err != nil {
return nil, err
}
return sourceRef, nil
})
if err != nil {
return nil, err
}
ref := sourceRef.(*cachedSourceRef)
if ref.src == nil { // failsafe
return nil, errors.Errorf("invalid empty pull")
}
wc := &wrappedContext{Source: ref.src, closer: func() error {
ref.Release()
return nil
}}
return wc, nil
}
// DiskUsage reports how much data is allocated by the cache
func (fsc *FSCache) DiskUsage(ctx context.Context) (int64, error) {
return fsc.store.DiskUsage(ctx)
}
// Prune allows manually cleaning up the cache
func (fsc *FSCache) Prune(ctx context.Context) (uint64, error) {
return fsc.store.Prune(ctx)
}
// Close stops the gc and closes the persistent db
func (fsc *FSCache) Close() error {
return fsc.store.Close()
}
func syncFrom(ctx context.Context, cs *cachedSourceRef, transport Transport, id RemoteIdentifier) (retErr error) {
src := cs.src
if src == nil {
src = remotecontext.NewCachableSource(cs.Dir())
}
if !cs.cached {
if err := cs.storage.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(id.Key()))
dt := b.Get([]byte(cacheKey))
if dt != nil {
if err := src.UnmarshalBinary(dt); err != nil {
return err
}
} else {
return errors.Wrap(src.Scan(), "failed to scan cache records")
}
return nil
}); err != nil {
return err
}
}
dc := &detectChanges{f: src.HandleChange}
// todo: probably send a bucket to `Copy` and let it return source
// but need to make sure that tx is safe
if err := transport.Copy(ctx, id, cs.Dir(), dc); err != nil {
return errors.Wrapf(err, "failed to copy to %s", cs.Dir())
}
if !dc.supported {
if err := src.Scan(); err != nil {
return errors.Wrap(err, "failed to scan cache records after transfer")
}
}
cs.cached = true
cs.src = src
return cs.storage.db.Update(func(tx *bolt.Tx) error {
dt, err := src.MarshalBinary()
if err != nil {
return err
}
b := tx.Bucket([]byte(id.Key()))
return b.Put([]byte(cacheKey), dt)
})
}
type fsCacheStore struct {
mu sync.Mutex
sources map[string]*cachedSource
db *bolt.DB
fs Backend
gcTimer *time.Timer
gcPolicy GCPolicy
}
// CachePolicy defines policy for keeping a resource in cache
type CachePolicy struct {
Priority int
LastUsed time.Time
}
func defaultCachePolicy() CachePolicy {
return CachePolicy{Priority: 10, LastUsed: time.Now()}
}
func newFSCacheStore(opt Opt) (*fsCacheStore, error) {
if err := os.MkdirAll(opt.Root, 0700); err != nil {
return nil, err
}
p := filepath.Join(opt.Root, dbFile)
db, err := bolt.Open(p, 0600, nil)
if err != nil {
return nil, errors.Wrap(err, "failed to open database file %s")
}
s := &fsCacheStore{db: db, sources: make(map[string]*cachedSource), fs: opt.Backend, gcPolicy: opt.GCPolicy}
db.View(func(tx *bolt.Tx) error {
return tx.ForEach(func(name []byte, b *bolt.Bucket) error {
dt := b.Get([]byte(metaKey))
if dt == nil {
return nil
}
var sm sourceMeta
if err := json.Unmarshal(dt, &sm); err != nil {
return err
}
dir, err := s.fs.Get(sm.BackendID)
if err != nil {
return err // TODO: handle gracefully
}
source := &cachedSource{
refs: make(map[*cachedSourceRef]struct{}),
id: string(name),
dir: dir,
sourceMeta: sm,
storage: s,
}
s.sources[string(name)] = source
return nil
})
})
s.gcTimer = s.startPeriodicGC(5 * time.Minute)
return s, nil
}
func (s *fsCacheStore) startPeriodicGC(interval time.Duration) *time.Timer {
var t *time.Timer
t = time.AfterFunc(interval, func() {
if err := s.GC(); err != nil {
logrus.Errorf("build gc error: %v", err)
}
t.Reset(interval)
})
return t
}
func (s *fsCacheStore) Close() error {
s.gcTimer.Stop()
return s.db.Close()
}
func (s *fsCacheStore) New(id, sharedKey string) (*cachedSourceRef, error) {
s.mu.Lock()
defer s.mu.Unlock()
var ret *cachedSource
if err := s.db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucket([]byte(id))
if err != nil {
return err
}
backendID := stringid.GenerateRandomID()
dir, err := s.fs.Get(backendID)
if err != nil {
return err
}
source := &cachedSource{
refs: make(map[*cachedSourceRef]struct{}),
id: id,
dir: dir,
sourceMeta: sourceMeta{
BackendID: backendID,
SharedKey: sharedKey,
CachePolicy: defaultCachePolicy(),
},
storage: s,
}
dt, err := json.Marshal(source.sourceMeta)
if err != nil {
return err
}
if err := b.Put([]byte(metaKey), dt); err != nil {
return err
}
s.sources[id] = source
ret = source
return nil
}); err != nil {
return nil, err
}
return ret.getRef(), nil
}
func (s *fsCacheStore) Rebase(sharedKey, newid string) (*cachedSourceRef, error) {
s.mu.Lock()
defer s.mu.Unlock()
var ret *cachedSource
for id, snap := range s.sources {
if snap.SharedKey == sharedKey && len(snap.refs) == 0 {
if err := s.db.Update(func(tx *bolt.Tx) error {
if err := tx.DeleteBucket([]byte(id)); err != nil {
return err
}
b, err := tx.CreateBucket([]byte(newid))
if err != nil {
return err
}
snap.id = newid
snap.CachePolicy = defaultCachePolicy()
dt, err := json.Marshal(snap.sourceMeta)
if err != nil {
return err
}
if err := b.Put([]byte(metaKey), dt); err != nil {
return err
}
delete(s.sources, id)
s.sources[newid] = snap
return nil
}); err != nil {
return nil, err
}
ret = snap
break
}
}
if ret == nil {
return nil, errors.Errorf("no candidate for rebase")
}
return ret.getRef(), nil
}
func (s *fsCacheStore) Get(id string) (*cachedSourceRef, error) {
s.mu.Lock()
defer s.mu.Unlock()
src, ok := s.sources[id]
if !ok {
return nil, errors.Errorf("not found")
}
return src.getRef(), nil
}
// DiskUsage reports how much data is allocated by the cache
func (s *fsCacheStore) DiskUsage(ctx context.Context) (int64, error) {
s.mu.Lock()
defer s.mu.Unlock()
var size int64
for _, snap := range s.sources {
if len(snap.refs) == 0 {
ss, err := snap.getSize(ctx)
if err != nil {
return 0, err
}
size += ss
}
}
return size, nil
}
// Prune allows manually cleaning up the cache
func (s *fsCacheStore) Prune(ctx context.Context) (uint64, error) {
s.mu.Lock()
defer s.mu.Unlock()
var size uint64
for id, snap := range s.sources {
select {
case <-ctx.Done():
logrus.Debugf("Cache prune operation cancelled, pruned size: %d", size)
// when the context is cancelled, only return current size and nil
return size, nil
default:
}
if len(snap.refs) == 0 {
ss, err := snap.getSize(ctx)
if err != nil {
return size, err
}
if err := s.delete(id); err != nil {
return size, errors.Wrapf(err, "failed to delete %s", id)
}
size += uint64(ss)
}
}
return size, nil
}
// GC runs a garbage collector on FSCache
func (s *fsCacheStore) GC() error {
s.mu.Lock()
defer s.mu.Unlock()
var size uint64
ctx := context.Background()
cutoff := time.Now().Add(-s.gcPolicy.MaxKeepDuration)
var blacklist []*cachedSource
for id, snap := range s.sources {
if len(snap.refs) == 0 {
if cutoff.After(snap.CachePolicy.LastUsed) {
if err := s.delete(id); err != nil {
return errors.Wrapf(err, "failed to delete %s", id)
}
} else {
ss, err := snap.getSize(ctx)
if err != nil {
return err
}
size += uint64(ss)
blacklist = append(blacklist, snap)
}
}
}
sort.Sort(sortableCacheSources(blacklist))
for _, snap := range blacklist {
if size <= s.gcPolicy.MaxSize {
break
}
ss, err := snap.getSize(ctx)
if err != nil {
return err
}
if err := s.delete(snap.id); err != nil {
return errors.Wrapf(err, "failed to delete %s", snap.id)
}
size -= uint64(ss)
}
return nil
}
// keep mu while calling this
func (s *fsCacheStore) delete(id string) error {
src, ok := s.sources[id]
if !ok {
return nil
}
if len(src.refs) > 0 {
return errors.Errorf("can't delete %s because it has active references", id)
}
delete(s.sources, id)
if err := s.db.Update(func(tx *bolt.Tx) error {
return tx.DeleteBucket([]byte(id))
}); err != nil {
return err
}
return s.fs.Remove(src.BackendID)
}
type sourceMeta struct {
SharedKey string
BackendID string
CachePolicy CachePolicy
Size int64
}
type cachedSource struct {
sourceMeta
refs map[*cachedSourceRef]struct{}
id string
dir string
src *remotecontext.CachableSource
storage *fsCacheStore
cached bool // keep track if cache is up to date
}
type cachedSourceRef struct {
*cachedSource
}
func (cs *cachedSource) Dir() string {
return cs.dir
}
// hold storage lock before calling
func (cs *cachedSource) getRef() *cachedSourceRef {
ref := &cachedSourceRef{cachedSource: cs}
cs.refs[ref] = struct{}{}
return ref
}
// hold storage lock before calling
func (cs *cachedSource) getSize(ctx context.Context) (int64, error) {
if cs.sourceMeta.Size < 0 {
ss, err := directory.Size(ctx, cs.dir)
if err != nil {
return 0, err
}
if err := cs.resetSize(ss); err != nil {
return 0, err
}
return ss, nil
}
return cs.sourceMeta.Size, nil
}
func (cs *cachedSource) resetSize(val int64) error {
cs.sourceMeta.Size = val
return cs.saveMeta()
}
func (cs *cachedSource) saveMeta() error {
return cs.storage.db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(cs.id))
dt, err := json.Marshal(cs.sourceMeta)
if err != nil {
return err
}
return b.Put([]byte(metaKey), dt)
})
}
func (csr *cachedSourceRef) Release() error {
csr.cachedSource.storage.mu.Lock()
defer csr.cachedSource.storage.mu.Unlock()
delete(csr.cachedSource.refs, csr)
if len(csr.cachedSource.refs) == 0 {
go csr.cachedSource.storage.GC()
}
return nil
}
type detectChanges struct {
f fsutil.ChangeFunc
supported bool
}
func (dc *detectChanges) HandleChange(kind fsutil.ChangeKind, path string, fi os.FileInfo, err error) error {
if dc == nil {
return nil
}
return dc.f(kind, path, fi, err)
}
func (dc *detectChanges) MarkSupported(v bool) {
if dc == nil {
return
}
dc.supported = v
}
func (dc *detectChanges) ContentHasher() fsutil.ContentHasher {
return newTarsumHash
}
type wrappedContext struct {
builder.Source
closer func() error
}
func (wc *wrappedContext) Close() error {
if err := wc.Source.Close(); err != nil {
return err
}
return wc.closer()
}
type sortableCacheSources []*cachedSource
// Len is the number of elements in the collection.
func (s sortableCacheSources) Len() int {
return len(s)
}
// Less reports whether the element with
// index i should sort before the element with index j.
func (s sortableCacheSources) Less(i, j int) bool {
return s[i].CachePolicy.LastUsed.Before(s[j].CachePolicy.LastUsed)
}
// Swap swaps the elements with indexes i and j.
func (s sortableCacheSources) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func newTarsumHash(stat *fsutiltypes.Stat) (hash.Hash, error) {
fi := &fsutil.StatInfo{Stat: stat}
p := stat.Path
if fi.IsDir() {
p += string(os.PathSeparator)
}
h, err := archive.FileInfoHeader(p, fi, stat.Linkname)
if err != nil {
return nil, err
}
h.Name = p
h.Uid = int(stat.Uid)
h.Gid = int(stat.Gid)
h.Linkname = stat.Linkname
if stat.Xattrs != nil {
h.Xattrs = make(map[string]string)
for k, v := range stat.Xattrs {
h.Xattrs[k] = string(v)
}
}
tsh := &tarsumHash{h: h, Hash: sha256.New()}
tsh.Reset()
return tsh, nil
}
// Reset resets the Hash to its initial state.
func (tsh *tarsumHash) Reset() {
tsh.Hash.Reset()
tarsum.WriteV1Header(tsh.h, tsh.Hash)
}
type tarsumHash struct {
hash.Hash
h *tar.Header
}
-28
View File
@@ -1,28 +0,0 @@
package fscache // import "github.com/docker/docker/builder/fscache"
import (
"os"
"path/filepath"
"github.com/pkg/errors"
)
// NewNaiveCacheBackend is a basic backend implementation for fscache
func NewNaiveCacheBackend(root string) Backend {
return &naiveCacheBackend{root: root}
}
type naiveCacheBackend struct {
root string
}
func (tcb *naiveCacheBackend) Get(id string) (string, error) {
d := filepath.Join(tcb.root, id)
if err := os.MkdirAll(d, 0700); err != nil {
return "", errors.Wrapf(err, "failed to create tmp dir for %s", d)
}
return d, nil
}
func (tcb *naiveCacheBackend) Remove(id string) error {
return errors.WithStack(os.RemoveAll(filepath.Join(tcb.root, id)))
}
+4 -9
View File
@@ -11,10 +11,10 @@ import (
"github.com/containerd/continuity/driver"
"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/builder"
"github.com/docker/docker/builder/dockerignore"
"github.com/docker/docker/errdefs"
"github.com/docker/docker/pkg/fileutils"
"github.com/docker/docker/pkg/urlutil"
"github.com/moby/buildkit/frontend/dockerfile/dockerignore"
"github.com/moby/buildkit/frontend/dockerfile/parser"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -33,12 +33,7 @@ func Detect(config backend.BuildConfig) (remote builder.Source, dockerfile *pars
case remoteURL == "":
remote, dockerfile, err = newArchiveRemote(config.Source, dockerfilePath)
case remoteURL == ClientSessionRemote:
res, err := parser.Parse(config.Source)
if err != nil {
return nil, nil, errdefs.InvalidParameter(err)
}
return nil, res, nil
return nil, nil, errdefs.InvalidParameter(errors.New("experimental session with v1 builder is no longer supported, use builder version v2 (BuildKit) instead"))
case urlutil.IsGitURL(remoteURL):
remote, dockerfile, err = newGitRemote(remoteURL, dockerfilePath)
case urlutil.IsURL(remoteURL):
@@ -62,7 +57,7 @@ func newArchiveRemote(rc io.ReadCloser, dockerfilePath string) (builder.Source,
func withDockerfileFromContext(c modifiableContext, dockerfilePath string) (builder.Source, *parser.Result, error) {
df, err := openAt(c, dockerfilePath)
if err != nil {
if os.IsNotExist(err) {
if errors.Is(err, os.ErrNotExist) {
if dockerfilePath == builder.DefaultDockerfileName {
lowercase := strings.ToLower(dockerfilePath)
if _, err := StatAt(c, lowercase); err == nil {
@@ -185,7 +180,7 @@ func FullPath(remote builder.Source, path string) (string, error) {
if runtime.GOOS == "windows" {
return "", fmt.Errorf("failed to resolve scoped path %s (%s): %s. Possible cause is a forbidden path outside the build context", path, fullPath, err)
}
return "", fmt.Errorf("Forbidden path outside the build context: %s (%s)", path, fullPath) // backwards compat with old error
return "", fmt.Errorf("forbidden path outside the build context: %s (%s)", path, fullPath) // backwards compat with old error
}
return fullPath, nil
}
+31 -8
View File
@@ -5,13 +5,12 @@ import (
"net/http"
"net/url"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/docker/docker/pkg/symlink"
"github.com/docker/docker/pkg/urlutil"
"github.com/moby/sys/symlink"
"github.com/pkg/errors"
exec "golang.org/x/sys/execabs"
)
type gitRepo struct {
@@ -102,6 +101,11 @@ func parseRemoteURL(remoteURL string) (gitRepo, error) {
u.Fragment = ""
repo.remote = u.String()
}
if strings.HasPrefix(repo.ref, "-") {
return gitRepo{}, errors.Errorf("invalid refspec: %s", repo.ref)
}
return repo, nil
}
@@ -124,22 +128,22 @@ func fetchArgs(remoteURL string, ref string) []string {
args = append(args, "--depth", "1")
}
return append(args, "origin", ref)
return append(args, "origin", "--", ref)
}
// Check if a given git URL supports a shallow git clone,
// i.e. it is a non-HTTP server or a smart HTTP server.
func supportsShallowClone(remoteURL string) bool {
if urlutil.IsURL(remoteURL) {
if scheme := getScheme(remoteURL); scheme == "http" || scheme == "https" {
// Check if the HTTP server is smart
// Smart servers must correctly respond to a query for the git-upload-pack service
serviceURL := remoteURL + "/info/refs?service=git-upload-pack"
// Try a HEAD request and fallback to a Get request on error
res, err := http.Head(serviceURL)
res, err := http.Head(serviceURL) // #nosec G107
if err != nil || res.StatusCode != http.StatusOK {
res, err = http.Get(serviceURL)
res, err = http.Get(serviceURL) // #nosec G107
if err == nil {
res.Body.Close()
}
@@ -200,5 +204,24 @@ func git(args ...string) ([]byte, error) {
// isGitTransport returns true if the provided str is a git transport by inspecting
// the prefix of the string for known protocols used in git.
func isGitTransport(str string) bool {
return urlutil.IsURL(str) || strings.HasPrefix(str, "git://") || strings.HasPrefix(str, "git@")
if strings.HasPrefix(str, "git@") {
return true
}
switch getScheme(str) {
case "git", "http", "https", "ssh":
return true
}
return false
}
// getScheme returns addresses' scheme in lowercase, or an empty
// string in case address is an invalid URL.
func getScheme(address string) string {
u, err := url.Parse(address)
if err != nil {
return ""
}
return u.Scheme
}
+1
View File
@@ -45,6 +45,7 @@ func downloadRemote(remoteURL string) (string, io.ReadCloser, error) {
// GetWithStatusError does an http.Get() and returns an error if the
// status code is 4xx or 5xx.
func GetWithStatusError(address string) (resp *http.Response, err error) {
// #nosec G107
if resp, err = http.Get(address); err != nil {
if uerr, ok := err.(*url.Error); ok {
if derr, ok := uerr.Err.(*net.DNSError); ok && !derr.IsTimeout {
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"github.com/docker/docker/pkg/containerfs"
iradix "github.com/hashicorp/go-immutable-radix"
"github.com/opencontainers/go-digest"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/tonistiigi/fsutil"
)
+2 -6
View File
@@ -11,10 +11,6 @@ func (cli *Client) BuildCancel(ctx context.Context, id string) error {
query.Set("id", id)
serverResp, err := cli.post(ctx, "/build/cancel", query, nil, nil)
if err != nil {
return err
}
defer ensureReaderClosed(serverResp)
return nil
ensureReaderClosed(serverResp)
return err
}
+1 -1
View File
@@ -31,11 +31,11 @@ func (cli *Client) BuildCachePrune(ctx context.Context, opts types.BuildCachePru
query.Set("filters", filters)
serverResp, err := cli.post(ctx, "/build/prune", query, nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return nil, err
}
defer ensureReaderClosed(serverResp)
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
return nil, fmt.Errorf("Error retrieving disk usage: %v", err)
+1 -1
View File
@@ -18,11 +18,11 @@ func (cli *Client) CheckpointList(ctx context.Context, container string, options
}
resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return checkpoints, wrapResponseError(err, resp, "container", container)
}
err = json.NewDecoder(resp.body).Decode(&checkpoints)
ensureReaderClosed(resp)
return checkpoints, err
}
+43 -12
View File
@@ -2,13 +2,13 @@
Package client is a Go client for the Docker Engine API.
For more information about the Engine API, see the documentation:
https://docs.docker.com/engine/reference/api/
https://docs.docker.com/engine/api/
Usage
You use the library by creating a client object and calling methods on it. The
client can be created either from environment variables with NewEnvClient, or
configured manually with NewClient.
client can be created either from environment variables with NewClientWithOpts(client.FromEnv),
or configured manually with NewClient().
For example, to list running containers (the equivalent of "docker ps"):
@@ -81,6 +81,15 @@ type Client struct {
customHTTPHeaders map[string]string
// manualOverride is set to true when the version was set by users.
manualOverride bool
// negotiateVersion indicates if the client should automatically negotiate
// the API version to use when making requests. API version negotiation is
// performed on the first request, after which negotiated is set to "true"
// so that subsequent requests do not re-negotiate.
negotiateVersion bool
// negotiated indicates that API version negotiation took place
negotiated bool
}
// CheckRedirect specifies the policy for dealing with redirect responses:
@@ -107,7 +116,7 @@ func CheckRedirect(req *http.Request, via []*http.Request) error {
// It won't send any version information if the version number is empty. It is
// highly recommended that you set a version or your client may break if the
// server is upgraded.
func NewClientWithOpts(ops ...func(*Client) error) (*Client, error) {
func NewClientWithOpts(ops ...Opt) (*Client, error) {
client, err := defaultHTTPClient(DefaultDockerHost)
if err != nil {
return nil, err
@@ -169,8 +178,11 @@ func (cli *Client) Close() error {
// getAPIPath returns the versioned request path to call the api.
// It appends the query parameters to the path if they are not empty.
func (cli *Client) getAPIPath(p string, query url.Values) string {
func (cli *Client) getAPIPath(ctx context.Context, p string, query url.Values) string {
var apiPath string
if cli.negotiateVersion && !cli.negotiated {
cli.NegotiateAPIVersion(ctx)
}
if cli.version != "" {
v := strings.TrimPrefix(cli.version, "v")
apiPath = path.Join(cli.basePath, "/v"+v, p)
@@ -186,19 +198,31 @@ func (cli *Client) ClientVersion() string {
}
// NegotiateAPIVersion queries the API and updates the version to match the
// API version. Any errors are silently ignored.
// API version. Any errors are silently ignored. If a manual override is in place,
// either through the `DOCKER_API_VERSION` environment variable, or if the client
// was initialized with a fixed version (`opts.WithVersion(xx)`), no negotiation
// will be performed.
func (cli *Client) NegotiateAPIVersion(ctx context.Context) {
ping, _ := cli.Ping(ctx)
cli.NegotiateAPIVersionPing(ping)
if !cli.manualOverride {
ping, _ := cli.Ping(ctx)
cli.negotiateAPIVersionPing(ping)
}
}
// NegotiateAPIVersionPing updates the client version to match the Ping.APIVersion
// if the ping version is less than the default version.
// if the ping version is less than the default version. If a manual override is
// in place, either through the `DOCKER_API_VERSION` environment variable, or if
// the client was initialized with a fixed version (`opts.WithVersion(xx)`), no
// negotiation is performed.
func (cli *Client) NegotiateAPIVersionPing(p types.Ping) {
if cli.manualOverride {
return
if !cli.manualOverride {
cli.negotiateAPIVersionPing(p)
}
}
// negotiateAPIVersionPing queries the API and updates the version to match the
// API version. Any errors are silently ignored.
func (cli *Client) negotiateAPIVersionPing(p types.Ping) {
// try the latest version before versioning headers existed
if p.APIVersion == "" {
p.APIVersion = "1.24"
@@ -213,6 +237,12 @@ func (cli *Client) NegotiateAPIVersionPing(p types.Ping) {
if versions.LessThan(p.APIVersion, cli.version) {
cli.version = p.APIVersion
}
// Store the results, so that automatic API version negotiation (if enabled)
// won't be performed on the next request.
if cli.negotiateVersion {
cli.negotiated = true
}
}
// DaemonHost returns the host address used by the client
@@ -222,7 +252,8 @@ func (cli *Client) DaemonHost() string {
// HTTPClient returns a copy of the HTTP client bound to the server
func (cli *Client) HTTPClient() *http.Client {
return &*cli.client
c := *cli.client
return &c
}
// ParseHostURL parses a url string, validates the string is a host url, and
+1 -1
View File
@@ -1,4 +1,4 @@
// +build linux freebsd openbsd darwin
// +build linux freebsd openbsd netbsd darwin solaris illumos dragonfly
package client // import "github.com/docker/docker/client"
+1 -1
View File
@@ -15,11 +15,11 @@ func (cli *Client) ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (t
return response, err
}
resp, err := cli.post(ctx, "/configs/create", nil, config, nil)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
}
err = json.NewDecoder(resp.body).Decode(&response)
ensureReaderClosed(resp)
return response, err
}
+1 -1
View File
@@ -18,10 +18,10 @@ func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.C
return swarm.Config{}, nil, err
}
resp, err := cli.get(ctx, "/configs/"+id, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return swarm.Config{}, nil, wrapResponseError(err, resp, "config", id)
}
defer ensureReaderClosed(resp)
body, err := ioutil.ReadAll(resp.body)
if err != nil {
+1 -1
View File
@@ -27,12 +27,12 @@ func (cli *Client) ConfigList(ctx context.Context, options types.ConfigListOptio
}
resp, err := cli.get(ctx, "/configs", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
}
var configs []swarm.Config
err = json.NewDecoder(resp.body).Decode(&configs)
ensureReaderClosed(resp)
return configs, err
}
+1 -1
View File
@@ -8,6 +8,6 @@ func (cli *Client) ConfigRemove(ctx context.Context, id string) error {
return err
}
resp, err := cli.delete(ctx, "/configs/"+id, nil, nil)
ensureReaderClosed(resp)
defer ensureReaderClosed(resp)
return wrapResponseError(err, resp, "config", id)
}
+1 -1
View File
@@ -45,11 +45,11 @@ func (cli *Client) ContainerCommit(ctx context.Context, container string, option
var response types.IDResponse
resp, err := cli.post(ctx, "/commit", query, options.Config, nil)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
}
err = json.NewDecoder(resp.body).Decode(&response)
ensureReaderClosed(resp)
return response, err
}
+2 -2
View File
@@ -21,10 +21,10 @@ func (cli *Client) ContainerStatPath(ctx context.Context, containerID, path stri
urlStr := "/containers/" + containerID + "/archive"
response, err := cli.head(ctx, urlStr, query, nil)
defer ensureReaderClosed(response)
if err != nil {
return types.ContainerPathStat{}, wrapResponseError(err, response, "container:path", containerID+":"+path)
}
defer ensureReaderClosed(response)
return getContainerPathStatFromHeader(response.header)
}
@@ -45,10 +45,10 @@ func (cli *Client) CopyToContainer(ctx context.Context, containerID, dstPath str
apiPath := "/containers/" + containerID + "/archive"
response, err := cli.putRaw(ctx, apiPath, query, content, nil)
defer ensureReaderClosed(response)
if err != nil {
return wrapResponseError(err, response, "container:path", containerID+":"+dstPath)
}
defer ensureReaderClosed(response)
// TODO this code converts non-error status-codes (e.g., "204 No Content") into an error; verify if this is the desired behavior
if response.statusCode != http.StatusOK {
+13 -2
View File
@@ -5,20 +5,23 @@ import (
"encoding/json"
"net/url"
"github.com/containerd/containerd/platforms"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/versions"
specs "github.com/opencontainers/image-spec/specs-go/v1"
)
type configWrapper struct {
*container.Config
HostConfig *container.HostConfig
NetworkingConfig *network.NetworkingConfig
Platform *specs.Platform
}
// ContainerCreate creates a new container based in the given configuration.
// It can be associated with a name, but it's not mandatory.
func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (container.ContainerCreateCreatedBody, error) {
func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *specs.Platform, containerName string) (container.ContainerCreateCreatedBody, error) {
var response container.ContainerCreateCreatedBody
if err := cli.NewVersionError("1.25", "stop timeout"); config != nil && config.StopTimeout != nil && err != nil {
@@ -30,7 +33,15 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
hostConfig.AutoRemove = false
}
if err := cli.NewVersionError("1.41", "specify container image platform"); platform != nil && err != nil {
return response, err
}
query := url.Values{}
if platform != nil {
query.Set("platform", platforms.Format(*platform))
}
if containerName != "" {
query.Set("name", containerName)
}
@@ -42,11 +53,11 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
}
serverResp, err := cli.post(ctx, "/containers/create", query, body, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return response, err
}
err = json.NewDecoder(serverResp.body).Decode(&response)
ensureReaderClosed(serverResp)
return response, err
}
+1 -1
View File
@@ -13,11 +13,11 @@ func (cli *Client) ContainerDiff(ctx context.Context, containerID string) ([]con
var changes []container.ContainerChangeResponseItem
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/changes", url.Values{}, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return changes, err
}
err = json.NewDecoder(serverResp.body).Decode(&changes)
ensureReaderClosed(serverResp)
return changes, err
}
+1 -1
View File
@@ -16,11 +16,11 @@ func (cli *Client) ContainerExecCreate(ctx context.Context, container string, co
}
resp, err := cli.post(ctx, "/containers/"+container+"/exec", nil, config, nil)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
}
err = json.NewDecoder(resp.body).Decode(&response)
ensureReaderClosed(resp)
return response, err
}
+2 -2
View File
@@ -16,10 +16,10 @@ func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (ty
return types.ContainerJSON{}, objectNotFoundError{object: "container", id: containerID}
}
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return types.ContainerJSON{}, wrapResponseError(err, serverResp, "container", containerID)
}
defer ensureReaderClosed(serverResp)
var response types.ContainerJSON
err = json.NewDecoder(serverResp.body).Decode(&response)
@@ -36,10 +36,10 @@ func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID stri
query.Set("size", "1")
}
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", query, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return types.ContainerJSON{}, nil, wrapResponseError(err, serverResp, "container", containerID)
}
defer ensureReaderClosed(serverResp)
body, err := ioutil.ReadAll(serverResp.body)
if err != nil {
+2 -1
View File
@@ -35,6 +35,7 @@ func (cli *Client) ContainerList(ctx context.Context, options types.ContainerLis
}
if options.Filters.Len() > 0 {
//nolint:staticcheck // ignore SA1019 for old code
filterJSON, err := filters.ToParamWithVersion(cli.version, options.Filters)
if err != nil {
@@ -45,12 +46,12 @@ func (cli *Client) ContainerList(ctx context.Context, options types.ContainerLis
}
resp, err := cli.get(ctx, "/containers/json", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
}
var containers []types.Container
err = json.NewDecoder(resp.body).Decode(&containers)
ensureReaderClosed(resp)
return containers, err
}
+1 -1
View File
@@ -23,10 +23,10 @@ func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Arg
}
serverResp, err := cli.post(ctx, "/containers/prune", query, nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return report, err
}
defer ensureReaderClosed(serverResp)
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
return report, fmt.Errorf("Error retrieving disk usage: %v", err)
+1 -1
View File
@@ -22,6 +22,6 @@ func (cli *Client) ContainerRemove(ctx context.Context, containerID string, opti
}
resp, err := cli.delete(ctx, "/containers/"+containerID, query, nil)
ensureReaderClosed(resp)
defer ensureReaderClosed(resp)
return wrapResponseError(err, resp, "container", containerID)
}
+16
View File
@@ -24,3 +24,19 @@ func (cli *Client) ContainerStats(ctx context.Context, containerID string, strea
osType := getDockerOS(resp.header.Get("Server"))
return types.ContainerStats{Body: resp.body, OSType: osType}, err
}
// ContainerStatsOneShot gets a single stat entry from a container.
// It differs from `ContainerStats` in that the API should not wait to prime the stats
func (cli *Client) ContainerStatsOneShot(ctx context.Context, containerID string) (types.ContainerStats, error) {
query := url.Values{}
query.Set("stream", "0")
query.Set("one-shot", "1")
resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil)
if err != nil {
return types.ContainerStats{}, err
}
osType := getDockerOS(resp.header.Get("Server"))
return types.ContainerStats{Body: resp.body, OSType: osType}, err
}
+1 -1
View File
@@ -18,11 +18,11 @@ func (cli *Client) ContainerTop(ctx context.Context, containerID string, argumen
}
resp, err := cli.get(ctx, "/containers/"+containerID+"/top", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
}
err = json.NewDecoder(resp.body).Decode(&response)
ensureReaderClosed(resp)
return response, err
}
+1 -2
View File
@@ -11,12 +11,11 @@ import (
func (cli *Client) ContainerUpdate(ctx context.Context, containerID string, updateConfig container.UpdateConfig) (container.ContainerUpdateOKBody, error) {
var response container.ContainerUpdateOKBody
serverResp, err := cli.post(ctx, "/containers/"+containerID+"/update", nil, updateConfig, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return response, err
}
err = json.NewDecoder(serverResp.body).Decode(&response)
ensureReaderClosed(serverResp)
return response, err
}
+1 -1
View File
@@ -13,10 +13,10 @@ func (cli *Client) DiskUsage(ctx context.Context) (types.DiskUsage, error) {
var du types.DiskUsage
serverResp, err := cli.get(ctx, "/system/df", nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return du, err
}
defer ensureReaderClosed(serverResp)
if err := json.NewDecoder(serverResp.body).Decode(&du); err != nil {
return du, fmt.Errorf("Error retrieving disk usage: %v", err)
+1 -1
View File
@@ -28,11 +28,11 @@ func (cli *Client) DistributionInspect(ctx context.Context, image, encodedRegist
}
resp, err := cli.get(ctx, "/distribution/"+image+"/json", url.Values{}, headers)
defer ensureReaderClosed(resp)
if err != nil {
return distributionInspect, err
}
err = json.NewDecoder(resp.body).Decode(&distributionInspect)
ensureReaderClosed(resp)
return distributionInspect, err
}
+4 -4
View File
@@ -24,8 +24,7 @@ func (err errConnectionFailed) Error() string {
// IsErrConnectionFailed returns true if the error is caused by connection failed.
func IsErrConnectionFailed(err error) bool {
_, ok := errors.Cause(err).(errConnectionFailed)
return ok
return errors.As(err, &errConnectionFailed{})
}
// ErrorConnectionFailed returns an error with host in the error message when connection to docker daemon failed.
@@ -42,8 +41,9 @@ type notFound interface {
// IsErrNotFound returns true if the error is a NotFound error, which is returned
// by the API when some object is not found.
func IsErrNotFound(err error) bool {
if _, ok := err.(notFound); ok {
return ok
var e notFound
if errors.As(err, &e) {
return true
}
return errdefs.IsNotFound(err)
}
+1
View File
@@ -90,6 +90,7 @@ func buildEventsQueryParams(cliVersion string, options types.EventsOptions) (url
}
if options.Filters.Len() > 0 {
//nolint:staticcheck // ignore SA1019 for old code
filterJSON, err := filters.ToParamWithVersion(cliVersion, options.Filters)
if err != nil {
return nil, err
+15 -2
View File
@@ -23,8 +23,8 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu
return types.HijackedResponse{}, err
}
apiPath := cli.getAPIPath(path, query)
req, err := http.NewRequest("POST", apiPath, bodyEncoded)
apiPath := cli.getAPIPath(ctx, path, query)
req, err := http.NewRequest(http.MethodPost, apiPath, bodyEncoded)
if err != nil {
return types.HijackedResponse{}, err
}
@@ -38,6 +38,17 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu
return types.HijackedResponse{Conn: conn, Reader: bufio.NewReader(conn)}, err
}
// DialHijack returns a hijacked connection with negotiated protocol proto.
func (cli *Client) DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error) {
req, err := http.NewRequest(http.MethodPost, url, nil)
if err != nil {
return nil, err
}
req = cli.addHeaders(req, meta)
return cli.setupHijackConn(ctx, req, proto)
}
// fallbackDial is used when WithDialer() was not called.
// See cli.Dialer().
func fallbackDial(proto, addr string, tlsConfig *tls.Config) (net.Conn, error) {
@@ -76,6 +87,8 @@ func (cli *Client) setupHijackConn(ctx context.Context, req *http.Request, proto
// Server hijacks the connection, error 'connection closed' expected
resp, err := clientconn.Do(req)
//nolint:staticcheck // ignore SA1019 for connecting to old (pre go1.8) daemons
if err != httputil.ErrPersistEOF {
if err != nil {
return nil, err
+1 -1
View File
@@ -12,11 +12,11 @@ import (
func (cli *Client) ImageHistory(ctx context.Context, imageID string) ([]image.HistoryResponseItem, error) {
var history []image.HistoryResponseItem
serverResp, err := cli.get(ctx, "/images/"+imageID+"/history", url.Values{}, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return history, err
}
err = json.NewDecoder(serverResp.body).Decode(&history)
ensureReaderClosed(serverResp)
return history, err
}
+1 -1
View File
@@ -14,7 +14,7 @@ import (
// It returns the JSON content in the response body.
func (cli *Client) ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) {
if ref != "" {
//Check if the given image name can be resolved
// Check if the given image name can be resolved
if _, err := reference.ParseNormalizedNamed(ref); err != nil {
return nil, err
}
+1 -1
View File
@@ -15,10 +15,10 @@ func (cli *Client) ImageInspectWithRaw(ctx context.Context, imageID string) (typ
return types.ImageInspect{}, nil, objectNotFoundError{object: "image", id: imageID}
}
serverResp, err := cli.get(ctx, "/images/"+imageID+"/json", nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return types.ImageInspect{}, nil, wrapResponseError(err, serverResp, "image", imageID)
}
defer ensureReaderClosed(serverResp)
body, err := ioutil.ReadAll(serverResp.body)
if err != nil {
+2 -1
View File
@@ -24,6 +24,7 @@ func (cli *Client) ImageList(ctx context.Context, options types.ImageListOptions
}
}
if optionFilters.Len() > 0 {
//nolint:staticcheck // ignore SA1019 for old code
filterJSON, err := filters.ToParamWithVersion(cli.version, optionFilters)
if err != nil {
return images, err
@@ -35,11 +36,11 @@ func (cli *Client) ImageList(ctx context.Context, options types.ImageListOptions
}
serverResp, err := cli.get(ctx, "/images/json", query, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return images, err
}
err = json.NewDecoder(serverResp.body).Decode(&images)
ensureReaderClosed(serverResp)
return images, err
}
+1 -1
View File
@@ -23,10 +23,10 @@ func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (
}
serverResp, err := cli.post(ctx, "/images/prune", query, nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return report, err
}
defer ensureReaderClosed(serverResp)
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
return report, fmt.Errorf("Error retrieving disk usage: %v", err)
+6 -7
View File
@@ -25,15 +25,14 @@ func (cli *Client) ImagePush(ctx context.Context, image string, options types.Im
return nil, errors.New("cannot push a digest reference")
}
tag := ""
name := reference.FamiliarName(ref)
if nameTaggedRef, isNamedTagged := ref.(reference.NamedTagged); isNamedTagged {
tag = nameTaggedRef.Tag()
}
query := url.Values{}
query.Set("tag", tag)
if !options.All {
ref = reference.TagNameOnly(ref)
if tagged, ok := ref.(reference.Tagged); ok {
query.Set("tag", tagged.Tag())
}
}
resp, err := cli.tryImagePush(ctx, name, query, options.RegistryAuth)
if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
+1 -1
View File
@@ -21,11 +21,11 @@ func (cli *Client) ImageRemove(ctx context.Context, imageID string, options type
var dels []types.ImageDeleteResponseItem
resp, err := cli.delete(ctx, "/images/"+imageID, query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return dels, wrapResponseError(err, resp, "image", imageID)
}
err = json.NewDecoder(resp.body).Decode(&dels)
ensureReaderClosed(resp)
return dels, err
}
+1 -1
View File
@@ -29,6 +29,7 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options types.I
}
resp, err := cli.tryImageSearch(ctx, query, options.RegistryAuth)
defer ensureReaderClosed(resp)
if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
newAuthHeader, privilegeErr := options.PrivilegeFunc()
if privilegeErr != nil {
@@ -41,7 +42,6 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options types.I
}
err = json.NewDecoder(resp.body).Decode(&results)
ensureReaderClosed(resp)
return results, err
}
+1 -1
View File
@@ -13,10 +13,10 @@ import (
func (cli *Client) Info(ctx context.Context) (types.Info, error) {
var info types.Info
serverResp, err := cli.get(ctx, "/info", url.Values{}, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return info, err
}
defer ensureReaderClosed(serverResp)
if err := json.NewDecoder(serverResp.body).Decode(&info); err != nil {
return info, fmt.Errorf("Error reading remote info: %v", err)
+4 -2
View File
@@ -16,6 +16,7 @@ import (
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/api/types/swarm"
volumetypes "github.com/docker/docker/api/types/volume"
specs "github.com/opencontainers/image-spec/specs-go/v1"
)
// CommonAPIClient is the common methods between stable and experimental versions of APIClient.
@@ -38,7 +39,7 @@ type CommonAPIClient interface {
ServerVersion(ctx context.Context) (types.Version, error)
NegotiateAPIVersion(ctx context.Context)
NegotiateAPIVersionPing(types.Ping)
DialSession(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error)
DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error)
Dialer() func(context.Context) (net.Conn, error)
Close() error
}
@@ -47,7 +48,7 @@ type CommonAPIClient interface {
type ContainerAPIClient interface {
ContainerAttach(ctx context.Context, container string, options types.ContainerAttachOptions) (types.HijackedResponse, error)
ContainerCommit(ctx context.Context, container string, options types.ContainerCommitOptions) (types.IDResponse, error)
ContainerCreate(ctx context.Context, config *containertypes.Config, hostConfig *containertypes.HostConfig, networkingConfig *networktypes.NetworkingConfig, containerName string) (containertypes.ContainerCreateCreatedBody, error)
ContainerCreate(ctx context.Context, config *containertypes.Config, hostConfig *containertypes.HostConfig, networkingConfig *networktypes.NetworkingConfig, platform *specs.Platform, containerName string) (containertypes.ContainerCreateCreatedBody, error)
ContainerDiff(ctx context.Context, container string) ([]containertypes.ContainerChangeResponseItem, error)
ContainerExecAttach(ctx context.Context, execID string, config types.ExecStartCheck) (types.HijackedResponse, error)
ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error)
@@ -67,6 +68,7 @@ type ContainerAPIClient interface {
ContainerRestart(ctx context.Context, container string, timeout *time.Duration) error
ContainerStatPath(ctx context.Context, container, path string) (types.ContainerPathStat, error)
ContainerStats(ctx context.Context, container string, stream bool) (types.ContainerStats, error)
ContainerStatsOneShot(ctx context.Context, container string) (types.ContainerStats, error)
ContainerStart(ctx context.Context, container string, options types.ContainerStartOptions) error
ContainerStop(ctx context.Context, container string, timeout *time.Duration) error
ContainerTop(ctx context.Context, container string, arguments []string) (containertypes.ContainerTopOKBody, error)
+1 -1
View File
@@ -13,6 +13,7 @@ import (
// It returns unauthorizedError when the authentication fails.
func (cli *Client) RegistryLogin(ctx context.Context, auth types.AuthConfig) (registry.AuthenticateOKBody, error) {
resp, err := cli.post(ctx, "/auth", url.Values{}, auth, nil)
defer ensureReaderClosed(resp)
if err != nil {
return registry.AuthenticateOKBody{}, err
@@ -20,6 +21,5 @@ func (cli *Client) RegistryLogin(ctx context.Context, auth types.AuthConfig) (re
var response registry.AuthenticateOKBody
err = json.NewDecoder(resp.body).Decode(&response)
ensureReaderClosed(resp)
return response, err
}
+2 -2
View File
@@ -15,11 +15,11 @@ func (cli *Client) NetworkCreate(ctx context.Context, name string, options types
}
var response types.NetworkCreateResponse
serverResp, err := cli.post(ctx, "/networks/create", nil, networkCreateRequest, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return response, err
}
json.NewDecoder(serverResp.body).Decode(&response)
ensureReaderClosed(serverResp)
err = json.NewDecoder(serverResp.body).Decode(&response)
return response, err
}
+1 -1
View File
@@ -34,10 +34,10 @@ func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string,
query.Set("scope", options.Scope)
}
resp, err = cli.get(ctx, "/networks/"+networkID, query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return networkResource, nil, wrapResponseError(err, resp, "network", networkID)
}
defer ensureReaderClosed(resp)
body, err := ioutil.ReadAll(resp.body)
if err != nil {
+2 -1
View File
@@ -13,6 +13,7 @@ import (
func (cli *Client) NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error) {
query := url.Values{}
if options.Filters.Len() > 0 {
//nolint:staticcheck // ignore SA1019 for old code
filterJSON, err := filters.ToParamWithVersion(cli.version, options.Filters)
if err != nil {
return nil, err
@@ -22,10 +23,10 @@ func (cli *Client) NetworkList(ctx context.Context, options types.NetworkListOpt
}
var networkResources []types.NetworkResource
resp, err := cli.get(ctx, "/networks", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return networkResources, err
}
err = json.NewDecoder(resp.body).Decode(&networkResources)
ensureReaderClosed(resp)
return networkResources, err
}
+1 -1
View File
@@ -23,10 +23,10 @@ func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args)
}
serverResp, err := cli.post(ctx, "/networks/prune", query, nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return report, err
}
defer ensureReaderClosed(serverResp)
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
return report, fmt.Errorf("Error retrieving network prune report: %v", err)
+1 -1
View File
@@ -5,6 +5,6 @@ import "context"
// NetworkRemove removes an existent network from the docker host.
func (cli *Client) NetworkRemove(ctx context.Context, networkID string) error {
resp, err := cli.delete(ctx, "/networks/"+networkID, nil, nil)
ensureReaderClosed(resp)
defer ensureReaderClosed(resp)
return wrapResponseError(err, resp, "network", networkID)
}
+1 -1
View File
@@ -15,10 +15,10 @@ func (cli *Client) NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm
return swarm.Node{}, nil, objectNotFoundError{object: "node", id: nodeID}
}
serverResp, err := cli.get(ctx, "/nodes/"+nodeID, nil, nil)
defer ensureReaderClosed(serverResp)
if err != nil {
return swarm.Node{}, nil, wrapResponseError(err, serverResp, "node", nodeID)
}
defer ensureReaderClosed(serverResp)
body, err := ioutil.ReadAll(serverResp.body)
if err != nil {
+1 -1
View File
@@ -25,12 +25,12 @@ func (cli *Client) NodeList(ctx context.Context, options types.NodeListOptions)
}
resp, err := cli.get(ctx, "/nodes", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
}
var nodes []swarm.Node
err = json.NewDecoder(resp.body).Decode(&nodes)
ensureReaderClosed(resp)
return nodes, err
}
+1 -1
View File
@@ -15,6 +15,6 @@ func (cli *Client) NodeRemove(ctx context.Context, nodeID string, options types.
}
resp, err := cli.delete(ctx, "/nodes/"+nodeID, query, nil)
ensureReaderClosed(resp)
defer ensureReaderClosed(resp)
return wrapResponseError(err, resp, "node", nodeID)
}
+40 -12
View File
@@ -6,12 +6,16 @@ import (
"net/http"
"os"
"path/filepath"
"time"
"github.com/docker/go-connections/sockets"
"github.com/docker/go-connections/tlsconfig"
"github.com/pkg/errors"
)
// Opt is a configuration option to initialize a client
type Opt func(*Client) error
// FromEnv configures the client with values from environment variables.
//
// Supported environment variables:
@@ -45,8 +49,9 @@ func FromEnv(c *Client) error {
}
if version := os.Getenv("DOCKER_API_VERSION"); version != "" {
c.version = version
c.manualOverride = true
if err := WithVersion(version)(c); err != nil {
return err
}
}
return nil
}
@@ -54,13 +59,13 @@ func FromEnv(c *Client) error {
// WithDialer applies the dialer.DialContext to the client transport. This can be
// used to set the Timeout and KeepAlive settings of the client.
// Deprecated: use WithDialContext
func WithDialer(dialer *net.Dialer) func(*Client) error {
func WithDialer(dialer *net.Dialer) Opt {
return WithDialContext(dialer.DialContext)
}
// WithDialContext applies the dialer to the client transport. This can be
// used to set the Timeout and KeepAlive settings of the client.
func WithDialContext(dialContext func(ctx context.Context, network, addr string) (net.Conn, error)) func(*Client) error {
func WithDialContext(dialContext func(ctx context.Context, network, addr string) (net.Conn, error)) Opt {
return func(c *Client) error {
if transport, ok := c.client.Transport.(*http.Transport); ok {
transport.DialContext = dialContext
@@ -71,7 +76,7 @@ func WithDialContext(dialContext func(ctx context.Context, network, addr string)
}
// WithHost overrides the client host with the specified one.
func WithHost(host string) func(*Client) error {
func WithHost(host string) Opt {
return func(c *Client) error {
hostURL, err := ParseHostURL(host)
if err != nil {
@@ -89,7 +94,7 @@ func WithHost(host string) func(*Client) error {
}
// WithHTTPClient overrides the client http client with the specified one
func WithHTTPClient(client *http.Client) func(*Client) error {
func WithHTTPClient(client *http.Client) Opt {
return func(c *Client) error {
if client != nil {
c.client = client
@@ -98,8 +103,16 @@ func WithHTTPClient(client *http.Client) func(*Client) error {
}
}
// WithTimeout configures the time limit for requests made by the HTTP client
func WithTimeout(timeout time.Duration) Opt {
return func(c *Client) error {
c.client.Timeout = timeout
return nil
}
}
// WithHTTPHeaders overrides the client default http headers
func WithHTTPHeaders(headers map[string]string) func(*Client) error {
func WithHTTPHeaders(headers map[string]string) Opt {
return func(c *Client) error {
c.customHTTPHeaders = headers
return nil
@@ -107,7 +120,7 @@ func WithHTTPHeaders(headers map[string]string) func(*Client) error {
}
// WithScheme overrides the client scheme with the specified one
func WithScheme(scheme string) func(*Client) error {
func WithScheme(scheme string) Opt {
return func(c *Client) error {
c.scheme = scheme
return nil
@@ -115,7 +128,7 @@ func WithScheme(scheme string) func(*Client) error {
}
// WithTLSClientConfig applies a tls config to the client transport.
func WithTLSClientConfig(cacertPath, certPath, keyPath string) func(*Client) error {
func WithTLSClientConfig(cacertPath, certPath, keyPath string) Opt {
return func(c *Client) error {
opts := tlsconfig.Options{
CAFile: cacertPath,
@@ -135,10 +148,25 @@ func WithTLSClientConfig(cacertPath, certPath, keyPath string) func(*Client) err
}
}
// WithVersion overrides the client version with the specified one
func WithVersion(version string) func(*Client) error {
// WithVersion overrides the client version with the specified one. If an empty
// version is specified, the value will be ignored to allow version negotiation.
func WithVersion(version string) Opt {
return func(c *Client) error {
c.version = version
if version != "" {
c.version = version
c.manualOverride = true
}
return nil
}
}
// WithAPIVersionNegotiation enables automatic API version negotiation for the client.
// With this option enabled, the client automatically negotiates the API version
// to use when making requests. API version negotiation is performed on the first
// request; subsequent requests will not re-negotiate.
func WithAPIVersionNegotiation() Opt {
return func(c *Client) error {
c.negotiateVersion = true
return nil
}
}

Some files were not shown because too many files have changed in this diff Show More