mirror of
https://github.com/GoogleContainerTools/kaniko
synced 2026-10-21 11:24:54 +02:00
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:
+177
-18
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,6 @@
|
||||
package types
|
||||
|
||||
// Error returns the error message
|
||||
func (e ErrorResponse) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
+2
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
+46
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user