Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
| ... | ... |
@@ -33,7 +33,7 @@ require ( |
| 33 | 33 |
github.com/containerd/fifo v1.1.0 |
| 34 | 34 |
github.com/containerd/log v0.1.0 |
| 35 | 35 |
github.com/containerd/platforms v0.2.1 |
| 36 |
- github.com/containerd/typeurl/v2 v2.1.1 |
|
| 36 |
+ github.com/containerd/typeurl/v2 v2.2.0 |
|
| 37 | 37 |
github.com/coreos/go-systemd/v22 v22.5.0 |
| 38 | 38 |
github.com/cpuguy83/tar2go v0.3.1 |
| 39 | 39 |
github.com/creack/pty v1.1.21 |
| ... | ... |
@@ -63,7 +63,7 @@ require ( |
| 63 | 63 |
github.com/miekg/dns v1.1.57 |
| 64 | 64 |
github.com/mistifyio/go-zfs/v3 v3.0.1 |
| 65 | 65 |
github.com/mitchellh/copystructure v1.2.0 |
| 66 |
- github.com/moby/buildkit v0.15.2 |
|
| 66 |
+ github.com/moby/buildkit v0.16.0-rc1 |
|
| 67 | 67 |
github.com/moby/docker-image-spec v1.3.1 |
| 68 | 68 |
github.com/moby/ipvs v1.1.0 |
| 69 | 69 |
github.com/moby/locker v1.0.1 |
| ... | ... |
@@ -209,9 +209,8 @@ require ( |
| 209 | 209 |
go.etcd.io/etcd/server/v3 v3.5.6 // indirect |
| 210 | 210 |
go.opencensus.io v0.24.0 // indirect |
| 211 | 211 |
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.46.1 // indirect |
| 212 |
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 // indirect |
|
| 213 |
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 // indirect |
|
| 214 |
- go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 // indirect |
|
| 212 |
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 // indirect |
|
| 213 |
+ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0 // indirect |
|
| 215 | 214 |
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect |
| 216 | 215 |
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 // indirect |
| 217 | 216 |
go.opentelemetry.io/otel/metric v1.21.0 // indirect |
| ... | ... |
@@ -170,8 +170,8 @@ github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G |
| 170 | 170 |
github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk= |
| 171 | 171 |
github.com/containerd/ttrpc v1.2.5 h1:IFckT1EFQoFBMG4c3sMdT8EP3/aKfumK1msY+Ze4oLU= |
| 172 | 172 |
github.com/containerd/ttrpc v1.2.5/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o= |
| 173 |
-github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4= |
|
| 174 |
-github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= |
|
| 173 |
+github.com/containerd/typeurl/v2 v2.2.0 h1:6NBDbQzr7I5LHgp34xAXYF5DOTQDn05X58lsPEmzLso= |
|
| 174 |
+github.com/containerd/typeurl/v2 v2.2.0/go.mod h1:8XOOxnyatxSWuG8OfsZXVnAF4iZfedjS/8UHSPJnX4g= |
|
| 175 | 175 |
github.com/containernetworking/cni v1.2.2 h1:9IbP6KJQQxVKo4hhnm8r50YcVKrJbJu3Dqw+Rbt1vYk= |
| 176 | 176 |
github.com/containernetworking/cni v1.2.2/go.mod h1:DuLgF+aPd3DzcTQTtp/Nvl1Kim23oFKdm2okJzBQA5M= |
| 177 | 177 |
github.com/containernetworking/plugins v1.4.0 h1:+w22VPYgk7nQHw7KT92lsRmuToHvb7wwSv9iTbXzzic= |
| ... | ... |
@@ -474,8 +474,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh |
| 474 | 474 |
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= |
| 475 | 475 |
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= |
| 476 | 476 |
github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs= |
| 477 |
-github.com/moby/buildkit v0.15.2 h1:DnONr0AoceTWyv+plsQ7IhkSaj+6o0WyoaxYPyTFIxs= |
|
| 478 |
-github.com/moby/buildkit v0.15.2/go.mod h1:Yis8ZMUJTHX9XhH9zVyK2igqSHV3sxi3UN0uztZocZk= |
|
| 477 |
+github.com/moby/buildkit v0.16.0-rc1 h1:G6KBYr6T4B1ylpinYIjcNLcVkPUkuddw3daqaM9yg9A= |
|
| 478 |
+github.com/moby/buildkit v0.16.0-rc1/go.mod h1:WLr3pMBXsAoSuZIGdGww1JPz8S8Qp+OTf0dlrPnzbDg= |
|
| 479 | 479 |
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= |
| 480 | 480 |
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= |
| 481 | 481 |
github.com/moby/ipvs v1.1.0 h1:ONN4pGaZQgAx+1Scz5RvWV4Q7Gb+mvfRh3NsPS+1XQQ= |
| ... | ... |
@@ -597,8 +597,8 @@ github.com/rexray/gocsi v1.2.2/go.mod h1:X9oJHHpIVGmfKdK8e+JuCXafggk7HxL9mWQOgrs |
| 597 | 597 |
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= |
| 598 | 598 |
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= |
| 599 | 599 |
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= |
| 600 |
-github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= |
|
| 601 |
-github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= |
|
| 600 |
+github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= |
|
| 601 |
+github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= |
|
| 602 | 602 |
github.com/rootless-containers/rootlesskit/v2 v2.0.2 h1:wztWcDYFlk+EVAUuPJwlNMFXZIk1G14T45lv47WWGuA= |
| 603 | 603 |
github.com/rootless-containers/rootlesskit/v2 v2.0.2/go.mod h1:hE+ztevrQxNi+tdZyPKumzDk7VKDAf0E4seOzlOyBsY= |
| 604 | 604 |
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= |
| ... | ... |
@@ -735,12 +735,10 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1: |
| 735 | 735 |
go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU= |
| 736 | 736 |
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= |
| 737 | 737 |
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= |
| 738 |
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 h1:ZtfnDL+tUrs1F0Pzfwbg2d59Gru9NCH3bgSHBM6LDwU= |
|
| 739 |
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0/go.mod h1:hG4Fj/y8TR/tlEDREo8tWstl9fO9gcFkn4xrx0Io8xU= |
|
| 740 |
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 h1:NmnYCiR0qNufkldjVvyQfZTHSdzeHoZ41zggMsdMcLM= |
|
| 741 |
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0/go.mod h1:UVAO61+umUsHLtYb8KXXRoHtxUkdOPkYidzW3gipRLQ= |
|
| 742 |
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 h1:wNMDy/LVGLj2h3p6zg4d0gypKfWKSWI14E1C4smOgl8= |
|
| 743 |
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0/go.mod h1:YfbDdXAAkemWJK3H/DshvlrxqFB2rtW4rY6ky/3x/H0= |
|
| 738 |
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 h1:jd0+5t/YynESZqsSyPz+7PAFdEop0dlN0+PkyHYo8oI= |
|
| 739 |
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0/go.mod h1:U707O40ee1FpQGyhvqnzmCJm1Wh6OX6GGBVn0E6Uyyk= |
|
| 740 |
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0 h1:bflGWrfYyuulcdxf14V6n9+CoQcu5SAAdHmDPAJnlps= |
|
| 741 |
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0/go.mod h1:qcTO4xHAxZLaLxPd60TdE88rxtItPHgHWqOhOGRr0as= |
|
| 744 | 742 |
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw= |
| 745 | 743 |
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= |
| 746 | 744 |
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= |
| 747 | 745 |
deleted file mode 100644 |
| ... | ... |
@@ -1,29 +0,0 @@ |
| 1 |
-/* |
|
| 2 |
- Copyright The containerd Authors. |
|
| 3 |
- |
|
| 4 |
- Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 5 |
- you may not use this file except in compliance with the License. |
|
| 6 |
- You may obtain a copy of the License at |
|
| 7 |
- |
|
| 8 |
- http://www.apache.org/licenses/LICENSE-2.0 |
|
| 9 |
- |
|
| 10 |
- Unless required by applicable law or agreed to in writing, software |
|
| 11 |
- distributed under the License is distributed on an "AS IS" BASIS, |
|
| 12 |
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 13 |
- See the License for the specific language governing permissions and |
|
| 14 |
- limitations under the License. |
|
| 15 |
-*/ |
|
| 16 |
- |
|
| 17 |
-// Deprecated: use github.com/moby/sys/userns |
|
| 18 |
-package userns |
|
| 19 |
- |
|
| 20 |
-import "github.com/moby/sys/userns" |
|
| 21 |
- |
|
| 22 |
-// RunningInUserNS detects whether we are currently running in a Linux |
|
| 23 |
-// user namespace and memoizes the result. It returns false on non-Linux |
|
| 24 |
-// platforms. |
|
| 25 |
-// |
|
| 26 |
-// Deprecated: use [userns.RunningInUserNS]. |
|
| 27 |
-func RunningInUserNS() bool {
|
|
| 28 |
- return userns.RunningInUserNS() |
|
| 29 |
-} |
| ... | ... |
@@ -2,7 +2,7 @@ |
| 2 | 2 |
|
| 3 | 3 |
[](https://pkg.go.dev/github.com/containerd/typeurl) |
| 4 | 4 |
[](https://github.com/containerd/typeurl/actions?query=workflow%3ACI) |
| 5 |
-[](https://codecov.io/gh/containerd/typeurl) |
|
| 5 |
+[](https://codecov.io/gh/containerd/typeurl) |
|
| 6 | 6 |
[](https://goreportcard.com/report/github.com/containerd/typeurl) |
| 7 | 7 |
|
| 8 | 8 |
A Go package for managing the registration, marshaling, and unmarshaling of encoded types. |
| ... | ... |
@@ -13,8 +13,8 @@ This package helps when types are sent over a ttrpc/GRPC API and marshaled as a |
| 13 | 13 |
|
| 14 | 14 |
**typeurl** is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). |
| 15 | 15 |
As a containerd sub-project, you will find the: |
| 16 |
- * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md), |
|
| 17 |
- * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS), |
|
| 18 |
- * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) |
|
| 16 |
+ * [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md), |
|
| 17 |
+ * [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS), |
|
| 18 |
+ * and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md) |
|
| 19 | 19 |
|
| 20 | 20 |
information in our [`containerd/project`](https://github.com/containerd/project) repository. |
| ... | ... |
@@ -27,6 +27,7 @@ import ( |
| 27 | 27 |
gogoproto "github.com/gogo/protobuf/proto" |
| 28 | 28 |
"google.golang.org/protobuf/proto" |
| 29 | 29 |
"google.golang.org/protobuf/reflect/protoregistry" |
| 30 |
+ "google.golang.org/protobuf/types/known/anypb" |
|
| 30 | 31 |
) |
| 31 | 32 |
|
| 32 | 33 |
var ( |
| ... | ... |
@@ -122,6 +123,9 @@ func TypeURL(v interface{}) (string, error) {
|
| 122 | 122 |
|
| 123 | 123 |
// Is returns true if the type of the Any is the same as v. |
| 124 | 124 |
func Is(any Any, v interface{}) bool {
|
| 125 |
+ if any == nil {
|
|
| 126 |
+ return false |
|
| 127 |
+ } |
|
| 125 | 128 |
// call to check that v is a pointer |
| 126 | 129 |
tryDereference(v) |
| 127 | 130 |
url, err := TypeURL(v) |
| ... | ... |
@@ -193,6 +197,31 @@ func UnmarshalToByTypeURL(typeURL string, value []byte, out interface{}) error {
|
| 193 | 193 |
return err |
| 194 | 194 |
} |
| 195 | 195 |
|
| 196 |
+// MarshalProto converts typeurl.Any to google.golang.org/protobuf/types/known/anypb.Any. |
|
| 197 |
+func MarshalProto(from Any) *anypb.Any {
|
|
| 198 |
+ if from == nil {
|
|
| 199 |
+ return nil |
|
| 200 |
+ } |
|
| 201 |
+ |
|
| 202 |
+ if pbany, ok := from.(*anypb.Any); ok {
|
|
| 203 |
+ return pbany |
|
| 204 |
+ } |
|
| 205 |
+ |
|
| 206 |
+ return &anypb.Any{
|
|
| 207 |
+ TypeUrl: from.GetTypeUrl(), |
|
| 208 |
+ Value: from.GetValue(), |
|
| 209 |
+ } |
|
| 210 |
+} |
|
| 211 |
+ |
|
| 212 |
+// MarshalAnyToProto converts an arbitrary interface to google.golang.org/protobuf/types/known/anypb.Any. |
|
| 213 |
+func MarshalAnyToProto(from interface{}) (*anypb.Any, error) {
|
|
| 214 |
+ anyType, err := MarshalAny(from) |
|
| 215 |
+ if err != nil {
|
|
| 216 |
+ return nil, err |
|
| 217 |
+ } |
|
| 218 |
+ return MarshalProto(anyType), nil |
|
| 219 |
+} |
|
| 220 |
+ |
|
| 196 | 221 |
func unmarshal(typeURL string, value []byte, v interface{}) (interface{}, error) {
|
| 197 | 222 |
t, err := getTypeByUrl(typeURL) |
| 198 | 223 |
if err != nil {
|
| ... | ... |
@@ -1520,6 +1520,7 @@ type BuildHistoryRecord struct {
|
| 1520 | 1520 |
NumTotalSteps int32 `protobuf:"varint,16,opt,name=numTotalSteps,proto3" json:"numTotalSteps,omitempty"` |
| 1521 | 1521 |
NumCompletedSteps int32 `protobuf:"varint,17,opt,name=numCompletedSteps,proto3" json:"numCompletedSteps,omitempty"` |
| 1522 | 1522 |
ExternalError *Descriptor `protobuf:"bytes,18,opt,name=externalError,proto3" json:"externalError,omitempty"` |
| 1523 |
+ NumWarnings int32 `protobuf:"varint,19,opt,name=numWarnings,proto3" json:"numWarnings,omitempty"` |
|
| 1523 | 1524 |
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
| 1524 | 1525 |
XXX_unrecognized []byte `json:"-"` |
| 1525 | 1526 |
XXX_sizecache int32 `json:"-"` |
| ... | ... |
@@ -1684,6 +1685,13 @@ func (m *BuildHistoryRecord) GetExternalError() *Descriptor {
|
| 1684 | 1684 |
return nil |
| 1685 | 1685 |
} |
| 1686 | 1686 |
|
| 1687 |
+func (m *BuildHistoryRecord) GetNumWarnings() int32 {
|
|
| 1688 |
+ if m != nil {
|
|
| 1689 |
+ return m.NumWarnings |
|
| 1690 |
+ } |
|
| 1691 |
+ return 0 |
|
| 1692 |
+} |
|
| 1693 |
+ |
|
| 1687 | 1694 |
type UpdateBuildHistoryRequest struct {
|
| 1688 | 1695 |
Ref string `protobuf:"bytes,1,opt,name=Ref,proto3" json:"Ref,omitempty"` |
| 1689 | 1696 |
Pinned bool `protobuf:"varint,2,opt,name=Pinned,proto3" json:"Pinned,omitempty"` |
| ... | ... |
@@ -2025,154 +2033,155 @@ func init() {
|
| 2025 | 2025 |
func init() { proto.RegisterFile("control.proto", fileDescriptor_0c5120591600887d) }
|
| 2026 | 2026 |
|
| 2027 | 2027 |
var fileDescriptor_0c5120591600887d = []byte{
|
| 2028 |
- // 2340 bytes of a gzipped FileDescriptorProto |
|
| 2028 |
+ // 2354 bytes of a gzipped FileDescriptorProto |
|
| 2029 | 2029 |
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x19, 0x4d, 0x73, 0x1b, 0x59, |
| 2030 | 2030 |
0x31, 0x23, 0xc9, 0xb2, 0xd4, 0x92, 0x1c, 0xf9, 0x25, 0x1b, 0x86, 0x21, 0x6b, 0x3b, 0xb3, 0x09, |
| 2031 | 2031 |
0xb8, 0x42, 0x32, 0xf2, 0x0a, 0x42, 0xb2, 0x0e, 0x84, 0x58, 0x96, 0xd8, 0x38, 0xc4, 0x15, 0xef, |
| 2032 | 2032 |
0xb3, 0xb3, 0xa1, 0xb6, 0x6a, 0xa1, 0xc6, 0xd2, 0xb3, 0x32, 0xe5, 0xd1, 0xcc, 0xf0, 0xde, 0x93, |
| 2033 |
- 0x37, 0xe2, 0xc4, 0x89, 0x2a, 0x2e, 0x14, 0x17, 0x8a, 0x0b, 0x77, 0x4e, 0x9c, 0x39, 0x71, 0xe0, |
|
| 2034 |
- 0x40, 0x55, 0x8e, 0x9c, 0xf7, 0x10, 0xa8, 0xfc, 0x00, 0x8a, 0x23, 0x47, 0xea, 0x7d, 0x8c, 0x34, |
|
| 2035 |
- 0x92, 0x46, 0xb6, 0x9c, 0xe4, 0xa4, 0xd7, 0xef, 0x75, 0xf7, 0x74, 0xf7, 0xeb, 0xee, 0xd7, 0xdd, |
|
| 2036 |
- 0x82, 0x4a, 0x3b, 0x0c, 0x38, 0x0d, 0x7d, 0x27, 0xa2, 0x21, 0x0f, 0x51, 0xb5, 0x17, 0x1e, 0x0e, |
|
| 2037 |
- 0x9c, 0xc3, 0xbe, 0xe7, 0x77, 0x8e, 0x3d, 0xee, 0x9c, 0x7c, 0x6c, 0xd5, 0xbb, 0x1e, 0x7f, 0xd1, |
|
| 2038 |
- 0x3f, 0x74, 0xda, 0x61, 0xaf, 0xd6, 0x0d, 0xbb, 0x61, 0xad, 0x1b, 0x86, 0x5d, 0x9f, 0xb8, 0x91, |
|
| 2039 |
- 0xc7, 0xf4, 0xb2, 0x46, 0xa3, 0x76, 0x8d, 0x71, 0x97, 0xf7, 0x99, 0xe2, 0x62, 0xdd, 0x9e, 0xa4, |
|
| 2040 |
- 0x91, 0xdb, 0x87, 0xfd, 0x23, 0x09, 0x49, 0x40, 0xae, 0x34, 0x7a, 0x2d, 0x81, 0x2e, 0xbe, 0x5f, |
|
| 2041 |
- 0x8b, 0xbf, 0x5f, 0x73, 0x23, 0xaf, 0xc6, 0x07, 0x11, 0x61, 0xb5, 0xaf, 0x42, 0x7a, 0x4c, 0xa8, |
|
| 2042 |
- 0x26, 0xb8, 0x35, 0x93, 0x80, 0x85, 0xfe, 0x09, 0xa1, 0xb5, 0xe8, 0xb0, 0x16, 0x46, 0xb1, 0x34, |
|
| 2043 |
- 0x77, 0x4e, 0xc1, 0xee, 0xd3, 0x36, 0x89, 0x42, 0xdf, 0x6b, 0x0f, 0x04, 0x8d, 0x5a, 0x69, 0xb2, |
|
| 2044 |
- 0x55, 0xad, 0xdd, 0x50, 0x76, 0xee, 0xf5, 0x08, 0xe3, 0x6e, 0x2f, 0x52, 0x08, 0xf6, 0x6f, 0x0c, |
|
| 2045 |
- 0x28, 0xef, 0xd1, 0x7e, 0x40, 0x30, 0xf9, 0x65, 0x9f, 0x30, 0x8e, 0xae, 0x40, 0xfe, 0xc8, 0xf3, |
|
| 2046 |
- 0x39, 0xa1, 0xa6, 0xb1, 0x96, 0x5d, 0x2f, 0x62, 0x0d, 0xa1, 0x2a, 0x64, 0x5d, 0xdf, 0x37, 0x33, |
|
| 2047 |
- 0x6b, 0xc6, 0x7a, 0x01, 0x8b, 0x25, 0x5a, 0x87, 0xf2, 0x31, 0x21, 0x51, 0xb3, 0x4f, 0x5d, 0xee, |
|
| 2048 |
- 0x85, 0x81, 0x99, 0x5d, 0x33, 0xd6, 0xb3, 0x8d, 0xdc, 0xab, 0xd7, 0xab, 0x06, 0x1e, 0x3b, 0x41, |
|
| 2049 |
- 0x36, 0x14, 0x05, 0xdc, 0x18, 0x70, 0xc2, 0xcc, 0x5c, 0x02, 0x6d, 0xb4, 0x6d, 0xdf, 0x84, 0x6a, |
|
| 2050 |
- 0xd3, 0x63, 0xc7, 0xcf, 0x98, 0xdb, 0x3d, 0x4b, 0x16, 0xfb, 0x31, 0x2c, 0x27, 0x70, 0x59, 0x14, |
|
| 2051 |
- 0x06, 0x8c, 0xa0, 0x3b, 0x90, 0xa7, 0xa4, 0x1d, 0xd2, 0x8e, 0x44, 0x2e, 0xd5, 0x3f, 0x74, 0x26, |
|
| 2052 |
- 0xdd, 0xc0, 0xd1, 0x04, 0x02, 0x09, 0x6b, 0x64, 0xfb, 0x8f, 0x59, 0x28, 0x25, 0xf6, 0xd1, 0x12, |
|
| 2053 |
- 0x64, 0x76, 0x9a, 0xa6, 0xb1, 0x66, 0xac, 0x17, 0x71, 0x66, 0xa7, 0x89, 0x4c, 0x58, 0xdc, 0xed, |
|
| 2054 |
- 0x73, 0xf7, 0xd0, 0x27, 0x5a, 0xf7, 0x18, 0x44, 0x97, 0x61, 0x61, 0x27, 0x78, 0xc6, 0x88, 0x54, |
|
| 2055 |
- 0xbc, 0x80, 0x15, 0x80, 0x10, 0xe4, 0xf6, 0xbd, 0x5f, 0x11, 0xa5, 0x26, 0x96, 0x6b, 0x64, 0x41, |
|
| 2056 |
- 0x7e, 0xcf, 0xa5, 0x24, 0xe0, 0xe6, 0x82, 0xe0, 0xdb, 0xc8, 0x98, 0x06, 0xd6, 0x3b, 0xa8, 0x01, |
|
| 2057 |
- 0xc5, 0x6d, 0x4a, 0x5c, 0x4e, 0x3a, 0x5b, 0xdc, 0xcc, 0xaf, 0x19, 0xeb, 0xa5, 0xba, 0xe5, 0xa8, |
|
| 2058 |
- 0x5b, 0x73, 0xe2, 0x5b, 0x73, 0x0e, 0xe2, 0x5b, 0x6b, 0x14, 0x5e, 0xbd, 0x5e, 0xbd, 0xf0, 0xfb, |
|
| 2059 |
- 0x7f, 0x09, 0xdb, 0x0d, 0xc9, 0xd0, 0x43, 0x80, 0x27, 0x2e, 0xe3, 0xcf, 0x98, 0x64, 0xb2, 0x78, |
|
| 2060 |
- 0x26, 0x93, 0x9c, 0x64, 0x90, 0xa0, 0x41, 0x2b, 0x00, 0xd2, 0x08, 0xdb, 0x61, 0x3f, 0xe0, 0x66, |
|
| 2061 |
- 0x41, 0xca, 0x9e, 0xd8, 0x41, 0x6b, 0x50, 0x6a, 0x12, 0xd6, 0xa6, 0x5e, 0x24, 0xaf, 0xba, 0x28, |
|
| 2062 |
- 0xcd, 0x93, 0xdc, 0x12, 0x1c, 0x94, 0x05, 0x0f, 0x06, 0x11, 0x31, 0x41, 0x22, 0x24, 0x76, 0xc4, |
|
| 2063 |
- 0x5d, 0xee, 0xbf, 0x70, 0x29, 0xe9, 0x98, 0x25, 0x69, 0x2e, 0x0d, 0x09, 0xfb, 0x2a, 0x4b, 0x30, |
|
| 2064 |
- 0xb3, 0x2c, 0x2f, 0x39, 0x06, 0xed, 0x5f, 0x17, 0xa0, 0xbc, 0x2f, 0x42, 0x21, 0x76, 0x87, 0x2a, |
|
| 2065 |
- 0x64, 0x31, 0x39, 0xd2, 0x77, 0x23, 0x96, 0xc8, 0x01, 0x68, 0x92, 0x23, 0x2f, 0xf0, 0xa4, 0x54, |
|
| 2066 |
- 0x19, 0xa9, 0xf8, 0x92, 0x13, 0x1d, 0x3a, 0xa3, 0x5d, 0x9c, 0xc0, 0x40, 0x0e, 0xa0, 0xd6, 0xcb, |
|
| 2067 |
- 0x28, 0xa4, 0x9c, 0xd0, 0x26, 0x89, 0x28, 0x69, 0x0b, 0x03, 0xca, 0xfb, 0x2b, 0xe2, 0x94, 0x13, |
|
| 2068 |
- 0xd4, 0x87, 0x6f, 0xc4, 0xbb, 0x5b, 0x9c, 0x53, 0x96, 0x20, 0xca, 0x49, 0x27, 0xbb, 0x3f, 0xed, |
|
| 2069 |
- 0x64, 0x49, 0x91, 0x9d, 0x19, 0xd4, 0xad, 0x80, 0xd3, 0x01, 0x9e, 0xc5, 0x5b, 0xd8, 0x64, 0x9f, |
|
| 2070 |
- 0x30, 0x26, 0x74, 0x92, 0x0e, 0x83, 0x63, 0x10, 0x59, 0x50, 0xf8, 0x09, 0x0d, 0x03, 0x4e, 0x82, |
|
| 2071 |
- 0x8e, 0x74, 0x96, 0x22, 0x1e, 0xc2, 0xe8, 0x39, 0x54, 0xe2, 0xb5, 0x64, 0x68, 0x2e, 0x4a, 0x11, |
|
| 2072 |
- 0x3f, 0x3e, 0x43, 0xc4, 0x31, 0x1a, 0x25, 0xd8, 0x38, 0x1f, 0xb4, 0x09, 0x0b, 0xdb, 0x6e, 0xfb, |
|
| 2073 |
- 0x05, 0x91, 0x7e, 0x51, 0xaa, 0xaf, 0x4c, 0x33, 0x94, 0xc7, 0x4f, 0xa5, 0x23, 0x30, 0x19, 0xda, |
|
| 2074 |
- 0x17, 0xb0, 0x22, 0x41, 0x3f, 0x87, 0x72, 0x2b, 0xe0, 0x1e, 0xf7, 0x49, 0x4f, 0xde, 0x71, 0x51, |
|
| 2075 |
- 0xdc, 0x71, 0x63, 0xf3, 0xeb, 0xd7, 0xab, 0x3f, 0x98, 0x99, 0xd1, 0xfa, 0xdc, 0xf3, 0x6b, 0x24, |
|
| 2076 |
- 0x41, 0xe5, 0x24, 0x58, 0xe0, 0x31, 0x7e, 0xe8, 0x0b, 0x58, 0x8a, 0x85, 0xdd, 0x09, 0xa2, 0x3e, |
|
| 2077 |
- 0x67, 0x26, 0x48, 0xad, 0xeb, 0x73, 0x6a, 0xad, 0x88, 0x94, 0xda, 0x13, 0x9c, 0x84, 0xb1, 0x77, |
|
| 2078 |
- 0x02, 0x4e, 0x68, 0xe0, 0xfa, 0xda, 0x69, 0x87, 0x30, 0xda, 0x11, 0xbe, 0x29, 0x12, 0xef, 0x9e, |
|
| 2079 |
- 0x4c, 0xb7, 0x66, 0x59, 0x9a, 0xe6, 0xc6, 0xf4, 0x57, 0x93, 0xe9, 0xd9, 0x51, 0xc8, 0x78, 0x8c, |
|
| 2080 |
- 0x14, 0xdd, 0x83, 0x62, 0xec, 0x08, 0xcc, 0xac, 0x48, 0xe9, 0xad, 0x69, 0x3e, 0x31, 0x0a, 0x1e, |
|
| 2081 |
- 0x21, 0x5b, 0x8f, 0xe1, 0xea, 0x69, 0x0e, 0x26, 0x02, 0xe6, 0x98, 0x0c, 0xe2, 0x80, 0x39, 0x26, |
|
| 2082 |
- 0x03, 0x91, 0xb3, 0x4e, 0x5c, 0xbf, 0xaf, 0x72, 0x59, 0x11, 0x2b, 0x60, 0x33, 0x73, 0xcf, 0xb0, |
|
| 2083 |
- 0x1e, 0x02, 0x9a, 0xf6, 0x84, 0x73, 0x71, 0xf8, 0x0c, 0x2e, 0xa5, 0x58, 0x35, 0x85, 0xc5, 0xf5, |
|
| 2084 |
- 0x24, 0x8b, 0xe9, 0x80, 0x1d, 0xb1, 0xb4, 0xff, 0x92, 0x85, 0x72, 0xd2, 0xb7, 0xd0, 0x06, 0x5c, |
|
| 2085 |
- 0x52, 0x1a, 0x63, 0x72, 0x94, 0x08, 0x46, 0xc5, 0x3c, 0xed, 0x08, 0xd5, 0xe1, 0xf2, 0x4e, 0x4f, |
|
| 2086 |
- 0x6f, 0x27, 0xe3, 0x37, 0x23, 0x93, 0x4d, 0xea, 0x19, 0x0a, 0xe1, 0x03, 0xc5, 0x6a, 0x32, 0xe8, |
|
| 2087 |
- 0xb3, 0xf2, 0x76, 0x3e, 0x39, 0x3d, 0x00, 0x9c, 0x54, 0x5a, 0xe5, 0x62, 0xe9, 0x7c, 0xd1, 0x8f, |
|
| 2088 |
- 0x60, 0x51, 0x1d, 0x30, 0x9d, 0x57, 0x3e, 0x3a, 0xfd, 0x13, 0x8a, 0x59, 0x4c, 0x23, 0xc8, 0x95, |
|
| 2089 |
- 0x1e, 0xcc, 0x5c, 0x38, 0x07, 0xb9, 0xa6, 0xb1, 0x1e, 0x81, 0x35, 0x5b, 0xe4, 0xf3, 0xb8, 0x80, |
|
| 2090 |
- 0xfd, 0x67, 0x03, 0x96, 0xa7, 0x3e, 0x24, 0x9e, 0x44, 0xf9, 0x28, 0x28, 0x16, 0x72, 0x8d, 0x9a, |
|
| 2091 |
- 0xb0, 0xa0, 0x92, 0x54, 0x46, 0x0a, 0xec, 0xcc, 0x21, 0xb0, 0x93, 0xc8, 0x50, 0x8a, 0xd8, 0xba, |
|
| 2092 |
- 0x07, 0xf0, 0x76, 0xce, 0x6a, 0xff, 0xd5, 0x80, 0x8a, 0x4e, 0x08, 0xba, 0x7e, 0x70, 0xa1, 0x3a, |
|
| 2093 |
- 0x8c, 0x31, 0xbd, 0xa7, 0x2b, 0x89, 0x3b, 0x33, 0x73, 0x89, 0x42, 0x73, 0x26, 0xe9, 0x94, 0x8c, |
|
| 2094 |
- 0x53, 0xec, 0xac, 0xed, 0xd8, 0xaf, 0x26, 0x50, 0xcf, 0x25, 0xf9, 0x35, 0xa8, 0xec, 0xcb, 0x3a, |
|
| 2095 |
- 0x75, 0xe6, 0xb3, 0x68, 0xff, 0xd7, 0x80, 0xa5, 0x18, 0x47, 0x6b, 0xf7, 0x7d, 0x28, 0x9c, 0x10, |
|
| 2096 |
- 0xca, 0xc9, 0x4b, 0xc2, 0xb4, 0x56, 0xe6, 0xb4, 0x56, 0x9f, 0x4b, 0x0c, 0x3c, 0xc4, 0x44, 0x9b, |
|
| 2097 |
- 0x50, 0x50, 0x35, 0x31, 0x89, 0x2f, 0x6a, 0x65, 0x16, 0x95, 0xfe, 0xde, 0x10, 0x1f, 0xd5, 0x20, |
|
| 2098 |
- 0xe7, 0x87, 0x5d, 0xa6, 0x63, 0xe6, 0x5b, 0xb3, 0xe8, 0x9e, 0x84, 0x5d, 0x2c, 0x11, 0xd1, 0x7d, |
|
| 2099 |
- 0x28, 0x7c, 0xe5, 0xd2, 0xc0, 0x0b, 0xba, 0x71, 0x14, 0xac, 0xce, 0x22, 0x7a, 0xae, 0xf0, 0xf0, |
|
| 2100 |
- 0x90, 0x40, 0x94, 0x71, 0x79, 0x75, 0x86, 0x1e, 0x43, 0xbe, 0xe3, 0x75, 0x09, 0xe3, 0xca, 0x24, |
|
| 2101 |
- 0x8d, 0xba, 0x78, 0x8f, 0xbe, 0x7e, 0xbd, 0x7a, 0x33, 0xf1, 0xe0, 0x84, 0x11, 0x09, 0x44, 0xd3, |
|
| 2102 |
- 0xe0, 0x7a, 0x01, 0xa1, 0xa2, 0x07, 0xb8, 0xad, 0x48, 0x9c, 0xa6, 0xfc, 0xc1, 0x9a, 0x83, 0xe0, |
|
| 2103 |
- 0xe5, 0xa9, 0x67, 0x45, 0xe6, 0x8b, 0xb7, 0xe3, 0xa5, 0x38, 0x88, 0x30, 0x08, 0xdc, 0x1e, 0xd1, |
|
| 2104 |
- 0xe5, 0x86, 0x5c, 0x8b, 0xaa, 0xa8, 0x2d, 0xfc, 0xbc, 0x23, 0xeb, 0xc5, 0x02, 0xd6, 0x10, 0xda, |
|
| 2105 |
- 0x84, 0x45, 0xc6, 0x5d, 0x2a, 0x72, 0xce, 0xc2, 0x9c, 0xe5, 0x5c, 0x4c, 0x80, 0x1e, 0x40, 0xb1, |
|
| 2106 |
- 0x1d, 0xf6, 0x22, 0x9f, 0x08, 0xea, 0xfc, 0x9c, 0xd4, 0x23, 0x12, 0xe1, 0x7a, 0x84, 0xd2, 0x90, |
|
| 2107 |
- 0xca, 0x42, 0xb2, 0x88, 0x15, 0x80, 0xee, 0x42, 0x25, 0xa2, 0x61, 0x97, 0x12, 0xc6, 0x3e, 0xa5, |
|
| 2108 |
- 0x61, 0x3f, 0xd2, 0xc5, 0xc0, 0xb2, 0x48, 0xde, 0x7b, 0xc9, 0x03, 0x3c, 0x8e, 0x67, 0xff, 0x27, |
|
| 2109 |
- 0x03, 0xe5, 0xa4, 0x8b, 0x4c, 0x55, 0xd8, 0x8f, 0x21, 0xaf, 0x1c, 0x4e, 0xf9, 0xfa, 0xdb, 0xd9, |
|
| 2110 |
- 0x58, 0x71, 0x48, 0xb5, 0xb1, 0x09, 0x8b, 0xed, 0x3e, 0x95, 0xe5, 0xb7, 0x2a, 0xca, 0x63, 0x50, |
|
| 2111 |
- 0x68, 0xca, 0x43, 0xee, 0xfa, 0xd2, 0xc6, 0x59, 0xac, 0x00, 0x51, 0x91, 0x0f, 0xbb, 0xa4, 0xf3, |
|
| 2112 |
- 0x55, 0xe4, 0x43, 0xb2, 0xe4, 0xfd, 0x2d, 0xbe, 0xd3, 0xfd, 0x15, 0xce, 0x7d, 0x7f, 0xf6, 0x3f, |
|
| 2113 |
- 0x0c, 0x28, 0x0e, 0x63, 0x2b, 0x61, 0x5d, 0xe3, 0x9d, 0xad, 0x3b, 0x66, 0x99, 0xcc, 0xdb, 0x59, |
|
| 2114 |
- 0xe6, 0x0a, 0xe4, 0x19, 0xa7, 0xc4, 0xed, 0xa9, 0x7e, 0x11, 0x6b, 0x48, 0x64, 0xb1, 0x1e, 0xeb, |
|
| 2115 |
- 0xca, 0x1b, 0x2a, 0x63, 0xb1, 0xb4, 0xff, 0x67, 0x40, 0x65, 0x2c, 0xdc, 0xdf, 0xab, 0x2e, 0x97, |
|
| 2116 |
- 0x61, 0xc1, 0x27, 0x27, 0x44, 0x75, 0xb4, 0x59, 0xac, 0x00, 0xb1, 0xcb, 0x5e, 0x84, 0x94, 0x4b, |
|
| 2117 |
- 0xe1, 0xca, 0x58, 0x01, 0x42, 0xe6, 0x0e, 0xe1, 0xae, 0xe7, 0xcb, 0xbc, 0x54, 0xc6, 0x1a, 0x12, |
|
| 2118 |
- 0x32, 0xf7, 0xa9, 0xaf, 0x6b, 0x74, 0xb1, 0x44, 0x36, 0xe4, 0xbc, 0xe0, 0x28, 0xd4, 0x6e, 0x23, |
|
| 2119 |
- 0x2b, 0x1b, 0x55, 0xeb, 0xed, 0x04, 0x47, 0x21, 0x96, 0x67, 0xe8, 0x1a, 0xe4, 0xa9, 0x1b, 0x74, |
|
| 2120 |
- 0x49, 0x5c, 0xa0, 0x17, 0x05, 0x16, 0x16, 0x3b, 0x58, 0x1f, 0xd8, 0x36, 0x94, 0x65, 0x57, 0xbc, |
|
| 2121 |
- 0x4b, 0x98, 0xe8, 0xc1, 0x84, 0x5b, 0x77, 0x5c, 0xee, 0x4a, 0xb5, 0xcb, 0x58, 0xae, 0xed, 0x5b, |
|
| 2122 |
- 0x80, 0x9e, 0x78, 0x8c, 0x3f, 0x97, 0x33, 0x05, 0x76, 0x56, 0xcb, 0xbc, 0x0f, 0x97, 0xc6, 0xb0, |
|
| 2123 |
- 0xf5, 0xb3, 0xf0, 0xc3, 0x89, 0xa6, 0xf9, 0xfa, 0x74, 0xc6, 0x95, 0xa3, 0x0b, 0x47, 0x11, 0x4e, |
|
| 2124 |
- 0xf4, 0xce, 0x15, 0x28, 0x49, 0xbd, 0xd4, 0xb7, 0x6d, 0x17, 0xca, 0x0a, 0xd4, 0xcc, 0x3f, 0x83, |
|
| 2125 |
- 0x8b, 0x31, 0xa3, 0xcf, 0x09, 0x95, 0xed, 0x8c, 0x21, 0xed, 0xf2, 0x9d, 0x59, 0x5f, 0x69, 0x8c, |
|
| 2126 |
- 0xa3, 0xe3, 0x49, 0x7a, 0x9b, 0xc0, 0x25, 0x89, 0xf3, 0xc8, 0x63, 0x3c, 0xa4, 0x83, 0x58, 0xeb, |
|
| 2127 |
- 0x15, 0x80, 0xad, 0x36, 0xf7, 0x4e, 0xc8, 0xd3, 0xc0, 0x57, 0xcf, 0x68, 0x01, 0x27, 0x76, 0xe2, |
|
| 2128 |
- 0x27, 0x32, 0x33, 0xea, 0x1c, 0xaf, 0x42, 0xb1, 0xe5, 0x52, 0x7f, 0xd0, 0x7a, 0xe9, 0x71, 0xdd, |
|
| 2129 |
- 0xc0, 0x8f, 0x36, 0xec, 0xdf, 0x19, 0xb0, 0x9c, 0xfc, 0x4e, 0xeb, 0x44, 0xa4, 0x8b, 0xfb, 0x90, |
|
| 2130 |
- 0xe3, 0x71, 0x1d, 0xb3, 0x94, 0xa6, 0xc4, 0x14, 0x89, 0x28, 0x75, 0xb0, 0x24, 0x4a, 0x58, 0x5a, |
|
| 2131 |
- 0x05, 0xce, 0xf5, 0xd3, 0xc9, 0x27, 0x2c, 0xfd, 0xb7, 0x22, 0xa0, 0xe9, 0xe3, 0x94, 0x8e, 0x38, |
|
| 2132 |
- 0xd9, 0x20, 0x66, 0x26, 0x1a, 0xc4, 0x2f, 0x27, 0x1b, 0x44, 0xf5, 0x34, 0xdf, 0x9d, 0x47, 0x92, |
|
| 2133 |
- 0x39, 0xda, 0xc4, 0xb1, 0x3e, 0x26, 0x77, 0x8e, 0x3e, 0x06, 0xad, 0xc7, 0x2f, 0x8e, 0x7a, 0xeb, |
|
| 2134 |
- 0x50, 0x9c, 0x53, 0x68, 0xd4, 0x76, 0x74, 0x5d, 0xa1, 0x5f, 0xa1, 0x07, 0xe7, 0x9b, 0x96, 0xe4, |
|
| 2135 |
- 0x26, 0x27, 0x25, 0x0d, 0x28, 0x6d, 0xc7, 0x89, 0xf2, 0x1c, 0xa3, 0x92, 0x24, 0x11, 0xda, 0xd0, |
|
| 2136 |
- 0x85, 0x8d, 0x4a, 0xcd, 0x57, 0xa7, 0x55, 0x8c, 0xc7, 0x22, 0x21, 0xd5, 0x95, 0xcd, 0x51, 0x4a, |
|
| 2137 |
- 0x69, 0x59, 0x94, 0x06, 0xda, 0x9c, 0xcb, 0xf6, 0x73, 0xd6, 0x97, 0xe8, 0x13, 0xc8, 0x63, 0xc2, |
|
| 2138 |
- 0xfa, 0x3e, 0x97, 0xf3, 0x97, 0x52, 0xfd, 0xda, 0x0c, 0xee, 0x0a, 0x49, 0xc6, 0xaa, 0x26, 0x40, |
|
| 2139 |
- 0x3f, 0x85, 0x45, 0xb5, 0x62, 0x66, 0x69, 0xd6, 0xd8, 0x20, 0x45, 0x32, 0x4d, 0xa3, 0x1b, 0x0a, |
|
| 2140 |
- 0x0d, 0x89, 0x70, 0xfc, 0x94, 0x04, 0x44, 0xcf, 0x05, 0x45, 0x6b, 0xbc, 0x80, 0x13, 0x3b, 0xa8, |
|
| 2141 |
- 0x0e, 0x0b, 0x9c, 0xba, 0x6d, 0x62, 0x56, 0xe6, 0x30, 0xa1, 0x42, 0x15, 0x89, 0x2d, 0xf2, 0x82, |
|
| 2142 |
- 0x80, 0x74, 0xcc, 0x25, 0x55, 0x29, 0x29, 0x08, 0x7d, 0x1b, 0x96, 0x82, 0x7e, 0x4f, 0x36, 0x0b, |
|
| 2143 |
- 0x9d, 0x7d, 0x4e, 0x22, 0x66, 0x5e, 0x94, 0xdf, 0x9b, 0xd8, 0x45, 0xd7, 0xa1, 0x12, 0xf4, 0x7b, |
|
| 2144 |
- 0x07, 0xe2, 0x85, 0x57, 0x68, 0x55, 0x89, 0x36, 0xbe, 0x89, 0x6e, 0xc1, 0xb2, 0xa0, 0x8b, 0x6f, |
|
| 2145 |
- 0x5b, 0x61, 0x2e, 0x4b, 0xcc, 0xe9, 0x03, 0xd4, 0x80, 0x0a, 0x79, 0xa9, 0x06, 0x02, 0x2d, 0xe9, |
|
| 2146 |
- 0xbf, 0x68, 0x0e, 0x7d, 0xc6, 0x49, 0xde, 0x43, 0xdf, 0xfd, 0x3e, 0xba, 0x0a, 0xeb, 0x4b, 0x28, |
|
| 2147 |
- 0x27, 0xef, 0x32, 0x85, 0xf6, 0xee, 0x78, 0xd7, 0x3e, 0x87, 0x6f, 0x25, 0x9a, 0x96, 0x01, 0x7c, |
|
| 2148 |
- 0xf3, 0x59, 0xd4, 0x71, 0x39, 0x49, 0xcb, 0xde, 0xd3, 0x59, 0xec, 0x0a, 0xe4, 0xf7, 0xd4, 0x65, |
|
| 2149 |
- 0xab, 0x99, 0xab, 0x86, 0xc4, 0x7e, 0x93, 0x88, 0x0b, 0xd0, 0x29, 0x5b, 0x43, 0x32, 0xeb, 0x79, |
|
| 2150 |
- 0x81, 0xeb, 0xc7, 0x83, 0xd7, 0x02, 0x1e, 0xc2, 0xf6, 0x55, 0xb0, 0xd2, 0x3e, 0xad, 0x0c, 0x65, |
|
| 2151 |
- 0xff, 0x29, 0x03, 0x30, 0xba, 0x1c, 0xf4, 0x21, 0x40, 0x8f, 0x74, 0x3c, 0xf7, 0x17, 0x7c, 0xd4, |
|
| 2152 |
- 0xb0, 0x16, 0xe5, 0x8e, 0xec, 0x5a, 0x47, 0xad, 0x45, 0xe6, 0x9d, 0x5b, 0x0b, 0x04, 0x39, 0x26, |
|
| 2153 |
- 0xe4, 0x55, 0x65, 0x90, 0x5c, 0xa3, 0xa7, 0x50, 0x72, 0x83, 0x20, 0xe4, 0x32, 0x4c, 0xe2, 0x66, |
|
| 2154 |
- 0xfe, 0xf6, 0x69, 0xee, 0xe4, 0x6c, 0x8d, 0xf0, 0x55, 0x14, 0x26, 0x39, 0x58, 0x0f, 0xa0, 0x3a, |
|
| 2155 |
- 0x89, 0x70, 0xae, 0x66, 0xf3, 0xef, 0x19, 0xb8, 0x38, 0x71, 0xad, 0xe8, 0x11, 0x54, 0x15, 0x34, |
|
| 2156 |
- 0x31, 0x80, 0x39, 0xcb, 0xf1, 0xa7, 0xa8, 0xd0, 0x43, 0x28, 0x6f, 0x71, 0x2e, 0x32, 0xad, 0xd2, |
|
| 2157 |
- 0x57, 0xb5, 0x98, 0xa7, 0x73, 0x19, 0xa3, 0x40, 0x8f, 0x46, 0x69, 0x2b, 0x3b, 0x6b, 0x90, 0x30, |
|
| 2158 |
- 0x21, 0x7f, 0x7a, 0xce, 0xb2, 0x7e, 0x36, 0x3b, 0x00, 0xb2, 0xca, 0x4a, 0xf5, 0xf1, 0x00, 0x38, |
|
| 2159 |
- 0x23, 0x6b, 0x8d, 0x6c, 0xf8, 0x07, 0x03, 0x0a, 0x71, 0x80, 0xa6, 0xce, 0x42, 0xee, 0x8f, 0xcf, |
|
| 2160 |
- 0x42, 0x6e, 0xcc, 0x7e, 0x34, 0xdf, 0xe7, 0x08, 0xe4, 0xe6, 0x8f, 0xe1, 0x83, 0xd4, 0x82, 0x05, |
|
| 2161 |
- 0x95, 0x60, 0x71, 0xff, 0x60, 0x0b, 0x1f, 0xb4, 0x9a, 0xd5, 0x0b, 0xa8, 0x0c, 0x85, 0xed, 0xa7, |
|
| 2162 |
- 0xbb, 0x7b, 0x4f, 0x5a, 0x07, 0xad, 0xaa, 0x21, 0x8e, 0x9a, 0x2d, 0xb1, 0x6e, 0x56, 0x33, 0xf5, |
|
| 2163 |
- 0xdf, 0xe6, 0x61, 0x71, 0x5b, 0xfd, 0xf3, 0x86, 0x0e, 0xa0, 0x38, 0xfc, 0x4b, 0x06, 0xd9, 0x29, |
|
| 2164 |
- 0xa6, 0x99, 0xf8, 0x6f, 0xc7, 0xfa, 0xe8, 0x54, 0x1c, 0xfd, 0xa0, 0x3d, 0x82, 0x05, 0xf9, 0xe7, |
|
| 2165 |
- 0x14, 0x4a, 0x19, 0x3b, 0x24, 0xff, 0xb5, 0xb2, 0x4e, 0xff, 0xb3, 0x67, 0xc3, 0x10, 0x9c, 0xe4, |
|
| 2166 |
- 0xcc, 0x26, 0x8d, 0x53, 0x72, 0x30, 0x6c, 0xad, 0x9e, 0x31, 0xec, 0x41, 0xbb, 0x90, 0xd7, 0x8d, |
|
| 2167 |
- 0x6c, 0x1a, 0x6a, 0x72, 0x32, 0x63, 0xad, 0xcd, 0x46, 0x50, 0xcc, 0x36, 0x0c, 0xb4, 0x3b, 0x9c, |
|
| 2168 |
- 0xf5, 0xa7, 0x89, 0x96, 0xec, 0x02, 0xac, 0x33, 0xce, 0xd7, 0x8d, 0x0d, 0x03, 0x7d, 0x01, 0xa5, |
|
| 2169 |
- 0x44, 0x9d, 0x8f, 0x52, 0xaa, 0xcc, 0xe9, 0xa6, 0xc1, 0xba, 0x71, 0x06, 0x96, 0xd6, 0xbc, 0x05, |
|
| 2170 |
- 0x39, 0x99, 0x00, 0x52, 0x8c, 0x9d, 0x68, 0x03, 0xd2, 0xc4, 0x1c, 0x6b, 0x0b, 0x0e, 0x55, 0xe3, |
|
| 2171 |
- 0x42, 0x82, 0xa4, 0xf7, 0xa1, 0x1b, 0x67, 0xd5, 0x1b, 0x33, 0xdd, 0x66, 0xca, 0x89, 0x37, 0x0c, |
|
| 2172 |
- 0x14, 0x02, 0x9a, 0x4e, 0xfa, 0xe8, 0xbb, 0x29, 0x5e, 0x32, 0xeb, 0x55, 0xb2, 0x6e, 0xcd, 0x87, |
|
| 2173 |
- 0xac, 0x94, 0x6a, 0x94, 0x5f, 0xbd, 0x59, 0x31, 0xfe, 0xf9, 0x66, 0xc5, 0xf8, 0xf7, 0x9b, 0x15, |
|
| 2174 |
- 0xe3, 0x30, 0x2f, 0x2b, 0xc9, 0xef, 0xfd, 0x3f, 0x00, 0x00, 0xff, 0xff, 0x12, 0xae, 0x41, 0x43, |
|
| 2175 |
- 0x99, 0x1e, 0x00, 0x00, |
|
| 2033 |
+ 0x37, 0xe2, 0xc4, 0x89, 0x2a, 0x2e, 0x14, 0x17, 0x8a, 0x0b, 0x77, 0x4e, 0x9c, 0x39, 0x73, 0xa0, |
|
| 2034 |
+ 0x2a, 0x47, 0xce, 0x7b, 0xc8, 0x52, 0xf9, 0x01, 0x14, 0x47, 0x8e, 0xd4, 0xfb, 0x18, 0x69, 0x24, |
|
| 2035 |
+ 0x8d, 0x6c, 0x39, 0xc9, 0x49, 0xaf, 0xdf, 0xeb, 0xee, 0xe9, 0xee, 0xd7, 0xdd, 0xaf, 0xbb, 0x05, |
|
| 2036 |
+ 0x95, 0x76, 0x18, 0x70, 0x1a, 0xfa, 0x4e, 0x44, 0x43, 0x1e, 0xa2, 0x6a, 0x2f, 0x3c, 0x1c, 0x38, |
|
| 2037 |
+ 0x87, 0x7d, 0xcf, 0xef, 0x1c, 0x7b, 0xdc, 0x39, 0xf9, 0xd8, 0xaa, 0x77, 0x3d, 0xfe, 0xa2, 0x7f, |
|
| 2038 |
+ 0xe8, 0xb4, 0xc3, 0x5e, 0xad, 0x1b, 0x76, 0xc3, 0x5a, 0x37, 0x0c, 0xbb, 0x3e, 0x71, 0x23, 0x8f, |
|
| 2039 |
+ 0xe9, 0x65, 0x8d, 0x46, 0xed, 0x1a, 0xe3, 0x2e, 0xef, 0x33, 0xc5, 0xc5, 0xba, 0x3d, 0x49, 0x23, |
|
| 2040 |
+ 0xb7, 0x0f, 0xfb, 0x47, 0x12, 0x92, 0x80, 0x5c, 0x69, 0xf4, 0x5a, 0x02, 0x5d, 0x7c, 0xbf, 0x16, |
|
| 2041 |
+ 0x7f, 0xbf, 0xe6, 0x46, 0x5e, 0x8d, 0x0f, 0x22, 0xc2, 0x6a, 0x5f, 0x85, 0xf4, 0x98, 0x50, 0x4d, |
|
| 2042 |
+ 0x70, 0x6b, 0x26, 0x01, 0x0b, 0xfd, 0x13, 0x42, 0x6b, 0xd1, 0x61, 0x2d, 0x8c, 0x62, 0x69, 0xee, |
|
| 2043 |
+ 0x9c, 0x82, 0xdd, 0xa7, 0x6d, 0x12, 0x85, 0xbe, 0xd7, 0x1e, 0x08, 0x1a, 0xb5, 0xd2, 0x64, 0xab, |
|
| 2044 |
+ 0x5a, 0xbb, 0xa1, 0xec, 0xdc, 0xeb, 0x11, 0xc6, 0xdd, 0x5e, 0xa4, 0x10, 0xec, 0xdf, 0x19, 0x50, |
|
| 2045 |
+ 0xde, 0xa3, 0xfd, 0x80, 0x60, 0xf2, 0xeb, 0x3e, 0x61, 0x1c, 0x5d, 0x81, 0xfc, 0x91, 0xe7, 0x73, |
|
| 2046 |
+ 0x42, 0x4d, 0x63, 0x2d, 0xbb, 0x5e, 0xc4, 0x1a, 0x42, 0x55, 0xc8, 0xba, 0xbe, 0x6f, 0x66, 0xd6, |
|
| 2047 |
+ 0x8c, 0xf5, 0x02, 0x16, 0x4b, 0xb4, 0x0e, 0xe5, 0x63, 0x42, 0xa2, 0x66, 0x9f, 0xba, 0xdc, 0x0b, |
|
| 2048 |
+ 0x03, 0x33, 0xbb, 0x66, 0xac, 0x67, 0x1b, 0xb9, 0x57, 0xaf, 0x57, 0x0d, 0x3c, 0x76, 0x82, 0x6c, |
|
| 2049 |
+ 0x28, 0x0a, 0xb8, 0x31, 0xe0, 0x84, 0x99, 0xb9, 0x04, 0xda, 0x68, 0xdb, 0xbe, 0x09, 0xd5, 0xa6, |
|
| 2050 |
+ 0xc7, 0x8e, 0x9f, 0x31, 0xb7, 0x7b, 0x96, 0x2c, 0xf6, 0x63, 0x58, 0x4e, 0xe0, 0xb2, 0x28, 0x0c, |
|
| 2051 |
+ 0x18, 0x41, 0x77, 0x20, 0x4f, 0x49, 0x3b, 0xa4, 0x1d, 0x89, 0x5c, 0xaa, 0x7f, 0xe8, 0x4c, 0xba, |
|
| 2052 |
+ 0x81, 0xa3, 0x09, 0x04, 0x12, 0xd6, 0xc8, 0xf6, 0x9f, 0xb3, 0x50, 0x4a, 0xec, 0xa3, 0x25, 0xc8, |
|
| 2053 |
+ 0xec, 0x34, 0x4d, 0x63, 0xcd, 0x58, 0x2f, 0xe2, 0xcc, 0x4e, 0x13, 0x99, 0xb0, 0xb8, 0xdb, 0xe7, |
|
| 2054 |
+ 0xee, 0xa1, 0x4f, 0xb4, 0xee, 0x31, 0x88, 0x2e, 0xc3, 0xc2, 0x4e, 0xf0, 0x8c, 0x11, 0xa9, 0x78, |
|
| 2055 |
+ 0x01, 0x2b, 0x00, 0x21, 0xc8, 0xed, 0x7b, 0xbf, 0x21, 0x4a, 0x4d, 0x2c, 0xd7, 0xc8, 0x82, 0xfc, |
|
| 2056 |
+ 0x9e, 0x4b, 0x49, 0xc0, 0xcd, 0x05, 0xc1, 0xb7, 0x91, 0x31, 0x0d, 0xac, 0x77, 0x50, 0x03, 0x8a, |
|
| 2057 |
+ 0xdb, 0x94, 0xb8, 0x9c, 0x74, 0xb6, 0xb8, 0x99, 0x5f, 0x33, 0xd6, 0x4b, 0x75, 0xcb, 0x51, 0xb7, |
|
| 2058 |
+ 0xe6, 0xc4, 0xb7, 0xe6, 0x1c, 0xc4, 0xb7, 0xd6, 0x28, 0xbc, 0x7a, 0xbd, 0x7a, 0xe1, 0x8f, 0xdf, |
|
| 2059 |
+ 0x08, 0xdb, 0x0d, 0xc9, 0xd0, 0x43, 0x80, 0x27, 0x2e, 0xe3, 0xcf, 0x98, 0x64, 0xb2, 0x78, 0x26, |
|
| 2060 |
+ 0x93, 0x9c, 0x64, 0x90, 0xa0, 0x41, 0x2b, 0x00, 0xd2, 0x08, 0xdb, 0x61, 0x3f, 0xe0, 0x66, 0x41, |
|
| 2061 |
+ 0xca, 0x9e, 0xd8, 0x41, 0x6b, 0x50, 0x6a, 0x12, 0xd6, 0xa6, 0x5e, 0x24, 0xaf, 0xba, 0x28, 0xcd, |
|
| 2062 |
+ 0x93, 0xdc, 0x12, 0x1c, 0x94, 0x05, 0x0f, 0x06, 0x11, 0x31, 0x41, 0x22, 0x24, 0x76, 0xc4, 0x5d, |
|
| 2063 |
+ 0xee, 0xbf, 0x70, 0x29, 0xe9, 0x98, 0x25, 0x69, 0x2e, 0x0d, 0x09, 0xfb, 0x2a, 0x4b, 0x30, 0xb3, |
|
| 2064 |
+ 0x2c, 0x2f, 0x39, 0x06, 0xed, 0xdf, 0x16, 0xa0, 0xbc, 0x2f, 0x42, 0x21, 0x76, 0x87, 0x2a, 0x64, |
|
| 2065 |
+ 0x31, 0x39, 0xd2, 0x77, 0x23, 0x96, 0xc8, 0x01, 0x68, 0x92, 0x23, 0x2f, 0xf0, 0xa4, 0x54, 0x19, |
|
| 2066 |
+ 0xa9, 0xf8, 0x92, 0x13, 0x1d, 0x3a, 0xa3, 0x5d, 0x9c, 0xc0, 0x40, 0x0e, 0xa0, 0xd6, 0xcb, 0x28, |
|
| 2067 |
+ 0xa4, 0x9c, 0xd0, 0x26, 0x89, 0x28, 0x69, 0x0b, 0x03, 0xca, 0xfb, 0x2b, 0xe2, 0x94, 0x13, 0xd4, |
|
| 2068 |
+ 0x87, 0x6f, 0xc5, 0xbb, 0x5b, 0x9c, 0x53, 0x96, 0x20, 0xca, 0x49, 0x27, 0xbb, 0x3f, 0xed, 0x64, |
|
| 2069 |
+ 0x49, 0x91, 0x9d, 0x19, 0xd4, 0xad, 0x80, 0xd3, 0x01, 0x9e, 0xc5, 0x5b, 0xd8, 0x64, 0x9f, 0x30, |
|
| 2070 |
+ 0x26, 0x74, 0x92, 0x0e, 0x83, 0x63, 0x10, 0x59, 0x50, 0xf8, 0x19, 0x0d, 0x03, 0x4e, 0x82, 0x8e, |
|
| 2071 |
+ 0x74, 0x96, 0x22, 0x1e, 0xc2, 0xe8, 0x39, 0x54, 0xe2, 0xb5, 0x64, 0x68, 0x2e, 0x4a, 0x11, 0x3f, |
|
| 2072 |
+ 0x3e, 0x43, 0xc4, 0x31, 0x1a, 0x25, 0xd8, 0x38, 0x1f, 0xb4, 0x09, 0x0b, 0xdb, 0x6e, 0xfb, 0x05, |
|
| 2073 |
+ 0x91, 0x7e, 0x51, 0xaa, 0xaf, 0x4c, 0x33, 0x94, 0xc7, 0x4f, 0xa5, 0x23, 0x30, 0x19, 0xda, 0x17, |
|
| 2074 |
+ 0xb0, 0x22, 0x41, 0xbf, 0x84, 0x72, 0x2b, 0xe0, 0x1e, 0xf7, 0x49, 0x4f, 0xde, 0x71, 0x51, 0xdc, |
|
| 2075 |
+ 0x71, 0x63, 0xf3, 0xeb, 0xd7, 0xab, 0x3f, 0x9a, 0x99, 0xd1, 0xfa, 0xdc, 0xf3, 0x6b, 0x24, 0x41, |
|
| 2076 |
+ 0xe5, 0x24, 0x58, 0xe0, 0x31, 0x7e, 0xe8, 0x0b, 0x58, 0x8a, 0x85, 0xdd, 0x09, 0xa2, 0x3e, 0x67, |
|
| 2077 |
+ 0x26, 0x48, 0xad, 0xeb, 0x73, 0x6a, 0xad, 0x88, 0x94, 0xda, 0x13, 0x9c, 0x84, 0xb1, 0x77, 0x02, |
|
| 2078 |
+ 0x4e, 0x68, 0xe0, 0xfa, 0xda, 0x69, 0x87, 0x30, 0xda, 0x11, 0xbe, 0x29, 0x12, 0xef, 0x9e, 0x4c, |
|
| 2079 |
+ 0xb7, 0x66, 0x59, 0x9a, 0xe6, 0xc6, 0xf4, 0x57, 0x93, 0xe9, 0xd9, 0x51, 0xc8, 0x78, 0x8c, 0x14, |
|
| 2080 |
+ 0xdd, 0x83, 0x62, 0xec, 0x08, 0xcc, 0xac, 0x48, 0xe9, 0xad, 0x69, 0x3e, 0x31, 0x0a, 0x1e, 0x21, |
|
| 2081 |
+ 0x5b, 0x8f, 0xe1, 0xea, 0x69, 0x0e, 0x26, 0x02, 0xe6, 0x98, 0x0c, 0xe2, 0x80, 0x39, 0x26, 0x03, |
|
| 2082 |
+ 0x91, 0xb3, 0x4e, 0x5c, 0xbf, 0xaf, 0x72, 0x59, 0x11, 0x2b, 0x60, 0x33, 0x73, 0xcf, 0xb0, 0x1e, |
|
| 2083 |
+ 0x02, 0x9a, 0xf6, 0x84, 0x73, 0x71, 0xf8, 0x0c, 0x2e, 0xa5, 0x58, 0x35, 0x85, 0xc5, 0xf5, 0x24, |
|
| 2084 |
+ 0x8b, 0xe9, 0x80, 0x1d, 0xb1, 0xb4, 0xff, 0x96, 0x85, 0x72, 0xd2, 0xb7, 0xd0, 0x06, 0x5c, 0x52, |
|
| 2085 |
+ 0x1a, 0x63, 0x72, 0x94, 0x08, 0x46, 0xc5, 0x3c, 0xed, 0x08, 0xd5, 0xe1, 0xf2, 0x4e, 0x4f, 0x6f, |
|
| 2086 |
+ 0x27, 0xe3, 0x37, 0x23, 0x93, 0x4d, 0xea, 0x19, 0x0a, 0xe1, 0x03, 0xc5, 0x6a, 0x32, 0xe8, 0xb3, |
|
| 2087 |
+ 0xf2, 0x76, 0x3e, 0x39, 0x3d, 0x00, 0x9c, 0x54, 0x5a, 0xe5, 0x62, 0xe9, 0x7c, 0xd1, 0x4f, 0x60, |
|
| 2088 |
+ 0x51, 0x1d, 0x30, 0x9d, 0x57, 0x3e, 0x3a, 0xfd, 0x13, 0x8a, 0x59, 0x4c, 0x23, 0xc8, 0x95, 0x1e, |
|
| 2089 |
+ 0xcc, 0x5c, 0x38, 0x07, 0xb9, 0xa6, 0xb1, 0x1e, 0x81, 0x35, 0x5b, 0xe4, 0xf3, 0xb8, 0x80, 0xfd, |
|
| 2090 |
+ 0x57, 0x03, 0x96, 0xa7, 0x3e, 0x24, 0x9e, 0x44, 0xf9, 0x28, 0x28, 0x16, 0x72, 0x8d, 0x9a, 0xb0, |
|
| 2091 |
+ 0xa0, 0x92, 0x54, 0x46, 0x0a, 0xec, 0xcc, 0x21, 0xb0, 0x93, 0xc8, 0x50, 0x8a, 0xd8, 0xba, 0x07, |
|
| 2092 |
+ 0xf0, 0x76, 0xce, 0x6a, 0xff, 0xdd, 0x80, 0x8a, 0x4e, 0x08, 0xba, 0x7e, 0x70, 0xa1, 0x3a, 0x8c, |
|
| 2093 |
+ 0x31, 0xbd, 0xa7, 0x2b, 0x89, 0x3b, 0x33, 0x73, 0x89, 0x42, 0x73, 0x26, 0xe9, 0x94, 0x8c, 0x53, |
|
| 2094 |
+ 0xec, 0xac, 0xed, 0xd8, 0xaf, 0x26, 0x50, 0xcf, 0x25, 0xf9, 0x35, 0xa8, 0xec, 0xcb, 0x3a, 0x75, |
|
| 2095 |
+ 0xe6, 0xb3, 0x68, 0xff, 0xd7, 0x80, 0xa5, 0x18, 0x47, 0x6b, 0xf7, 0x43, 0x28, 0x9c, 0x10, 0xca, |
|
| 2096 |
+ 0xc9, 0x4b, 0xc2, 0xb4, 0x56, 0xe6, 0xb4, 0x56, 0x9f, 0x4b, 0x0c, 0x3c, 0xc4, 0x44, 0x9b, 0x50, |
|
| 2097 |
+ 0x50, 0x35, 0x31, 0x89, 0x2f, 0x6a, 0x65, 0x16, 0x95, 0xfe, 0xde, 0x10, 0x1f, 0xd5, 0x20, 0xe7, |
|
| 2098 |
+ 0x87, 0x5d, 0xa6, 0x63, 0xe6, 0x3b, 0xb3, 0xe8, 0x9e, 0x84, 0x5d, 0x2c, 0x11, 0xd1, 0x7d, 0x28, |
|
| 2099 |
+ 0x7c, 0xe5, 0xd2, 0xc0, 0x0b, 0xba, 0x71, 0x14, 0xac, 0xce, 0x22, 0x7a, 0xae, 0xf0, 0xf0, 0x90, |
|
| 2100 |
+ 0x40, 0x94, 0x71, 0x79, 0x75, 0x86, 0x1e, 0x43, 0xbe, 0xe3, 0x75, 0x09, 0xe3, 0xca, 0x24, 0x8d, |
|
| 2101 |
+ 0xba, 0x78, 0x8f, 0xbe, 0x7e, 0xbd, 0x7a, 0x33, 0xf1, 0xe0, 0x84, 0x11, 0x09, 0x44, 0xd3, 0xe0, |
|
| 2102 |
+ 0x7a, 0x01, 0xa1, 0xa2, 0x07, 0xb8, 0xad, 0x48, 0x9c, 0xa6, 0xfc, 0xc1, 0x9a, 0x83, 0xe0, 0xe5, |
|
| 2103 |
+ 0xa9, 0x67, 0x45, 0xe6, 0x8b, 0xb7, 0xe3, 0xa5, 0x38, 0x88, 0x30, 0x08, 0xdc, 0x1e, 0xd1, 0xe5, |
|
| 2104 |
+ 0x86, 0x5c, 0x8b, 0xaa, 0xa8, 0x2d, 0xfc, 0xbc, 0x23, 0xeb, 0xc5, 0x02, 0xd6, 0x10, 0xda, 0x84, |
|
| 2105 |
+ 0x45, 0xc6, 0x5d, 0x2a, 0x72, 0xce, 0xc2, 0x9c, 0xe5, 0x5c, 0x4c, 0x80, 0x1e, 0x40, 0xb1, 0x1d, |
|
| 2106 |
+ 0xf6, 0x22, 0x9f, 0x08, 0xea, 0xfc, 0x9c, 0xd4, 0x23, 0x12, 0xe1, 0x7a, 0x84, 0xd2, 0x90, 0xca, |
|
| 2107 |
+ 0x42, 0xb2, 0x88, 0x15, 0x80, 0xee, 0x42, 0x25, 0xa2, 0x61, 0x97, 0x12, 0xc6, 0x3e, 0xa5, 0x61, |
|
| 2108 |
+ 0x3f, 0xd2, 0xc5, 0xc0, 0xb2, 0x48, 0xde, 0x7b, 0xc9, 0x03, 0x3c, 0x8e, 0x67, 0xff, 0x27, 0x03, |
|
| 2109 |
+ 0xe5, 0xa4, 0x8b, 0x4c, 0x55, 0xd8, 0x8f, 0x21, 0xaf, 0x1c, 0x4e, 0xf9, 0xfa, 0xdb, 0xd9, 0x58, |
|
| 2110 |
+ 0x71, 0x48, 0xb5, 0xb1, 0x09, 0x8b, 0xed, 0x3e, 0x95, 0xe5, 0xb7, 0x2a, 0xca, 0x63, 0x50, 0x68, |
|
| 2111 |
+ 0xca, 0x43, 0xee, 0xfa, 0xd2, 0xc6, 0x59, 0xac, 0x00, 0x51, 0x91, 0x0f, 0xbb, 0xa4, 0xf3, 0x55, |
|
| 2112 |
+ 0xe4, 0x43, 0xb2, 0xe4, 0xfd, 0x2d, 0xbe, 0xd3, 0xfd, 0x15, 0xce, 0x7d, 0x7f, 0xf6, 0x3f, 0x0d, |
|
| 2113 |
+ 0x28, 0x0e, 0x63, 0x2b, 0x61, 0x5d, 0xe3, 0x9d, 0xad, 0x3b, 0x66, 0x99, 0xcc, 0xdb, 0x59, 0xe6, |
|
| 2114 |
+ 0x0a, 0xe4, 0x19, 0xa7, 0xc4, 0xed, 0xa9, 0x7e, 0x11, 0x6b, 0x48, 0x64, 0xb1, 0x1e, 0xeb, 0xca, |
|
| 2115 |
+ 0x1b, 0x2a, 0x63, 0xb1, 0xb4, 0xff, 0x67, 0x40, 0x65, 0x2c, 0xdc, 0xdf, 0xab, 0x2e, 0x97, 0x61, |
|
| 2116 |
+ 0xc1, 0x27, 0x27, 0x44, 0x75, 0xb4, 0x59, 0xac, 0x00, 0xb1, 0xcb, 0x5e, 0x84, 0x94, 0x4b, 0xe1, |
|
| 2117 |
+ 0xca, 0x58, 0x01, 0x42, 0xe6, 0x0e, 0xe1, 0xae, 0xe7, 0xcb, 0xbc, 0x54, 0xc6, 0x1a, 0x12, 0x32, |
|
| 2118 |
+ 0xf7, 0xa9, 0xaf, 0x6b, 0x74, 0xb1, 0x44, 0x36, 0xe4, 0xbc, 0xe0, 0x28, 0xd4, 0x6e, 0x23, 0x2b, |
|
| 2119 |
+ 0x1b, 0x55, 0xeb, 0xed, 0x04, 0x47, 0x21, 0x96, 0x67, 0xe8, 0x1a, 0xe4, 0xa9, 0x1b, 0x74, 0x49, |
|
| 2120 |
+ 0x5c, 0xa0, 0x17, 0x05, 0x16, 0x16, 0x3b, 0x58, 0x1f, 0xd8, 0x36, 0x94, 0x65, 0x57, 0xbc, 0x4b, |
|
| 2121 |
+ 0x98, 0xe8, 0xc1, 0x84, 0x5b, 0x77, 0x5c, 0xee, 0x4a, 0xb5, 0xcb, 0x58, 0xae, 0xed, 0x5b, 0x80, |
|
| 2122 |
+ 0x9e, 0x78, 0x8c, 0x3f, 0x97, 0x33, 0x05, 0x76, 0x56, 0xcb, 0xbc, 0x0f, 0x97, 0xc6, 0xb0, 0xf5, |
|
| 2123 |
+ 0xb3, 0xf0, 0xe3, 0x89, 0xa6, 0xf9, 0xfa, 0x74, 0xc6, 0x95, 0xa3, 0x0b, 0x47, 0x11, 0x4e, 0xf4, |
|
| 2124 |
+ 0xce, 0x15, 0x28, 0x49, 0xbd, 0xd4, 0xb7, 0x6d, 0x17, 0xca, 0x0a, 0xd4, 0xcc, 0x3f, 0x83, 0x8b, |
|
| 2125 |
+ 0x31, 0xa3, 0xcf, 0x09, 0x95, 0xed, 0x8c, 0x21, 0xed, 0xf2, 0xbd, 0x59, 0x5f, 0x69, 0x8c, 0xa3, |
|
| 2126 |
+ 0xe3, 0x49, 0x7a, 0x9b, 0xc0, 0x25, 0x89, 0xf3, 0xc8, 0x63, 0x3c, 0xa4, 0x83, 0x58, 0xeb, 0x15, |
|
| 2127 |
+ 0x80, 0xad, 0x36, 0xf7, 0x4e, 0xc8, 0xd3, 0xc0, 0x57, 0xcf, 0x68, 0x01, 0x27, 0x76, 0xe2, 0x27, |
|
| 2128 |
+ 0x32, 0x33, 0xea, 0x1c, 0xaf, 0x42, 0xb1, 0xe5, 0x52, 0x7f, 0xd0, 0x7a, 0xe9, 0x71, 0xdd, 0xc0, |
|
| 2129 |
+ 0x8f, 0x36, 0xec, 0x3f, 0x18, 0xb0, 0x9c, 0xfc, 0x4e, 0xeb, 0x44, 0xa4, 0x8b, 0xfb, 0x90, 0xe3, |
|
| 2130 |
+ 0x71, 0x1d, 0xb3, 0x94, 0xa6, 0xc4, 0x14, 0x89, 0x28, 0x75, 0xb0, 0x24, 0x4a, 0x58, 0x5a, 0x05, |
|
| 2131 |
+ 0xce, 0xf5, 0xd3, 0xc9, 0x27, 0x2c, 0xfd, 0x4d, 0x11, 0xd0, 0xf4, 0x71, 0x4a, 0x47, 0x9c, 0x6c, |
|
| 2132 |
+ 0x10, 0x33, 0x13, 0x0d, 0xe2, 0x97, 0x93, 0x0d, 0xa2, 0x7a, 0x9a, 0xef, 0xce, 0x23, 0xc9, 0x1c, |
|
| 2133 |
+ 0x6d, 0xe2, 0x58, 0x1f, 0x93, 0x3b, 0x47, 0x1f, 0x83, 0xd6, 0xe3, 0x17, 0x47, 0xbd, 0x75, 0x28, |
|
| 2134 |
+ 0xce, 0x29, 0x34, 0x6a, 0x3b, 0xba, 0xae, 0xd0, 0xaf, 0xd0, 0x83, 0xf3, 0x4d, 0x4b, 0x72, 0x93, |
|
| 2135 |
+ 0x93, 0x92, 0x06, 0x94, 0xb6, 0xe3, 0x44, 0x79, 0x8e, 0x51, 0x49, 0x92, 0x08, 0x6d, 0xe8, 0xc2, |
|
| 2136 |
+ 0x46, 0xa5, 0xe6, 0xab, 0xd3, 0x2a, 0xc6, 0x63, 0x91, 0x90, 0xea, 0xca, 0xe6, 0x28, 0xa5, 0xb4, |
|
| 2137 |
+ 0x2c, 0x4a, 0x03, 0x6d, 0xce, 0x65, 0xfb, 0x39, 0xeb, 0x4b, 0xf4, 0x09, 0xe4, 0x31, 0x61, 0x7d, |
|
| 2138 |
+ 0x9f, 0xcb, 0xf9, 0x4b, 0xa9, 0x7e, 0x6d, 0x06, 0x77, 0x85, 0x24, 0x63, 0x55, 0x13, 0xa0, 0x9f, |
|
| 2139 |
+ 0xc3, 0xa2, 0x5a, 0x31, 0xb3, 0x34, 0x6b, 0x6c, 0x90, 0x22, 0x99, 0xa6, 0xd1, 0x0d, 0x85, 0x86, |
|
| 2140 |
+ 0x44, 0x38, 0x7e, 0x4a, 0x02, 0xa2, 0xe7, 0x82, 0xa2, 0x35, 0x5e, 0xc0, 0x89, 0x1d, 0x54, 0x87, |
|
| 2141 |
+ 0x05, 0x4e, 0xdd, 0x36, 0x31, 0x2b, 0x73, 0x98, 0x50, 0xa1, 0x8a, 0xc4, 0x16, 0x79, 0x41, 0x40, |
|
| 2142 |
+ 0x3a, 0xe6, 0x92, 0xaa, 0x94, 0x14, 0x84, 0xbe, 0x0b, 0x4b, 0x41, 0xbf, 0x27, 0x9b, 0x85, 0xce, |
|
| 2143 |
+ 0x3e, 0x27, 0x11, 0x33, 0x2f, 0xca, 0xef, 0x4d, 0xec, 0xa2, 0xeb, 0x50, 0x09, 0xfa, 0xbd, 0x03, |
|
| 2144 |
+ 0xf1, 0xc2, 0x2b, 0xb4, 0xaa, 0x44, 0x1b, 0xdf, 0x44, 0xb7, 0x60, 0x59, 0xd0, 0xc5, 0xb7, 0xad, |
|
| 2145 |
+ 0x30, 0x97, 0x25, 0xe6, 0xf4, 0x01, 0x6a, 0x40, 0x85, 0xbc, 0x54, 0x03, 0x81, 0x96, 0xf4, 0x5f, |
|
| 2146 |
+ 0x34, 0x87, 0x3e, 0xe3, 0x24, 0x68, 0x0d, 0x4a, 0x41, 0xbf, 0xf7, 0x3c, 0x2e, 0x7c, 0x2f, 0xc9, |
|
| 2147 |
+ 0x6f, 0x25, 0xb7, 0xde, 0x43, 0x67, 0xfe, 0x3e, 0xfa, 0x0e, 0xeb, 0x4b, 0x28, 0x27, 0x6f, 0x3b, |
|
| 2148 |
+ 0x85, 0xf6, 0xee, 0x78, 0x5f, 0x3f, 0x87, 0xf7, 0x25, 0xda, 0x9a, 0x01, 0x7c, 0xfb, 0x59, 0xd4, |
|
| 2149 |
+ 0x71, 0x39, 0x49, 0xcb, 0xef, 0xd3, 0x79, 0xee, 0x0a, 0xe4, 0xf7, 0x94, 0x3b, 0xa8, 0xa9, 0xac, |
|
| 2150 |
+ 0x86, 0xc4, 0x7e, 0x93, 0x88, 0x2b, 0xd2, 0x49, 0x5d, 0x43, 0x32, 0x2f, 0x7a, 0x81, 0xeb, 0xc7, |
|
| 2151 |
+ 0xa3, 0xd9, 0x02, 0x1e, 0xc2, 0xf6, 0x55, 0xb0, 0xd2, 0x3e, 0xad, 0x0c, 0x65, 0xff, 0x25, 0x03, |
|
| 2152 |
+ 0x30, 0xba, 0x3e, 0xf4, 0x21, 0x40, 0x8f, 0x74, 0x3c, 0xf7, 0x57, 0x7c, 0xd4, 0xd2, 0x16, 0xe5, |
|
| 2153 |
+ 0x8e, 0xec, 0x6b, 0x47, 0xcd, 0x47, 0xe6, 0x9d, 0x9b, 0x0f, 0x04, 0x39, 0x26, 0xe4, 0x55, 0x85, |
|
| 2154 |
+ 0x92, 0x5c, 0xa3, 0xa7, 0x50, 0x72, 0x83, 0x20, 0xe4, 0x32, 0x90, 0xe2, 0x76, 0xff, 0xf6, 0x69, |
|
| 2155 |
+ 0x0e, 0xe7, 0x6c, 0x8d, 0xf0, 0x55, 0x9c, 0x26, 0x39, 0x58, 0x0f, 0xa0, 0x3a, 0x89, 0x70, 0xae, |
|
| 2156 |
+ 0x76, 0xf4, 0x1f, 0x19, 0xb8, 0x38, 0x71, 0xad, 0xe8, 0x11, 0x54, 0x15, 0x34, 0x31, 0xa2, 0x39, |
|
| 2157 |
+ 0x2b, 0x34, 0xa6, 0xa8, 0xd0, 0x43, 0x28, 0x6f, 0x71, 0x2e, 0x72, 0xb1, 0xd2, 0x57, 0x35, 0xa1, |
|
| 2158 |
+ 0xa7, 0x73, 0x19, 0xa3, 0x40, 0x8f, 0x46, 0x89, 0x2d, 0x3b, 0x6b, 0xd4, 0x30, 0x21, 0x7f, 0x7a, |
|
| 2159 |
+ 0x56, 0xb3, 0x7e, 0x31, 0x3b, 0x00, 0xb2, 0xca, 0x4a, 0xf5, 0xf1, 0x00, 0x38, 0x23, 0xaf, 0x8d, |
|
| 2160 |
+ 0x6c, 0xf8, 0x27, 0x03, 0x0a, 0x71, 0x80, 0xa6, 0x4e, 0x4b, 0xee, 0x8f, 0x4f, 0x4b, 0x6e, 0xcc, |
|
| 2161 |
+ 0x7e, 0x56, 0xdf, 0xe7, 0x90, 0xe4, 0xe6, 0x4f, 0xe1, 0x83, 0xd4, 0x92, 0x06, 0x95, 0x60, 0x71, |
|
| 2162 |
+ 0xff, 0x60, 0x0b, 0x1f, 0xb4, 0x9a, 0xd5, 0x0b, 0xa8, 0x0c, 0x85, 0xed, 0xa7, 0xbb, 0x7b, 0x4f, |
|
| 2163 |
+ 0x5a, 0x07, 0xad, 0xaa, 0x21, 0x8e, 0x9a, 0x2d, 0xb1, 0x6e, 0x56, 0x33, 0xf5, 0xdf, 0xe7, 0x61, |
|
| 2164 |
+ 0x71, 0x5b, 0xfd, 0x37, 0x87, 0x0e, 0xa0, 0x38, 0xfc, 0xd3, 0x06, 0xd9, 0x29, 0xa6, 0x99, 0xf8, |
|
| 2165 |
+ 0xf7, 0xc7, 0xfa, 0xe8, 0x54, 0x1c, 0xfd, 0xe4, 0x3d, 0x82, 0x05, 0xf9, 0xf7, 0x15, 0x4a, 0x19, |
|
| 2166 |
+ 0x4c, 0x24, 0xff, 0xd7, 0xb2, 0x4e, 0xff, 0x3b, 0x68, 0xc3, 0x10, 0x9c, 0xe4, 0x54, 0x27, 0x8d, |
|
| 2167 |
+ 0x53, 0x72, 0x74, 0x6c, 0xad, 0x9e, 0x31, 0x0e, 0x42, 0xbb, 0x90, 0xd7, 0xad, 0x6e, 0x1a, 0x6a, |
|
| 2168 |
+ 0x72, 0x76, 0x63, 0xad, 0xcd, 0x46, 0x50, 0xcc, 0x36, 0x0c, 0xb4, 0x3b, 0xfc, 0x37, 0x20, 0x4d, |
|
| 2169 |
+ 0xb4, 0x64, 0x9f, 0x60, 0x9d, 0x71, 0xbe, 0x6e, 0x6c, 0x18, 0xe8, 0x0b, 0x28, 0x25, 0x3a, 0x01, |
|
| 2170 |
+ 0x94, 0x52, 0x87, 0x4e, 0xb7, 0x15, 0xd6, 0x8d, 0x33, 0xb0, 0xb4, 0xe6, 0x2d, 0xc8, 0xc9, 0x04, |
|
| 2171 |
+ 0x90, 0x62, 0xec, 0x44, 0xa3, 0x90, 0x26, 0xe6, 0x58, 0xe3, 0x70, 0xa8, 0x5a, 0x1b, 0x12, 0x24, |
|
| 2172 |
+ 0xbd, 0x0f, 0xdd, 0x38, 0xab, 0x22, 0x99, 0xe9, 0x36, 0x53, 0x4e, 0xbc, 0x61, 0xa0, 0x10, 0xd0, |
|
| 2173 |
+ 0x74, 0xd2, 0x47, 0xdf, 0x4f, 0xf1, 0x92, 0x59, 0xaf, 0x92, 0x75, 0x6b, 0x3e, 0x64, 0xa5, 0x54, |
|
| 2174 |
+ 0xa3, 0xfc, 0xea, 0xcd, 0x8a, 0xf1, 0xaf, 0x37, 0x2b, 0xc6, 0xbf, 0xdf, 0xac, 0x18, 0x87, 0x79, |
|
| 2175 |
+ 0x59, 0x6b, 0xfe, 0xe0, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0xaa, 0x06, 0xac, 0x18, 0xbb, 0x1e, |
|
| 2176 |
+ 0x00, 0x00, |
|
| 2176 | 2177 |
} |
| 2177 | 2178 |
|
| 2178 | 2179 |
// Reference imports to suppress errors if they are not otherwise used. |
| ... | ... |
@@ -4030,6 +4039,13 @@ func (m *BuildHistoryRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
| 4030 | 4030 |
i -= len(m.XXX_unrecognized) |
| 4031 | 4031 |
copy(dAtA[i:], m.XXX_unrecognized) |
| 4032 | 4032 |
} |
| 4033 |
+ if m.NumWarnings != 0 {
|
|
| 4034 |
+ i = encodeVarintControl(dAtA, i, uint64(m.NumWarnings)) |
|
| 4035 |
+ i-- |
|
| 4036 |
+ dAtA[i] = 0x1 |
|
| 4037 |
+ i-- |
|
| 4038 |
+ dAtA[i] = 0x98 |
|
| 4039 |
+ } |
|
| 4033 | 4040 |
if m.ExternalError != nil {
|
| 4034 | 4041 |
{
|
| 4035 | 4042 |
size, err := m.ExternalError.MarshalToSizedBuffer(dAtA[:i]) |
| ... | ... |
@@ -5242,6 +5258,9 @@ func (m *BuildHistoryRecord) Size() (n int) {
|
| 5242 | 5242 |
l = m.ExternalError.Size() |
| 5243 | 5243 |
n += 2 + l + sovControl(uint64(l)) |
| 5244 | 5244 |
} |
| 5245 |
+ if m.NumWarnings != 0 {
|
|
| 5246 |
+ n += 2 + sovControl(uint64(m.NumWarnings)) |
|
| 5247 |
+ } |
|
| 5245 | 5248 |
if m.XXX_unrecognized != nil {
|
| 5246 | 5249 |
n += len(m.XXX_unrecognized) |
| 5247 | 5250 |
} |
| ... | ... |
@@ -10303,6 +10322,25 @@ func (m *BuildHistoryRecord) Unmarshal(dAtA []byte) error {
|
| 10303 | 10303 |
return err |
| 10304 | 10304 |
} |
| 10305 | 10305 |
iNdEx = postIndex |
| 10306 |
+ case 19: |
|
| 10307 |
+ if wireType != 0 {
|
|
| 10308 |
+ return fmt.Errorf("proto: wrong wireType = %d for field NumWarnings", wireType)
|
|
| 10309 |
+ } |
|
| 10310 |
+ m.NumWarnings = 0 |
|
| 10311 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 10312 |
+ if shift >= 64 {
|
|
| 10313 |
+ return ErrIntOverflowControl |
|
| 10314 |
+ } |
|
| 10315 |
+ if iNdEx >= l {
|
|
| 10316 |
+ return io.ErrUnexpectedEOF |
|
| 10317 |
+ } |
|
| 10318 |
+ b := dAtA[iNdEx] |
|
| 10319 |
+ iNdEx++ |
|
| 10320 |
+ m.NumWarnings |= int32(b&0x7F) << shift |
|
| 10321 |
+ if b < 0x80 {
|
|
| 10322 |
+ break |
|
| 10323 |
+ } |
|
| 10324 |
+ } |
|
| 10306 | 10325 |
default: |
| 10307 | 10326 |
iNdEx = preIndex |
| 10308 | 10327 |
skippy, err := skipControl(dAtA[iNdEx:]) |
| ... | ... |
@@ -37,10 +37,10 @@ func v0TarHeaderSelect(h *tar.Header) (orderedHeaders [][2]string) {
|
| 37 | 37 |
|
| 38 | 38 |
func v1TarHeaderSelect(h *tar.Header) (orderedHeaders [][2]string) {
|
| 39 | 39 |
pax := h.PAXRecords |
| 40 |
- if len(h.Xattrs) > 0 { //nolint:staticcheck // field deprecated in stdlib
|
|
| 40 |
+ if len(h.Xattrs) > 0 { // field deprecated in stdlib
|
|
| 41 | 41 |
if pax == nil {
|
| 42 | 42 |
pax = map[string]string{}
|
| 43 |
- for k, v := range h.Xattrs { //nolint:staticcheck // field deprecated in stdlib
|
|
| 43 |
+ for k, v := range h.Xattrs { // field deprecated in stdlib
|
|
| 44 | 44 |
pax["SCHILY.xattr."+k] = v |
| 45 | 45 |
} |
| 46 | 46 |
} |
| ... | ... |
@@ -8,6 +8,8 @@ import ( |
| 8 | 8 |
"sync" |
| 9 | 9 |
|
| 10 | 10 |
"github.com/moby/buildkit/util/bklog" |
| 11 |
+ "github.com/moby/buildkit/util/db" |
|
| 12 |
+ "github.com/moby/buildkit/util/db/boltutil" |
|
| 11 | 13 |
"github.com/pkg/errors" |
| 12 | 14 |
bolt "go.etcd.io/bbolt" |
| 13 | 15 |
) |
| ... | ... |
@@ -21,18 +23,18 @@ const ( |
| 21 | 21 |
var errNotFound = errors.Errorf("not found")
|
| 22 | 22 |
|
| 23 | 23 |
type Store struct {
|
| 24 |
- db *bolt.DB |
|
| 24 |
+ db db.DB |
|
| 25 | 25 |
} |
| 26 | 26 |
|
| 27 | 27 |
func NewStore(dbPath string) (*Store, error) {
|
| 28 |
- db, err := bolt.Open(dbPath, 0600, nil) |
|
| 28 |
+ db, err := boltutil.Open(dbPath, 0600, nil) |
|
| 29 | 29 |
if err != nil {
|
| 30 | 30 |
return nil, errors.Wrapf(err, "failed to open database file %s", dbPath) |
| 31 | 31 |
} |
| 32 | 32 |
return &Store{db: db}, nil
|
| 33 | 33 |
} |
| 34 | 34 |
|
| 35 |
-func (s *Store) DB() *bolt.DB {
|
|
| 35 |
+func (s *Store) DB() db.Transactor {
|
|
| 36 | 36 |
return s.db |
| 37 | 37 |
} |
| 38 | 38 |
|
| ... | ... |
@@ -183,21 +185,28 @@ func (s *Store) Get(id string) (*StorageItem, bool) {
|
| 183 | 183 |
si, _ := newStorageItem(id, nil, s) |
| 184 | 184 |
return si |
| 185 | 185 |
} |
| 186 |
- tx, err := s.db.Begin(false) |
|
| 187 |
- if err != nil {
|
|
| 188 |
- return empty(), false |
|
| 189 |
- } |
|
| 190 |
- defer tx.Rollback() |
|
| 191 |
- b := tx.Bucket([]byte(mainBucket)) |
|
| 192 |
- if b == nil {
|
|
| 186 |
+ |
|
| 187 |
+ var si *StorageItem |
|
| 188 |
+ if err := s.db.Update(func(tx *bolt.Tx) error {
|
|
| 189 |
+ b := tx.Bucket([]byte(mainBucket)) |
|
| 190 |
+ if b == nil {
|
|
| 191 |
+ return nil |
|
| 192 |
+ } |
|
| 193 |
+ b = b.Bucket([]byte(id)) |
|
| 194 |
+ if b == nil {
|
|
| 195 |
+ return nil |
|
| 196 |
+ } |
|
| 197 |
+ si, _ = newStorageItem(id, b, s) |
|
| 198 |
+ return nil |
|
| 199 |
+ }); err != nil {
|
|
| 193 | 200 |
return empty(), false |
| 194 | 201 |
} |
| 195 |
- b = b.Bucket([]byte(id)) |
|
| 196 |
- if b == nil {
|
|
| 197 |
- return empty(), false |
|
| 202 |
+ |
|
| 203 |
+ if si != nil {
|
|
| 204 |
+ return si, true |
|
| 198 | 205 |
} |
| 199 |
- si, _ := newStorageItem(id, b, s) |
|
| 200 |
- return si, true |
|
| 206 |
+ |
|
| 207 |
+ return empty(), false |
|
| 201 | 208 |
} |
| 202 | 209 |
|
| 203 | 210 |
func (s *Store) Close() error {
|
| ... | ... |
@@ -15,7 +15,6 @@ import ( |
| 15 | 15 |
"github.com/containerd/containerd/labels" |
| 16 | 16 |
"github.com/containerd/containerd/leases" |
| 17 | 17 |
"github.com/containerd/containerd/mount" |
| 18 |
- "github.com/containerd/containerd/pkg/userns" |
|
| 19 | 18 |
"github.com/containerd/containerd/snapshots" |
| 20 | 19 |
cerrdefs "github.com/containerd/errdefs" |
| 21 | 20 |
"github.com/docker/docker/pkg/idtools" |
| ... | ... |
@@ -34,6 +33,7 @@ import ( |
| 34 | 34 |
rootlessmountopts "github.com/moby/buildkit/util/rootless/mountopts" |
| 35 | 35 |
"github.com/moby/buildkit/util/winlayers" |
| 36 | 36 |
"github.com/moby/sys/mountinfo" |
| 37 |
+ "github.com/moby/sys/userns" |
|
| 37 | 38 |
digest "github.com/opencontainers/go-digest" |
| 38 | 39 |
ocispecs "github.com/opencontainers/image-spec/specs-go/v1" |
| 39 | 40 |
"github.com/pkg/errors" |
| ... | ... |
@@ -131,16 +131,24 @@ func StatFile(ctx context.Context, mount snapshot.Mountable, path string) (*fsty |
| 131 | 131 |
// The filename here is internal to the mount, so we can restore |
| 132 | 132 |
// the request base path for error reporting. |
| 133 | 133 |
// See os.DirFS.Open for details. |
| 134 |
- err1 := err |
|
| 135 |
- if err := errors.Cause(err); err != nil {
|
|
| 136 |
- err1 = err |
|
| 137 |
- } |
|
| 138 |
- if pe, ok := err1.(*os.PathError); ok {
|
|
| 139 |
- pe.Path = path |
|
| 140 |
- } |
|
| 134 |
+ replaceErrorPath(err, path) |
|
| 141 | 135 |
return errors.WithStack(err) |
| 142 | 136 |
} |
| 143 | 137 |
return nil |
| 144 | 138 |
}) |
| 145 | 139 |
return st, err |
| 146 | 140 |
} |
| 141 |
+ |
|
| 142 |
+// replaceErrorPath will override the path in an os.PathError in the error chain. |
|
| 143 |
+// This works with the fsutil library, but it isn't necessarily the correct |
|
| 144 |
+// way to do this because the error message of wrapped errors doesn't necessarily |
|
| 145 |
+// update or change when a wrapped error is changed. |
|
| 146 |
+// |
|
| 147 |
+// Still, this method of updating the path works with the way this specific |
|
| 148 |
+// library returns errors. |
|
| 149 |
+func replaceErrorPath(err error, path string) {
|
|
| 150 |
+ var pe *os.PathError |
|
| 151 |
+ if errors.As(err, &pe) {
|
|
| 152 |
+ pe.Path = path |
|
| 153 |
+ } |
|
| 154 |
+} |
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
"fmt" |
| 7 | 7 |
"net" |
| 8 | 8 |
"sort" |
| 9 |
+ "strings" |
|
| 9 | 10 |
|
| 10 | 11 |
"github.com/moby/buildkit/solver/pb" |
| 11 | 12 |
"github.com/moby/buildkit/util/system" |
| ... | ... |
@@ -290,7 +291,7 @@ func (e *ExecOp) Marshal(ctx context.Context, c *Constraints) (digest.Digest, [] |
| 290 | 290 |
if len(e.secrets) > 0 {
|
| 291 | 291 |
addCap(&e.constraints, pb.CapExecMountSecret) |
| 292 | 292 |
for _, s := range e.secrets {
|
| 293 |
- if s.IsEnv {
|
|
| 293 |
+ if s.Env != nil {
|
|
| 294 | 294 |
addCap(&e.constraints, pb.CapExecSecretEnv) |
| 295 | 295 |
break |
| 296 | 296 |
} |
| ... | ... |
@@ -388,16 +389,17 @@ func (e *ExecOp) Marshal(ctx context.Context, c *Constraints) (digest.Digest, [] |
| 388 | 388 |
} |
| 389 | 389 |
|
| 390 | 390 |
for _, s := range e.secrets {
|
| 391 |
- if s.IsEnv {
|
|
| 391 |
+ if s.Env != nil {
|
|
| 392 | 392 |
peo.Secretenv = append(peo.Secretenv, &pb.SecretEnv{
|
| 393 | 393 |
ID: s.ID, |
| 394 |
- Name: s.Target, |
|
| 394 |
+ Name: *s.Env, |
|
| 395 | 395 |
Optional: s.Optional, |
| 396 | 396 |
}) |
| 397 |
- } else {
|
|
| 397 |
+ } |
|
| 398 |
+ if s.Target != nil {
|
|
| 398 | 399 |
pm := &pb.Mount{
|
| 399 | 400 |
Input: pb.Empty, |
| 400 |
- Dest: s.Target, |
|
| 401 |
+ Dest: *s.Target, |
|
| 401 | 402 |
MountType: pb.MountType_SECRET, |
| 402 | 403 |
SecretOpt: &pb.SecretOpt{
|
| 403 | 404 |
ID: s.ID, |
| ... | ... |
@@ -680,7 +682,19 @@ type SSHInfo struct {
|
| 680 | 680 |
// AddSecret is a RunOption that adds a secret to the exec. |
| 681 | 681 |
func AddSecret(dest string, opts ...SecretOption) RunOption {
|
| 682 | 682 |
return runOptionFunc(func(ei *ExecInfo) {
|
| 683 |
- s := &SecretInfo{ID: dest, Target: dest, Mode: 0400}
|
|
| 683 |
+ s := &SecretInfo{ID: dest, Target: &dest, Mode: 0400}
|
|
| 684 |
+ for _, opt := range opts {
|
|
| 685 |
+ opt.SetSecretOption(s) |
|
| 686 |
+ } |
|
| 687 |
+ ei.Secrets = append(ei.Secrets, *s) |
|
| 688 |
+ }) |
|
| 689 |
+} |
|
| 690 |
+ |
|
| 691 |
+// AddSecretWithDest is a RunOption that adds a secret to the exec |
|
| 692 |
+// with an optional destination. |
|
| 693 |
+func AddSecretWithDest(src string, dest *string, opts ...SecretOption) RunOption {
|
|
| 694 |
+ return runOptionFunc(func(ei *ExecInfo) {
|
|
| 695 |
+ s := &SecretInfo{ID: src, Target: dest, Mode: 0400}
|
|
| 684 | 696 |
for _, opt := range opts {
|
| 685 | 697 |
opt.SetSecretOption(s) |
| 686 | 698 |
} |
| ... | ... |
@@ -699,13 +713,15 @@ func (fn secretOptionFunc) SetSecretOption(si *SecretInfo) {
|
| 699 | 699 |
} |
| 700 | 700 |
|
| 701 | 701 |
type SecretInfo struct {
|
| 702 |
- ID string |
|
| 703 |
- Target string |
|
| 702 |
+ ID string |
|
| 703 |
+ // Target optionally specifies the target for the secret mount |
|
| 704 |
+ Target *string |
|
| 705 |
+ // Env optionally names the environment variable for the secret |
|
| 706 |
+ Env *string |
|
| 704 | 707 |
Mode int |
| 705 | 708 |
UID int |
| 706 | 709 |
GID int |
| 707 | 710 |
Optional bool |
| 708 |
- IsEnv bool |
|
| 709 | 711 |
} |
| 710 | 712 |
|
| 711 | 713 |
var SecretOptional = secretOptionFunc(func(si *SecretInfo) {
|
| ... | ... |
@@ -721,7 +737,24 @@ func SecretID(id string) SecretOption {
|
| 721 | 721 |
// SecretAsEnv defines if the secret should be added as an environment variable |
| 722 | 722 |
func SecretAsEnv(v bool) SecretOption {
|
| 723 | 723 |
return secretOptionFunc(func(si *SecretInfo) {
|
| 724 |
- si.IsEnv = v |
|
| 724 |
+ if !v {
|
|
| 725 |
+ si.Env = nil |
|
| 726 |
+ return |
|
| 727 |
+ } |
|
| 728 |
+ if si.Target == nil {
|
|
| 729 |
+ return |
|
| 730 |
+ } |
|
| 731 |
+ target := strings.Clone(*si.Target) |
|
| 732 |
+ si.Env = &target |
|
| 733 |
+ si.Target = nil |
|
| 734 |
+ }) |
|
| 735 |
+} |
|
| 736 |
+ |
|
| 737 |
+// SecretAsEnvName defines if the secret should be added as an environment variable |
|
| 738 |
+// with the specified name |
|
| 739 |
+func SecretAsEnvName(v string) SecretOption {
|
|
| 740 |
+ return secretOptionFunc(func(si *SecretInfo) {
|
|
| 741 |
+ si.Env = &v |
|
| 725 | 742 |
}) |
| 726 | 743 |
} |
| 727 | 744 |
|
| ... | ... |
@@ -12,6 +12,7 @@ import ( |
| 12 | 12 |
"github.com/moby/buildkit/client/llb/sourceresolver" |
| 13 | 13 |
"github.com/moby/buildkit/util/contentutil" |
| 14 | 14 |
"github.com/moby/buildkit/util/imageutil" |
| 15 |
+ "github.com/moby/buildkit/util/tracing" |
|
| 15 | 16 |
"github.com/moby/buildkit/version" |
| 16 | 17 |
"github.com/moby/locker" |
| 17 | 18 |
digest "github.com/opencontainers/go-digest" |
| ... | ... |
@@ -75,7 +76,12 @@ type resolveResult struct {
|
| 75 | 75 |
dgst digest.Digest |
| 76 | 76 |
} |
| 77 | 77 |
|
| 78 |
-func (imr *imageMetaResolver) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt) (string, digest.Digest, []byte, error) {
|
|
| 78 |
+func (imr *imageMetaResolver) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt) (resolvedRef string, digest digest.Digest, config []byte, retErr error) {
|
|
| 79 |
+ span, ctx := tracing.StartSpan(ctx, "resolving "+ref) |
|
| 80 |
+ defer func() {
|
|
| 81 |
+ tracing.FinishWithError(span, retErr) |
|
| 82 |
+ }() |
|
| 83 |
+ |
|
| 79 | 84 |
imr.locker.Lock(ref) |
| 80 | 85 |
defer imr.locker.Unlock(ref) |
| 81 | 86 |
|
| ... | ... |
@@ -7,7 +7,6 @@ import ( |
| 7 | 7 |
"io" |
| 8 | 8 |
"maps" |
| 9 | 9 |
"os" |
| 10 |
- "path/filepath" |
|
| 11 | 10 |
"strings" |
| 12 | 11 |
"time" |
| 13 | 12 |
|
| ... | ... |
@@ -120,7 +119,7 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG |
| 120 | 120 |
if opt.SessionPreInitialized {
|
| 121 | 121 |
return nil, errors.Errorf("no session provided for preinitialized option")
|
| 122 | 122 |
} |
| 123 |
- s, err = session.NewSession(statusContext, defaultSessionName(), opt.SharedKey) |
|
| 123 |
+ s, err = session.NewSession(statusContext, opt.SharedKey) |
|
| 124 | 124 |
if err != nil {
|
| 125 | 125 |
return nil, errors.Wrap(err, "failed to create session") |
| 126 | 126 |
} |
| ... | ... |
@@ -419,14 +418,6 @@ func prepareSyncedFiles(def *llb.Definition, localMounts map[string]fsutil.FS) ( |
| 419 | 419 |
return result, nil |
| 420 | 420 |
} |
| 421 | 421 |
|
| 422 |
-func defaultSessionName() string {
|
|
| 423 |
- wd, err := os.Getwd() |
|
| 424 |
- if err != nil {
|
|
| 425 |
- return "unknown" |
|
| 426 |
- } |
|
| 427 |
- return filepath.Base(wd) |
|
| 428 |
-} |
|
| 429 |
- |
|
| 430 | 422 |
type cacheOptions struct {
|
| 431 | 423 |
options controlapi.CacheOptions |
| 432 | 424 |
contentStores map[string]content.Store // key: ID of content store ("local:" + csDir)
|
| ... | ... |
@@ -35,6 +35,7 @@ import ( |
| 35 | 35 |
"github.com/moby/buildkit/solver/llbsolver/proc" |
| 36 | 36 |
"github.com/moby/buildkit/solver/pb" |
| 37 | 37 |
"github.com/moby/buildkit/util/bklog" |
| 38 |
+ "github.com/moby/buildkit/util/db" |
|
| 38 | 39 |
"github.com/moby/buildkit/util/imageutil" |
| 39 | 40 |
"github.com/moby/buildkit/util/leaseutil" |
| 40 | 41 |
"github.com/moby/buildkit/util/throttle" |
| ... | ... |
@@ -43,7 +44,6 @@ import ( |
| 43 | 43 |
"github.com/moby/buildkit/worker" |
| 44 | 44 |
digest "github.com/opencontainers/go-digest" |
| 45 | 45 |
"github.com/pkg/errors" |
| 46 |
- "go.etcd.io/bbolt" |
|
| 47 | 46 |
sdktrace "go.opentelemetry.io/otel/sdk/trace" |
| 48 | 47 |
tracev1 "go.opentelemetry.io/proto/otlp/collector/trace/v1" |
| 49 | 48 |
"golang.org/x/sync/errgroup" |
| ... | ... |
@@ -62,7 +62,7 @@ type Opt struct {
|
| 62 | 62 |
ResolveCacheImporterFuncs map[string]remotecache.ResolveCacheImporterFunc |
| 63 | 63 |
Entitlements []string |
| 64 | 64 |
TraceCollector sdktrace.SpanExporter |
| 65 |
- HistoryDB *bbolt.DB |
|
| 65 |
+ HistoryDB db.DB |
|
| 66 | 66 |
CacheStore *bboltcachestorage.Store |
| 67 | 67 |
LeaseManager *leaseutil.Manager |
| 68 | 68 |
ContentStore *containerdsnapshot.Store |
| 69 | 69 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,59 @@ |
| 0 |
+package errdefs |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "errors" |
|
| 4 |
+ "syscall" |
|
| 5 |
+) |
|
| 6 |
+ |
|
| 7 |
+type internalErr struct {
|
|
| 8 |
+ error |
|
| 9 |
+} |
|
| 10 |
+ |
|
| 11 |
+func (internalErr) System() {}
|
|
| 12 |
+ |
|
| 13 |
+func (err internalErr) Unwrap() error {
|
|
| 14 |
+ return err.error |
|
| 15 |
+} |
|
| 16 |
+ |
|
| 17 |
+type system interface {
|
|
| 18 |
+ System() |
|
| 19 |
+} |
|
| 20 |
+ |
|
| 21 |
+var _ system = internalErr{}
|
|
| 22 |
+ |
|
| 23 |
+func Internal(err error) error {
|
|
| 24 |
+ if err == nil {
|
|
| 25 |
+ return nil |
|
| 26 |
+ } |
|
| 27 |
+ return internalErr{err}
|
|
| 28 |
+} |
|
| 29 |
+ |
|
| 30 |
+func IsInternal(err error) bool {
|
|
| 31 |
+ var s system |
|
| 32 |
+ if errors.As(err, &s) {
|
|
| 33 |
+ return true |
|
| 34 |
+ } |
|
| 35 |
+ |
|
| 36 |
+ var errno syscall.Errno |
|
| 37 |
+ if errors.As(err, &errno) {
|
|
| 38 |
+ if _, ok := isInternalSyscall(errno); ok {
|
|
| 39 |
+ return true |
|
| 40 |
+ } |
|
| 41 |
+ } |
|
| 42 |
+ return false |
|
| 43 |
+} |
|
| 44 |
+ |
|
| 45 |
+func IsResourceExhausted(err error) bool {
|
|
| 46 |
+ var errno syscall.Errno |
|
| 47 |
+ if errors.As(err, &errno) {
|
|
| 48 |
+ if v, ok := isInternalSyscall(errno); ok && v {
|
|
| 49 |
+ return v |
|
| 50 |
+ } |
|
| 51 |
+ } |
|
| 52 |
+ return false |
|
| 53 |
+} |
|
| 54 |
+ |
|
| 55 |
+func isInternalSyscall(err syscall.Errno) (bool, bool) {
|
|
| 56 |
+ v, ok := syscallErrors()[err] |
|
| 57 |
+ return v, ok |
|
| 58 |
+} |
| 0 | 59 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,23 @@ |
| 0 |
+//go:build linux |
|
| 1 |
+// +build linux |
|
| 2 |
+ |
|
| 3 |
+package errdefs |
|
| 4 |
+ |
|
| 5 |
+import ( |
|
| 6 |
+ "syscall" |
|
| 7 |
+ |
|
| 8 |
+ "golang.org/x/sys/unix" |
|
| 9 |
+) |
|
| 10 |
+ |
|
| 11 |
+// syscallErrors returns a map of syscall errors that are considered internal. |
|
| 12 |
+// value is true if the error is of type resource exhaustion, false otherwise. |
|
| 13 |
+func syscallErrors() map[syscall.Errno]bool {
|
|
| 14 |
+ return map[syscall.Errno]bool{
|
|
| 15 |
+ unix.EIO: false, // I/O error |
|
| 16 |
+ unix.ENOMEM: true, // Out of memory |
|
| 17 |
+ unix.EFAULT: false, // Bad address |
|
| 18 |
+ unix.ENOSPC: true, // No space left on device |
|
| 19 |
+ unix.ENOTRECOVERABLE: false, // State not recoverable |
|
| 20 |
+ unix.EHWPOISON: false, // Memory page has hardware error |
|
| 21 |
+ } |
|
| 22 |
+} |
| ... | ... |
@@ -40,34 +40,34 @@ func makeHostsFile(stateDir string, extraHosts []executor.HostIP, idmap *idtools |
| 40 | 40 |
return "", func() {}, nil
|
| 41 | 41 |
} |
| 42 | 42 |
if !errors.Is(err, os.ErrNotExist) {
|
| 43 |
- return "", nil, err |
|
| 43 |
+ return "", nil, errors.WithStack(err) |
|
| 44 | 44 |
} |
| 45 | 45 |
|
| 46 | 46 |
b := &bytes.Buffer{}
|
| 47 | 47 |
if _, err := b.Write([]byte(initHostsFile(hostname))); err != nil {
|
| 48 |
- return "", nil, err |
|
| 48 |
+ return "", nil, errors.WithStack(err) |
|
| 49 | 49 |
} |
| 50 | 50 |
|
| 51 | 51 |
for _, h := range extraHosts {
|
| 52 | 52 |
if _, err := b.Write([]byte(fmt.Sprintf("%s\t%s\n", h.IP.String(), h.Host))); err != nil {
|
| 53 |
- return "", nil, err |
|
| 53 |
+ return "", nil, errors.WithStack(err) |
|
| 54 | 54 |
} |
| 55 | 55 |
} |
| 56 | 56 |
|
| 57 | 57 |
tmpPath := p + ".tmp" |
| 58 | 58 |
if err := os.WriteFile(tmpPath, b.Bytes(), 0644); err != nil {
|
| 59 |
- return "", nil, err |
|
| 59 |
+ return "", nil, errors.WithStack(err) |
|
| 60 | 60 |
} |
| 61 | 61 |
|
| 62 | 62 |
if idmap != nil {
|
| 63 | 63 |
root := idmap.RootPair() |
| 64 | 64 |
if err := os.Chown(tmpPath, root.UID, root.GID); err != nil {
|
| 65 |
- return "", nil, err |
|
| 65 |
+ return "", nil, errors.WithStack(err) |
|
| 66 | 66 |
} |
| 67 | 67 |
} |
| 68 | 68 |
|
| 69 | 69 |
if err := os.Rename(tmpPath, p); err != nil {
|
| 70 |
- return "", nil, err |
|
| 70 |
+ return "", nil, errors.WithStack(err) |
|
| 71 | 71 |
} |
| 72 | 72 |
return p, func() {
|
| 73 | 73 |
os.RemoveAll(p) |
| ... | ... |
@@ -17,7 +17,18 @@ var notFirstRun bool |
| 17 | 17 |
var lastNotEmpty bool |
| 18 | 18 |
|
| 19 | 19 |
// overridden by tests |
| 20 |
-var resolvconfPath = resolvconf.Path |
|
| 20 |
+var resolvconfPath = func(netMode pb.NetMode) string {
|
|
| 21 |
+ // The implementation of resolvconf.Path checks if systemd resolved is activated and chooses the internal |
|
| 22 |
+ // resolv.conf (/run/systemd/resolve/resolv.conf) in such a case - see resolvconf_path.go of libnetwork. |
|
| 23 |
+ // This, however, can be problematic, see https://github.com/moby/buildkit/issues/2404 and is not necessary |
|
| 24 |
+ // in case the networking mode is set to host since the locally (127.0.0.53) running resolved daemon is |
|
| 25 |
+ // accessible from inside a host networked container. |
|
| 26 |
+ // For details of the implementation see https://github.com/moby/buildkit/pull/5207#discussion_r1705362230. |
|
| 27 |
+ if netMode == pb.NetMode_HOST {
|
|
| 28 |
+ return "/etc/resolv.conf" |
|
| 29 |
+ } |
|
| 30 |
+ return resolvconf.Path() |
|
| 31 |
+} |
|
| 21 | 32 |
|
| 22 | 33 |
type DNSConfig struct {
|
| 23 | 34 |
Nameservers []string |
| ... | ... |
@@ -39,12 +50,12 @@ func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.Identity |
| 39 | 39 |
fi, err := os.Stat(p) |
| 40 | 40 |
if err != nil {
|
| 41 | 41 |
if !errors.Is(err, os.ErrNotExist) {
|
| 42 |
- return struct{}{}, err
|
|
| 42 |
+ return struct{}{}, errors.WithStack(err)
|
|
| 43 | 43 |
} |
| 44 | 44 |
generate = true |
| 45 | 45 |
} |
| 46 | 46 |
if !generate {
|
| 47 |
- fiMain, err := os.Stat(resolvconfPath()) |
|
| 47 |
+ fiMain, err := os.Stat(resolvconfPath(netMode)) |
|
| 48 | 48 |
if err != nil {
|
| 49 | 49 |
if !errors.Is(err, os.ErrNotExist) {
|
| 50 | 50 |
return struct{}{}, err
|
| ... | ... |
@@ -63,9 +74,9 @@ func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.Identity |
| 63 | 63 |
return struct{}{}, nil
|
| 64 | 64 |
} |
| 65 | 65 |
|
| 66 |
- dt, err := os.ReadFile(resolvconfPath()) |
|
| 66 |
+ dt, err := os.ReadFile(resolvconfPath(netMode)) |
|
| 67 | 67 |
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
| 68 |
- return struct{}{}, err
|
|
| 68 |
+ return struct{}{}, errors.WithStack(err)
|
|
| 69 | 69 |
} |
| 70 | 70 |
|
| 71 | 71 |
tmpPath := p + ".tmp" |
| ... | ... |
@@ -87,7 +98,7 @@ func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.Identity |
| 87 | 87 |
|
| 88 | 88 |
f, err := resolvconf.Build(tmpPath, dnsNameservers, dnsSearchDomains, dnsOptions) |
| 89 | 89 |
if err != nil {
|
| 90 |
- return struct{}{}, err
|
|
| 90 |
+ return struct{}{}, errors.WithStack(err)
|
|
| 91 | 91 |
} |
| 92 | 92 |
dt = f.Content |
| 93 | 93 |
} |
| ... | ... |
@@ -95,24 +106,24 @@ func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.Identity |
| 95 | 95 |
if netMode != pb.NetMode_HOST || len(resolvconf.GetNameservers(dt, resolvconf.IP)) == 0 {
|
| 96 | 96 |
f, err := resolvconf.FilterResolvDNS(dt, true) |
| 97 | 97 |
if err != nil {
|
| 98 |
- return struct{}{}, err
|
|
| 98 |
+ return struct{}{}, errors.WithStack(err)
|
|
| 99 | 99 |
} |
| 100 | 100 |
dt = f.Content |
| 101 | 101 |
} |
| 102 | 102 |
|
| 103 | 103 |
if err := os.WriteFile(tmpPath, dt, 0644); err != nil {
|
| 104 |
- return struct{}{}, err
|
|
| 104 |
+ return struct{}{}, errors.WithStack(err)
|
|
| 105 | 105 |
} |
| 106 | 106 |
|
| 107 | 107 |
if idmap != nil {
|
| 108 | 108 |
root := idmap.RootPair() |
| 109 | 109 |
if err := os.Chown(tmpPath, root.UID, root.GID); err != nil {
|
| 110 |
- return struct{}{}, err
|
|
| 110 |
+ return struct{}{}, errors.WithStack(err)
|
|
| 111 | 111 |
} |
| 112 | 112 |
} |
| 113 | 113 |
|
| 114 | 114 |
if err := os.Rename(tmpPath, p); err != nil {
|
| 115 |
- return struct{}{}, err
|
|
| 115 |
+ return struct{}{}, errors.WithStack(err)
|
|
| 116 | 116 |
} |
| 117 | 117 |
return struct{}{}, nil
|
| 118 | 118 |
}) |
| ... | ... |
@@ -13,7 +13,6 @@ import ( |
| 13 | 13 |
"github.com/containerd/containerd/mount" |
| 14 | 14 |
"github.com/containerd/containerd/namespaces" |
| 15 | 15 |
"github.com/containerd/containerd/oci" |
| 16 |
- "github.com/containerd/containerd/pkg/userns" |
|
| 17 | 16 |
"github.com/docker/docker/pkg/idtools" |
| 18 | 17 |
"github.com/mitchellh/hashstructure/v2" |
| 19 | 18 |
"github.com/moby/buildkit/executor" |
| ... | ... |
@@ -21,6 +20,7 @@ import ( |
| 21 | 21 |
"github.com/moby/buildkit/util/network" |
| 22 | 22 |
rootlessmountopts "github.com/moby/buildkit/util/rootless/mountopts" |
| 23 | 23 |
traceexec "github.com/moby/buildkit/util/tracing/exec" |
| 24 |
+ "github.com/moby/sys/userns" |
|
| 24 | 25 |
specs "github.com/opencontainers/runtime-spec/specs-go" |
| 25 | 26 |
"github.com/opencontainers/selinux/go-selinux" |
| 26 | 27 |
"github.com/pkg/errors" |
| ... | ... |
@@ -84,11 +84,7 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou |
| 84 | 84 |
ctx = namespaces.WithNamespace(ctx, "buildkit") |
| 85 | 85 |
} |
| 86 | 86 |
|
| 87 |
- if mountOpts, err := generateMountOpts(resolvConf, hostsFile); err == nil {
|
|
| 88 |
- opts = append(opts, mountOpts...) |
|
| 89 |
- } else {
|
|
| 90 |
- return nil, nil, err |
|
| 91 |
- } |
|
| 87 |
+ opts = append(opts, generateMountOpts(resolvConf, hostsFile)...) |
|
| 92 | 88 |
|
| 93 | 89 |
if securityOpts, err := generateSecurityOpts(meta.SecurityMode, apparmorProfile, selinuxB); err == nil {
|
| 94 | 90 |
opts = append(opts, securityOpts...) |
| ... | ... |
@@ -135,7 +131,7 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou |
| 135 | 135 |
|
| 136 | 136 |
s, err := oci.GenerateSpec(ctx, nil, c, opts...) |
| 137 | 137 |
if err != nil {
|
| 138 |
- return nil, nil, err |
|
| 138 |
+ return nil, nil, errors.WithStack(err) |
|
| 139 | 139 |
} |
| 140 | 140 |
|
| 141 | 141 |
if cgroupV2NamespaceSupported() {
|
| ... | ... |
@@ -151,7 +147,7 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou |
| 151 | 151 |
|
| 152 | 152 |
// set the networking information on the spec |
| 153 | 153 |
if err := namespace.Set(s); err != nil {
|
| 154 |
- return nil, nil, err |
|
| 154 |
+ return nil, nil, errors.WithStack(err) |
|
| 155 | 155 |
} |
| 156 | 156 |
|
| 157 | 157 |
sm := &submounts{}
|
| ... | ... |
@@ -196,6 +192,12 @@ func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mou |
| 196 | 196 |
mount, err = sm.subMount(mount, m.Selector) |
| 197 | 197 |
if err != nil {
|
| 198 | 198 |
releaseAll() |
| 199 |
+ var os *os.PathError |
|
| 200 |
+ if errors.As(err, &os) {
|
|
| 201 |
+ if strings.HasSuffix(os.Path, m.Selector) {
|
|
| 202 |
+ os.Path = m.Selector |
|
| 203 |
+ } |
|
| 204 |
+ } |
|
| 199 | 205 |
return nil, nil, err |
| 200 | 206 |
} |
| 201 | 207 |
s.Mounts = append(s.Mounts, specs.Mount{
|
| ... | ... |
@@ -248,7 +250,7 @@ func (s *submounts) subMount(m mount.Mount, subPath string) (mount.Mount, error) |
| 248 | 248 |
} |
| 249 | 249 |
h, err := hashstructure.Hash(m, hashstructure.FormatV2, nil) |
| 250 | 250 |
if err != nil {
|
| 251 |
- return mount.Mount{}, err
|
|
| 251 |
+ return mount.Mount{}, errors.WithStack(err)
|
|
| 252 | 252 |
} |
| 253 | 253 |
if mr, ok := s.m[h]; ok {
|
| 254 | 254 |
if sm, ok := mr.subRefs[subPath]; ok {
|
| ... | ... |
@@ -14,8 +14,8 @@ func withProcessArgs(args ...string) oci.SpecOpts {
|
| 14 | 14 |
return oci.WithProcessArgs(args...) |
| 15 | 15 |
} |
| 16 | 16 |
|
| 17 |
-func generateMountOpts(_, _ string) ([]oci.SpecOpts, error) {
|
|
| 18 |
- return nil, nil |
|
| 17 |
+func generateMountOpts(_, _ string) []oci.SpecOpts {
|
|
| 18 |
+ return nil |
|
| 19 | 19 |
} |
| 20 | 20 |
|
| 21 | 21 |
// generateSecurityOpts may affect mounts, so must be called after generateMountOpts |
| ... | ... |
@@ -38,14 +38,14 @@ func withProcessArgs(args ...string) oci.SpecOpts {
|
| 38 | 38 |
return oci.WithProcessArgs(args...) |
| 39 | 39 |
} |
| 40 | 40 |
|
| 41 |
-func generateMountOpts(resolvConf, hostsFile string) ([]oci.SpecOpts, error) {
|
|
| 41 |
+func generateMountOpts(resolvConf, hostsFile string) []oci.SpecOpts {
|
|
| 42 | 42 |
return []oci.SpecOpts{
|
| 43 | 43 |
// https://github.com/moby/buildkit/issues/429 |
| 44 | 44 |
withRemovedMount("/run"),
|
| 45 | 45 |
withROBind(resolvConf, "/etc/resolv.conf"), |
| 46 | 46 |
withROBind(hostsFile, "/etc/hosts"), |
| 47 | 47 |
withCGroup(), |
| 48 |
- }, nil |
|
| 48 |
+ } |
|
| 49 | 49 |
} |
| 50 | 50 |
|
| 51 | 51 |
// generateSecurityOpts may affect mounts, so must be called after generateMountOpts |
| ... | ... |
@@ -260,13 +260,13 @@ func sub(m mount.Mount, subPath string) (mount.Mount, func() error, error) {
|
| 260 | 260 |
// similar to runc.WithProcfd |
| 261 | 261 |
fh, err := os.OpenFile(src, unix.O_PATH|unix.O_CLOEXEC, 0) |
| 262 | 262 |
if err != nil {
|
| 263 |
- return mount.Mount{}, nil, err
|
|
| 263 |
+ return mount.Mount{}, nil, errors.WithStack(err)
|
|
| 264 | 264 |
} |
| 265 | 265 |
|
| 266 | 266 |
fdPath := "/proc/self/fd/" + strconv.Itoa(int(fh.Fd())) |
| 267 | 267 |
if resolved, err := os.Readlink(fdPath); err != nil {
|
| 268 | 268 |
fh.Close() |
| 269 |
- return mount.Mount{}, nil, err
|
|
| 269 |
+ return mount.Mount{}, nil, errors.WithStack(err)
|
|
| 270 | 270 |
} else if resolved != src {
|
| 271 | 271 |
retries-- |
| 272 | 272 |
if retries <= 0 {
|
| ... | ... |
@@ -51,10 +51,10 @@ func withGetUserInfoMount() oci.SpecOpts {
|
| 51 | 51 |
} |
| 52 | 52 |
} |
| 53 | 53 |
|
| 54 |
-func generateMountOpts(_, _ string) ([]oci.SpecOpts, error) {
|
|
| 54 |
+func generateMountOpts(_, _ string) []oci.SpecOpts {
|
|
| 55 | 55 |
return []oci.SpecOpts{
|
| 56 | 56 |
withGetUserInfoMount(), |
| 57 |
- }, nil |
|
| 57 |
+ } |
|
| 58 | 58 |
} |
| 59 | 59 |
|
| 60 | 60 |
// generateSecurityOpts may affect mounts, so must be called after generateMountOpts |
| ... | ... |
@@ -219,7 +219,7 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount, |
| 219 | 219 |
bundle := filepath.Join(w.root, id) |
| 220 | 220 |
|
| 221 | 221 |
if err := os.Mkdir(bundle, 0o711); err != nil {
|
| 222 |
- return nil, err |
|
| 222 |
+ return nil, errors.WithStack(err) |
|
| 223 | 223 |
} |
| 224 | 224 |
defer os.RemoveAll(bundle) |
| 225 | 225 |
|
| ... | ... |
@@ -230,10 +230,10 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount, |
| 230 | 230 |
|
| 231 | 231 |
rootFSPath := filepath.Join(bundle, "rootfs") |
| 232 | 232 |
if err := idtools.MkdirAllAndChown(rootFSPath, 0o700, identity); err != nil {
|
| 233 |
- return nil, err |
|
| 233 |
+ return nil, errors.WithStack(err) |
|
| 234 | 234 |
} |
| 235 | 235 |
if err := mount.All(rootMount, rootFSPath); err != nil {
|
| 236 |
- return nil, err |
|
| 236 |
+ return nil, errors.WithStack(err) |
|
| 237 | 237 |
} |
| 238 | 238 |
defer mount.Unmount(rootFSPath, 0) |
| 239 | 239 |
|
| ... | ... |
@@ -241,12 +241,12 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount, |
| 241 | 241 |
|
| 242 | 242 |
uid, gid, sgids, err := oci.GetUser(rootFSPath, meta.User) |
| 243 | 243 |
if err != nil {
|
| 244 |
- return nil, err |
|
| 244 |
+ return nil, errors.WithStack(err) |
|
| 245 | 245 |
} |
| 246 | 246 |
|
| 247 | 247 |
f, err := os.Create(filepath.Join(bundle, "config.json")) |
| 248 | 248 |
if err != nil {
|
| 249 |
- return nil, err |
|
| 249 |
+ return nil, errors.WithStack(err) |
|
| 250 | 250 |
} |
| 251 | 251 |
defer f.Close() |
| 252 | 252 |
|
| ... | ... |
@@ -297,7 +297,7 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount, |
| 297 | 297 |
} |
| 298 | 298 |
|
| 299 | 299 |
if err := json.NewEncoder(f).Encode(spec); err != nil {
|
| 300 |
- return nil, err |
|
| 300 |
+ return nil, errors.WithStack(err) |
|
| 301 | 301 |
} |
| 302 | 302 |
|
| 303 | 303 |
bklog.G(ctx).Debugf("> creating %s %v", id, meta.Args)
|
| ... | ... |
@@ -335,7 +335,7 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount, |
| 335 | 335 |
} |
| 336 | 336 |
doReleaseNetwork = false |
| 337 | 337 |
|
| 338 |
- err = exitError(ctx, err) |
|
| 338 |
+ err = exitError(ctx, cgroupPath, err) |
|
| 339 | 339 |
if err != nil {
|
| 340 | 340 |
if rec != nil {
|
| 341 | 341 |
rec.Close() |
| ... | ... |
@@ -351,7 +351,7 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount, |
| 351 | 351 |
return rec, rec.CloseAsync(releaseContainer) |
| 352 | 352 |
} |
| 353 | 353 |
|
| 354 |
-func exitError(ctx context.Context, err error) error {
|
|
| 354 |
+func exitError(ctx context.Context, cgroupPath string, err error) error {
|
|
| 355 | 355 |
if err != nil {
|
| 356 | 356 |
exitErr := &gatewayapi.ExitError{
|
| 357 | 357 |
ExitCode: gatewayapi.UnknownExitStatus, |
| ... | ... |
@@ -363,6 +363,9 @@ func exitError(ctx context.Context, err error) error {
|
| 363 | 363 |
ExitCode: uint32(runcExitError.Status), |
| 364 | 364 |
} |
| 365 | 365 |
} |
| 366 |
+ |
|
| 367 |
+ detectOOM(ctx, cgroupPath, exitErr) |
|
| 368 |
+ |
|
| 366 | 369 |
trace.SpanFromContext(ctx).AddEvent( |
| 367 | 370 |
"Container exited", |
| 368 | 371 |
trace.WithAttributes( |
| ... | ... |
@@ -371,7 +374,7 @@ func exitError(ctx context.Context, err error) error {
|
| 371 | 371 |
) |
| 372 | 372 |
select {
|
| 373 | 373 |
case <-ctx.Done(): |
| 374 |
- exitErr.Err = errors.Wrapf(context.Cause(ctx), exitErr.Error()) |
|
| 374 |
+ exitErr.Err = errors.Wrap(context.Cause(ctx), exitErr.Error()) |
|
| 375 | 375 |
return exitErr |
| 376 | 376 |
default: |
| 377 | 377 |
return stack.Enable(exitErr) |
| ... | ... |
@@ -453,7 +456,7 @@ func (w *runcExecutor) Exec(ctx context.Context, id string, process executor.Pro |
| 453 | 453 |
} |
| 454 | 454 |
|
| 455 | 455 |
err = w.exec(ctx, id, spec.Process, process, nil) |
| 456 |
- return exitError(ctx, err) |
|
| 456 |
+ return exitError(ctx, "", err) |
|
| 457 | 457 |
} |
| 458 | 458 |
|
| 459 | 459 |
type forwardIO struct {
|
| ... | ... |
@@ -1,14 +1,19 @@ |
| 1 | 1 |
package runcexecutor |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "bufio" |
|
| 4 | 5 |
"context" |
| 5 | 6 |
"io" |
| 6 | 7 |
"os" |
| 8 |
+ "path/filepath" |
|
| 9 |
+ "strconv" |
|
| 10 |
+ "strings" |
|
| 7 | 11 |
"syscall" |
| 8 | 12 |
|
| 9 | 13 |
"github.com/containerd/console" |
| 10 | 14 |
runc "github.com/containerd/go-runc" |
| 11 | 15 |
"github.com/moby/buildkit/executor" |
| 16 |
+ gatewayapi "github.com/moby/buildkit/frontend/gateway/pb" |
|
| 12 | 17 |
"github.com/moby/buildkit/util/bklog" |
| 13 | 18 |
"github.com/moby/sys/signal" |
| 14 | 19 |
"github.com/opencontainers/runtime-spec/specs-go" |
| ... | ... |
@@ -172,3 +177,44 @@ func (w *runcExecutor) callWithIO(ctx context.Context, process executor.ProcessI |
| 172 | 172 |
|
| 173 | 173 |
return call(ctx, startedCh, runcIO, killer.pidfile) |
| 174 | 174 |
} |
| 175 |
+ |
|
| 176 |
+func detectOOM(ctx context.Context, ns string, gwErr *gatewayapi.ExitError) {
|
|
| 177 |
+ const defaultCgroupMountpoint = "/sys/fs/cgroup" |
|
| 178 |
+ |
|
| 179 |
+ if ns == "" {
|
|
| 180 |
+ return |
|
| 181 |
+ } |
|
| 182 |
+ |
|
| 183 |
+ count, err := readMemoryEvent(filepath.Join(defaultCgroupMountpoint, ns), "oom_kill") |
|
| 184 |
+ if err != nil {
|
|
| 185 |
+ bklog.G(ctx).WithError(err).Warn("failed to read oom_kill event")
|
|
| 186 |
+ return |
|
| 187 |
+ } |
|
| 188 |
+ if count > 0 {
|
|
| 189 |
+ gwErr.Err = syscall.ENOMEM |
|
| 190 |
+ } |
|
| 191 |
+} |
|
| 192 |
+ |
|
| 193 |
+func readMemoryEvent(fp string, event string) (uint64, error) {
|
|
| 194 |
+ f, err := os.Open(filepath.Join(fp, "memory.events")) |
|
| 195 |
+ if err != nil {
|
|
| 196 |
+ return 0, err |
|
| 197 |
+ } |
|
| 198 |
+ defer f.Close() |
|
| 199 |
+ |
|
| 200 |
+ s := bufio.NewScanner(f) |
|
| 201 |
+ for s.Scan() {
|
|
| 202 |
+ parts := strings.Fields(s.Text()) |
|
| 203 |
+ if len(parts) != 2 {
|
|
| 204 |
+ continue |
|
| 205 |
+ } |
|
| 206 |
+ if parts[0] != event {
|
|
| 207 |
+ continue |
|
| 208 |
+ } |
|
| 209 |
+ v, err := strconv.ParseUint(parts[1], 10, 64) |
|
| 210 |
+ if err == nil {
|
|
| 211 |
+ return v, nil |
|
| 212 |
+ } |
|
| 213 |
+ } |
|
| 214 |
+ return 0, s.Err() |
|
| 215 |
+} |
| ... | ... |
@@ -251,8 +251,6 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS |
| 251 | 251 |
} |
| 252 | 252 |
} |
| 253 | 253 |
|
| 254 |
- validateCommandCasing(dockerfile, lint) |
|
| 255 |
- |
|
| 256 | 254 |
proxyEnv := proxyEnvFromBuildArgs(opt.BuildArgs) |
| 257 | 255 |
|
| 258 | 256 |
stages, metaArgs, err := instructions.Parse(dockerfile.AST, lint) |
| ... | ... |
@@ -263,6 +261,7 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS |
| 263 | 263 |
return nil, errors.New("dockerfile contains no stages to build")
|
| 264 | 264 |
} |
| 265 | 265 |
validateStageNames(stages, lint) |
| 266 |
+ validateCommandCasing(stages, lint) |
|
| 266 | 267 |
|
| 267 | 268 |
shlex := shell.NewLex(dockerfile.EscapeToken) |
| 268 | 269 |
outline := newOutlineCapture() |
| ... | ... |
@@ -596,7 +595,7 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS |
| 596 | 596 |
ctxPaths := map[string]struct{}{}
|
| 597 | 597 |
|
| 598 | 598 |
var dockerIgnoreMatcher *patternmatcher.PatternMatcher |
| 599 |
- if opt.Client != nil && opt.Client.CopyIgnoredCheckEnabled {
|
|
| 599 |
+ if opt.Client != nil {
|
|
| 600 | 600 |
dockerIgnorePatterns, err := opt.Client.DockerIgnorePatterns(ctx) |
| 601 | 601 |
if err != nil {
|
| 602 | 602 |
return nil, err |
| ... | ... |
@@ -1363,10 +1362,11 @@ func dispatchCopy(d *dispatchState, cfg copyConfig) error {
|
| 1363 | 1363 |
var mode *os.FileMode |
| 1364 | 1364 |
if cfg.chmod != "" {
|
| 1365 | 1365 |
p, err := strconv.ParseUint(cfg.chmod, 8, 32) |
| 1366 |
- if err == nil {
|
|
| 1367 |
- perm := os.FileMode(p) |
|
| 1368 |
- mode = &perm |
|
| 1366 |
+ if err != nil || p > 0o7777 {
|
|
| 1367 |
+ return errors.Errorf("invalid chmod parameter: '%v'. it should be octal string and between 0 and 07777", cfg.chmod)
|
|
| 1369 | 1368 |
} |
| 1369 |
+ perm := os.FileMode(p) |
|
| 1370 |
+ mode = &perm |
|
| 1370 | 1371 |
} |
| 1371 | 1372 |
|
| 1372 | 1373 |
if cfg.checksum != "" {
|
| ... | ... |
@@ -2198,32 +2198,49 @@ func isSelfConsistentCasing(s string) bool {
|
| 2198 | 2198 |
return s == strings.ToLower(s) || s == strings.ToUpper(s) |
| 2199 | 2199 |
} |
| 2200 | 2200 |
|
| 2201 |
-func validateCommandCasing(dockerfile *parser.Result, lint *linter.Linter) {
|
|
| 2201 |
+func validateCaseMatch(name string, isMajorityLower bool, location []parser.Range, lint *linter.Linter) {
|
|
| 2202 |
+ var correctCasing string |
|
| 2203 |
+ if isMajorityLower && strings.ToLower(name) != name {
|
|
| 2204 |
+ correctCasing = "lowercase" |
|
| 2205 |
+ } else if !isMajorityLower && strings.ToUpper(name) != name {
|
|
| 2206 |
+ correctCasing = "uppercase" |
|
| 2207 |
+ } |
|
| 2208 |
+ if correctCasing != "" {
|
|
| 2209 |
+ msg := linter.RuleConsistentInstructionCasing.Format(name, correctCasing) |
|
| 2210 |
+ lint.Run(&linter.RuleConsistentInstructionCasing, location, msg) |
|
| 2211 |
+ } |
|
| 2212 |
+} |
|
| 2213 |
+ |
|
| 2214 |
+func validateCommandCasing(stages []instructions.Stage, lint *linter.Linter) {
|
|
| 2202 | 2215 |
var lowerCount, upperCount int |
| 2203 |
- for _, node := range dockerfile.AST.Children {
|
|
| 2204 |
- if isSelfConsistentCasing(node.Value) {
|
|
| 2205 |
- if strings.ToLower(node.Value) == node.Value {
|
|
| 2216 |
+ for _, stage := range stages {
|
|
| 2217 |
+ if isSelfConsistentCasing(stage.OrigCmd) {
|
|
| 2218 |
+ if strings.ToLower(stage.OrigCmd) == stage.OrigCmd {
|
|
| 2206 | 2219 |
lowerCount++ |
| 2207 | 2220 |
} else {
|
| 2208 | 2221 |
upperCount++ |
| 2209 | 2222 |
} |
| 2210 | 2223 |
} |
| 2224 |
+ for _, cmd := range stage.Commands {
|
|
| 2225 |
+ cmdName := cmd.Name() |
|
| 2226 |
+ if isSelfConsistentCasing(cmdName) {
|
|
| 2227 |
+ if strings.ToLower(cmdName) == cmdName {
|
|
| 2228 |
+ lowerCount++ |
|
| 2229 |
+ } else {
|
|
| 2230 |
+ upperCount++ |
|
| 2231 |
+ } |
|
| 2232 |
+ } |
|
| 2233 |
+ } |
|
| 2211 | 2234 |
} |
| 2212 | 2235 |
|
| 2213 | 2236 |
isMajorityLower := lowerCount > upperCount |
| 2214 |
- for _, node := range dockerfile.AST.Children {
|
|
| 2237 |
+ for _, stage := range stages {
|
|
| 2215 | 2238 |
// Here, we check both if the command is consistent per command (ie, "CMD" or "cmd", not "Cmd") |
| 2216 | 2239 |
// as well as ensuring that the casing is consistent throughout the dockerfile by comparing the |
| 2217 | 2240 |
// command to the casing of the majority of commands. |
| 2218 |
- var correctCasing string |
|
| 2219 |
- if isMajorityLower && strings.ToLower(node.Value) != node.Value {
|
|
| 2220 |
- correctCasing = "lowercase" |
|
| 2221 |
- } else if !isMajorityLower && strings.ToUpper(node.Value) != node.Value {
|
|
| 2222 |
- correctCasing = "uppercase" |
|
| 2223 |
- } |
|
| 2224 |
- if correctCasing != "" {
|
|
| 2225 |
- msg := linter.RuleConsistentInstructionCasing.Format(node.Value, correctCasing) |
|
| 2226 |
- lint.Run(&linter.RuleConsistentInstructionCasing, node.Location(), msg) |
|
| 2241 |
+ validateCaseMatch(stage.OrigCmd, isMajorityLower, stage.Location, lint) |
|
| 2242 |
+ for _, cmd := range stage.Commands {
|
|
| 2243 |
+ validateCaseMatch(cmd.Name(), isMajorityLower, cmd.Location(), lint) |
|
| 2227 | 2244 |
} |
| 2228 | 2245 |
} |
| 2229 | 2246 |
} |
| ... | ... |
@@ -22,9 +22,17 @@ func dispatchSecret(d *dispatchState, m *instructions.Mount, loc []parser.Range) |
| 22 | 22 |
id = path.Base(m.Target) |
| 23 | 23 |
} |
| 24 | 24 |
|
| 25 |
- target := m.Target |
|
| 26 |
- if target == "" {
|
|
| 27 |
- target = "/run/secrets/" + path.Base(id) |
|
| 25 |
+ var target *string |
|
| 26 |
+ if m.Target != "" {
|
|
| 27 |
+ target = &m.Target |
|
| 28 |
+ } |
|
| 29 |
+ |
|
| 30 |
+ if m.Env == nil {
|
|
| 31 |
+ dest := m.Target |
|
| 32 |
+ if dest == "" {
|
|
| 33 |
+ dest = "/run/secrets/" + path.Base(id) |
|
| 34 |
+ } |
|
| 35 |
+ target = &dest |
|
| 28 | 36 |
} |
| 29 | 37 |
|
| 30 | 38 |
if _, ok := d.outline.secrets[id]; !ok {
|
| ... | ... |
@@ -39,6 +47,9 @@ func dispatchSecret(d *dispatchState, m *instructions.Mount, loc []parser.Range) |
| 39 | 39 |
if !m.Required {
|
| 40 | 40 |
opts = append(opts, llb.SecretOptional) |
| 41 | 41 |
} |
| 42 |
+ if m.Env != nil {
|
|
| 43 |
+ opts = append(opts, llb.SecretAsEnvName(*m.Env)) |
|
| 44 |
+ } |
|
| 42 | 45 |
|
| 43 | 46 |
if m.UID != nil || m.GID != nil || m.Mode != nil {
|
| 44 | 47 |
var uid, gid, mode int |
| ... | ... |
@@ -56,5 +67,5 @@ func dispatchSecret(d *dispatchState, m *instructions.Mount, loc []parser.Range) |
| 56 | 56 |
opts = append(opts, llb.SecretFileOpt(uid, gid, mode)) |
| 57 | 57 |
} |
| 58 | 58 |
|
| 59 |
- return llb.AddSecret(target, opts...), nil |
|
| 59 |
+ return llb.AddSecretWithDest(id, target, opts...), nil |
|
| 60 | 60 |
} |
| ... | ... |
@@ -255,6 +255,12 @@ func (c *AddCommand) Expand(expander SingleWordExpander) error {
|
| 255 | 255 |
} |
| 256 | 256 |
c.Chown = expandedChown |
| 257 | 257 |
|
| 258 |
+ expandedChmod, err := expander(c.Chmod) |
|
| 259 |
+ if err != nil {
|
|
| 260 |
+ return err |
|
| 261 |
+ } |
|
| 262 |
+ c.Chmod = expandedChmod |
|
| 263 |
+ |
|
| 258 | 264 |
expandedChecksum, err := expander(c.Checksum) |
| 259 | 265 |
if err != nil {
|
| 260 | 266 |
return err |
| ... | ... |
@@ -287,6 +293,12 @@ func (c *CopyCommand) Expand(expander SingleWordExpander) error {
|
| 287 | 287 |
} |
| 288 | 288 |
c.Chown = expandedChown |
| 289 | 289 |
|
| 290 |
+ expandedChmod, err := expander(c.Chmod) |
|
| 291 |
+ if err != nil {
|
|
| 292 |
+ return err |
|
| 293 |
+ } |
|
| 294 |
+ c.Chmod = expandedChmod |
|
| 295 |
+ |
|
| 290 | 296 |
return c.SourcesAndDest.Expand(expander) |
| 291 | 297 |
} |
| 292 | 298 |
|
| ... | ... |
@@ -494,6 +506,7 @@ type ShellCommand struct {
|
| 494 | 494 |
type Stage struct {
|
| 495 | 495 |
Name string // name of the stage |
| 496 | 496 |
Commands []Command // commands contained within the stage |
| 497 |
+ OrigCmd string // original FROM command, used for rule checks |
|
| 497 | 498 |
BaseName string // name of the base stage or source |
| 498 | 499 |
Platform string // platform of base source to use |
| 499 | 500 |
|
| ... | ... |
@@ -122,9 +122,12 @@ type Mount struct {
|
| 122 | 122 |
CacheID string |
| 123 | 123 |
CacheSharing ShareMode |
| 124 | 124 |
Required bool |
| 125 |
- Mode *uint64 |
|
| 126 |
- UID *uint64 |
|
| 127 |
- GID *uint64 |
|
| 125 |
+ // Env optionally specifies the name of the environment variable for a secret. |
|
| 126 |
+ // A pointer to an empty value uses the default |
|
| 127 |
+ Env *string |
|
| 128 |
+ Mode *uint64 |
|
| 129 |
+ UID *uint64 |
|
| 130 |
+ GID *uint64 |
|
| 128 | 131 |
} |
| 129 | 132 |
|
| 130 | 133 |
func parseMount(val string, expander SingleWordExpander) (*Mount, error) {
|
| ... | ... |
@@ -252,9 +255,11 @@ func parseMount(val string, expander SingleWordExpander) (*Mount, error) {
|
| 252 | 252 |
return nil, errors.Errorf("invalid value %s for gid", value)
|
| 253 | 253 |
} |
| 254 | 254 |
m.GID = &gid |
| 255 |
+ case "env": |
|
| 256 |
+ m.Env = &value |
|
| 255 | 257 |
default: |
| 256 | 258 |
allKeys := []string{
|
| 257 |
- "type", "from", "source", "target", "readonly", "id", "sharing", "required", "mode", "uid", "gid", "src", "dst", "ro", "rw", "readwrite", |
|
| 259 |
+ "type", "from", "source", "target", "readonly", "id", "sharing", "required", "size", "mode", "uid", "gid", "src", "dst", "destination", "ro", "rw", "readwrite", "env", |
|
| 258 | 260 |
} |
| 259 | 261 |
return nil, suggest.WrapError(errors.Errorf("unexpected key '%s' in '%s'", key, field), key, allKeys, true)
|
| 260 | 262 |
} |
| ... | ... |
@@ -10,42 +10,61 @@ import ( |
| 10 | 10 |
) |
| 11 | 11 |
|
| 12 | 12 |
type Config struct {
|
| 13 |
- Warn LintWarnFunc |
|
| 14 |
- SkipRules []string |
|
| 15 |
- SkipAll bool |
|
| 16 |
- ReturnAsError bool |
|
| 13 |
+ ExperimentalAll bool |
|
| 14 |
+ ExperimentalRules []string |
|
| 15 |
+ ReturnAsError bool |
|
| 16 |
+ SkipAll bool |
|
| 17 |
+ SkipRules []string |
|
| 18 |
+ Warn LintWarnFunc |
|
| 17 | 19 |
} |
| 18 | 20 |
|
| 19 | 21 |
type Linter struct {
|
| 20 |
- SkippedRules map[string]struct{}
|
|
| 21 |
- CalledRules []string |
|
| 22 |
- SkipAll bool |
|
| 23 |
- ReturnAsError bool |
|
| 24 |
- Warn LintWarnFunc |
|
| 22 |
+ CalledRules []string |
|
| 23 |
+ ExperimentalAll bool |
|
| 24 |
+ ExperimentalRules map[string]struct{}
|
|
| 25 |
+ ReturnAsError bool |
|
| 26 |
+ SkipAll bool |
|
| 27 |
+ SkippedRules map[string]struct{}
|
|
| 28 |
+ Warn LintWarnFunc |
|
| 25 | 29 |
} |
| 26 | 30 |
|
| 27 | 31 |
func New(config *Config) *Linter {
|
| 28 | 32 |
toret := &Linter{
|
| 29 |
- SkippedRules: map[string]struct{}{},
|
|
| 30 |
- CalledRules: []string{},
|
|
| 31 |
- Warn: config.Warn, |
|
| 33 |
+ SkippedRules: map[string]struct{}{},
|
|
| 34 |
+ ExperimentalRules: map[string]struct{}{},
|
|
| 35 |
+ CalledRules: []string{},
|
|
| 36 |
+ Warn: config.Warn, |
|
| 32 | 37 |
} |
| 33 | 38 |
toret.SkipAll = config.SkipAll |
| 39 |
+ toret.ExperimentalAll = config.ExperimentalAll |
|
| 34 | 40 |
toret.ReturnAsError = config.ReturnAsError |
| 35 | 41 |
for _, rule := range config.SkipRules {
|
| 36 | 42 |
toret.SkippedRules[rule] = struct{}{}
|
| 37 | 43 |
} |
| 44 |
+ for _, rule := range config.ExperimentalRules {
|
|
| 45 |
+ toret.ExperimentalRules[rule] = struct{}{}
|
|
| 46 |
+ } |
|
| 38 | 47 |
return toret |
| 39 | 48 |
} |
| 40 | 49 |
|
| 41 | 50 |
func (lc *Linter) Run(rule LinterRuleI, location []parser.Range, txt ...string) {
|
| 42 |
- if lc == nil || lc.Warn == nil || lc.SkipAll || rule.IsDeprecated() {
|
|
| 51 |
+ if lc == nil || lc.Warn == nil || rule.IsDeprecated() {
|
|
| 43 | 52 |
return |
| 44 | 53 |
} |
| 54 |
+ |
|
| 45 | 55 |
rulename := rule.RuleName() |
| 46 |
- if _, ok := lc.SkippedRules[rulename]; ok {
|
|
| 47 |
- return |
|
| 56 |
+ if rule.IsExperimental() {
|
|
| 57 |
+ _, experimentalOk := lc.ExperimentalRules[rulename] |
|
| 58 |
+ if !(lc.ExperimentalAll || experimentalOk) {
|
|
| 59 |
+ return |
|
| 60 |
+ } |
|
| 61 |
+ } else {
|
|
| 62 |
+ _, skipOk := lc.SkippedRules[rulename] |
|
| 63 |
+ if lc.SkipAll || skipOk {
|
|
| 64 |
+ return |
|
| 65 |
+ } |
|
| 48 | 66 |
} |
| 67 |
+ |
|
| 49 | 68 |
lc.CalledRules = append(lc.CalledRules, rulename) |
| 50 | 69 |
rule.Run(lc.Warn, location, txt...) |
| 51 | 70 |
} |
| ... | ... |
@@ -72,14 +91,16 @@ type LinterRuleI interface {
|
| 72 | 72 |
RuleName() string |
| 73 | 73 |
Run(warn LintWarnFunc, location []parser.Range, txt ...string) |
| 74 | 74 |
IsDeprecated() bool |
| 75 |
+ IsExperimental() bool |
|
| 75 | 76 |
} |
| 76 | 77 |
|
| 77 | 78 |
type LinterRule[F any] struct {
|
| 78 |
- Name string |
|
| 79 |
- Description string |
|
| 80 |
- Deprecated bool |
|
| 81 |
- URL string |
|
| 82 |
- Format F |
|
| 79 |
+ Name string |
|
| 80 |
+ Description string |
|
| 81 |
+ Deprecated bool |
|
| 82 |
+ Experimental bool |
|
| 83 |
+ URL string |
|
| 84 |
+ Format F |
|
| 83 | 85 |
} |
| 84 | 86 |
|
| 85 | 87 |
func (rule *LinterRule[F]) RuleName() string {
|
| ... | ... |
@@ -98,6 +119,10 @@ func (rule *LinterRule[F]) IsDeprecated() bool {
|
| 98 | 98 |
return rule.Deprecated |
| 99 | 99 |
} |
| 100 | 100 |
|
| 101 |
+func (rule *LinterRule[F]) IsExperimental() bool {
|
|
| 102 |
+ return rule.Experimental |
|
| 103 |
+} |
|
| 104 |
+ |
|
| 101 | 105 |
func LintFormatShort(rulename, msg string, line int) string {
|
| 102 | 106 |
msg = fmt.Sprintf("%s: %s", rulename, msg)
|
| 103 | 107 |
if line > 0 {
|
| ... | ... |
@@ -114,9 +139,9 @@ func ParseLintOptions(checkStr string) (*Config, error) {
|
| 114 | 114 |
return &Config{}, nil
|
| 115 | 115 |
} |
| 116 | 116 |
|
| 117 |
- parts := strings.SplitN(checkStr, ";", 2) |
|
| 118 |
- var skipSet []string |
|
| 119 |
- var errorOnWarn, skipAll bool |
|
| 117 |
+ parts := strings.SplitN(checkStr, ";", 3) |
|
| 118 |
+ var skipSet, experimentalSet []string |
|
| 119 |
+ var errorOnWarn, skipAll, experimentalAll bool |
|
| 120 | 120 |
for _, p := range parts {
|
| 121 | 121 |
k, v, ok := strings.Cut(p, "=") |
| 122 | 122 |
if !ok {
|
| ... | ... |
@@ -134,6 +159,16 @@ func ParseLintOptions(checkStr string) (*Config, error) {
|
| 134 | 134 |
skipSet[i] = strings.TrimSpace(rule) |
| 135 | 135 |
} |
| 136 | 136 |
} |
| 137 |
+ case "experimental": |
|
| 138 |
+ v = strings.TrimSpace(v) |
|
| 139 |
+ if v == "all" {
|
|
| 140 |
+ experimentalAll = true |
|
| 141 |
+ } else {
|
|
| 142 |
+ experimentalSet = strings.Split(v, ",") |
|
| 143 |
+ for i, rule := range experimentalSet {
|
|
| 144 |
+ experimentalSet[i] = strings.TrimSpace(rule) |
|
| 145 |
+ } |
|
| 146 |
+ } |
|
| 137 | 147 |
case "error": |
| 138 | 148 |
v, err := strconv.ParseBool(strings.TrimSpace(v)) |
| 139 | 149 |
if err != nil {
|
| ... | ... |
@@ -145,8 +180,10 @@ func ParseLintOptions(checkStr string) (*Config, error) {
|
| 145 | 145 |
} |
| 146 | 146 |
} |
| 147 | 147 |
return &Config{
|
| 148 |
- SkipRules: skipSet, |
|
| 149 |
- SkipAll: skipAll, |
|
| 150 |
- ReturnAsError: errorOnWarn, |
|
| 148 |
+ ExperimentalAll: experimentalAll, |
|
| 149 |
+ ExperimentalRules: experimentalSet, |
|
| 150 |
+ SkipRules: skipSet, |
|
| 151 |
+ SkipAll: skipAll, |
|
| 152 |
+ ReturnAsError: errorOnWarn, |
|
| 151 | 153 |
}, nil |
| 152 | 154 |
} |
| ... | ... |
@@ -378,6 +378,9 @@ func (sw *shellWord) processDollar() (string, error) {
|
| 378 | 378 |
fallthrough |
| 379 | 379 |
case '+', '-', '?', '#', '%': |
| 380 | 380 |
rawEscapes := ch == '#' || ch == '%' |
| 381 |
+ if nullIsUnset && rawEscapes {
|
|
| 382 |
+ return "", errors.Errorf("unsupported modifier (%s) in substitution", chs)
|
|
| 383 |
+ } |
|
| 381 | 384 |
word, _, err := sw.processStopOn('}', rawEscapes)
|
| 382 | 385 |
if err != nil {
|
| 383 | 386 |
if sw.scanner.Peek() == scanner.EOF {
|
| ... | ... |
@@ -125,6 +125,16 @@ func parseSourceDateEpoch(v string) (*time.Time, error) {
|
| 125 | 125 |
return &tm, nil |
| 126 | 126 |
} |
| 127 | 127 |
|
| 128 |
+func parseLocalSessionIDs(opt map[string]string) map[string]string {
|
|
| 129 |
+ m := map[string]string{}
|
|
| 130 |
+ for k, v := range opt {
|
|
| 131 |
+ if strings.HasPrefix(k, localSessionIDPrefix) {
|
|
| 132 |
+ m[strings.TrimPrefix(k, localSessionIDPrefix)] = v |
|
| 133 |
+ } |
|
| 134 |
+ } |
|
| 135 |
+ return m |
|
| 136 |
+} |
|
| 137 |
+ |
|
| 128 | 138 |
func filter(opt map[string]string, key string) map[string]string {
|
| 129 | 139 |
m := map[string]string{}
|
| 130 | 140 |
for k, v := range opt {
|
| ... | ... |
@@ -26,8 +26,9 @@ import ( |
| 26 | 26 |
) |
| 27 | 27 |
|
| 28 | 28 |
const ( |
| 29 |
- buildArgPrefix = "build-arg:" |
|
| 30 |
- labelPrefix = "label:" |
|
| 29 |
+ buildArgPrefix = "build-arg:" |
|
| 30 |
+ labelPrefix = "label:" |
|
| 31 |
+ localSessionIDPrefix = "local-sessionid:" |
|
| 31 | 32 |
|
| 32 | 33 |
keyTarget = "target" |
| 33 | 34 |
keyCgroupParent = "cgroup-parent" |
| ... | ... |
@@ -45,30 +46,28 @@ const ( |
| 45 | 45 |
|
| 46 | 46 |
// Don't forget to update frontend documentation if you add |
| 47 | 47 |
// a new build-arg: frontend/dockerfile/docs/reference.md |
| 48 |
- keyCacheNSArg = "build-arg:BUILDKIT_CACHE_MOUNT_NS" |
|
| 49 |
- keyMultiPlatformArg = "build-arg:BUILDKIT_MULTI_PLATFORM" |
|
| 50 |
- keyHostnameArg = "build-arg:BUILDKIT_SANDBOX_HOSTNAME" |
|
| 51 |
- keyDockerfileLintArg = "build-arg:BUILDKIT_DOCKERFILE_CHECK" |
|
| 52 |
- keyContextKeepGitDirArg = "build-arg:BUILDKIT_CONTEXT_KEEP_GIT_DIR" |
|
| 53 |
- keySourceDateEpoch = "build-arg:SOURCE_DATE_EPOCH" |
|
| 54 |
- keyCopyIgnoredCheckEnabled = "build-arg:BUILDKIT_DOCKERFILE_CHECK_COPYIGNORED_EXPERIMENT" |
|
| 48 |
+ keyCacheNSArg = "build-arg:BUILDKIT_CACHE_MOUNT_NS" |
|
| 49 |
+ keyMultiPlatformArg = "build-arg:BUILDKIT_MULTI_PLATFORM" |
|
| 50 |
+ keyHostnameArg = "build-arg:BUILDKIT_SANDBOX_HOSTNAME" |
|
| 51 |
+ keyDockerfileLintArg = "build-arg:BUILDKIT_DOCKERFILE_CHECK" |
|
| 52 |
+ keyContextKeepGitDirArg = "build-arg:BUILDKIT_CONTEXT_KEEP_GIT_DIR" |
|
| 53 |
+ keySourceDateEpoch = "build-arg:SOURCE_DATE_EPOCH" |
|
| 55 | 54 |
) |
| 56 | 55 |
|
| 57 | 56 |
type Config struct {
|
| 58 |
- BuildArgs map[string]string |
|
| 59 |
- CacheIDNamespace string |
|
| 60 |
- CgroupParent string |
|
| 61 |
- Epoch *time.Time |
|
| 62 |
- ExtraHosts []llb.HostIP |
|
| 63 |
- Hostname string |
|
| 64 |
- ImageResolveMode llb.ResolveMode |
|
| 65 |
- Labels map[string]string |
|
| 66 |
- NetworkMode pb.NetMode |
|
| 67 |
- ShmSize int64 |
|
| 68 |
- Target string |
|
| 69 |
- Ulimits []pb.Ulimit |
|
| 70 |
- LinterConfig *linter.Config |
|
| 71 |
- CopyIgnoredCheckEnabled bool |
|
| 57 |
+ BuildArgs map[string]string |
|
| 58 |
+ CacheIDNamespace string |
|
| 59 |
+ CgroupParent string |
|
| 60 |
+ Epoch *time.Time |
|
| 61 |
+ ExtraHosts []llb.HostIP |
|
| 62 |
+ Hostname string |
|
| 63 |
+ ImageResolveMode llb.ResolveMode |
|
| 64 |
+ Labels map[string]string |
|
| 65 |
+ NetworkMode pb.NetMode |
|
| 66 |
+ ShmSize int64 |
|
| 67 |
+ Target string |
|
| 68 |
+ Ulimits []pb.Ulimit |
|
| 69 |
+ LinterConfig *linter.Config |
|
| 72 | 70 |
|
| 73 | 71 |
CacheImports []client.CacheOptionsEntry |
| 74 | 72 |
TargetPlatforms []ocispecs.Platform // nil means default |
| ... | ... |
@@ -79,10 +78,11 @@ type Config struct {
|
| 79 | 79 |
|
| 80 | 80 |
type Client struct {
|
| 81 | 81 |
Config |
| 82 |
- client client.Client |
|
| 83 |
- ignoreCache []string |
|
| 84 |
- g flightcontrol.CachedGroup[*buildContext] |
|
| 85 |
- bopts client.BuildOpts |
|
| 82 |
+ client client.Client |
|
| 83 |
+ ignoreCache []string |
|
| 84 |
+ g flightcontrol.CachedGroup[*buildContext] |
|
| 85 |
+ bopts client.BuildOpts |
|
| 86 |
+ localsSessionIDs map[string]string |
|
| 86 | 87 |
|
| 87 | 88 |
dockerignore []byte |
| 88 | 89 |
dockerignoreName string |
| ... | ... |
@@ -289,15 +289,8 @@ func (bc *Client) init() error {
|
| 289 | 289 |
} |
| 290 | 290 |
} |
| 291 | 291 |
|
| 292 |
- // CopyIgnoredCheckEnabled is an experimental feature to check if COPY is ignored by .dockerignore, |
|
| 293 |
- // and it is disabled by default. It is expected that this feature will be enabled by default in a future |
|
| 294 |
- // release, and this build-arg will be removed. |
|
| 295 |
- if v, ok := opts[keyCopyIgnoredCheckEnabled]; ok {
|
|
| 296 |
- bc.CopyIgnoredCheckEnabled, err = strconv.ParseBool(v) |
|
| 297 |
- if err != nil {
|
|
| 298 |
- return errors.Wrapf(err, "failed to parse %s", keyCopyIgnoredCheckEnabled) |
|
| 299 |
- } |
|
| 300 |
- } |
|
| 292 |
+ bc.localsSessionIDs = parseLocalSessionIDs(opts) |
|
| 293 |
+ |
|
| 301 | 294 |
return nil |
| 302 | 295 |
} |
| 303 | 296 |
|
| ... | ... |
@@ -331,9 +324,14 @@ func (bc *Client) ReadEntrypoint(ctx context.Context, lang string, opts ...llb.L |
| 331 | 331 |
filenames = append(filenames, path.Join(path.Dir(bctx.filename), strings.ToLower(DefaultDockerfileName))) |
| 332 | 332 |
} |
| 333 | 333 |
|
| 334 |
+ sessionID := bc.bopts.SessionID |
|
| 335 |
+ if v, ok := bc.localsSessionIDs[bctx.dockerfileLocalName]; ok {
|
|
| 336 |
+ sessionID = v |
|
| 337 |
+ } |
|
| 338 |
+ |
|
| 334 | 339 |
opts = append([]llb.LocalOption{
|
| 335 | 340 |
llb.FollowPaths(filenames), |
| 336 |
- llb.SessionID(bc.bopts.SessionID), |
|
| 341 |
+ llb.SessionID(sessionID), |
|
| 337 | 342 |
llb.SharedKeyHint(bctx.dockerfileLocalName), |
| 338 | 343 |
WithInternalName(name), |
| 339 | 344 |
llb.Differ(llb.DiffNone, false), |
| ... | ... |
@@ -427,8 +425,13 @@ func (bc *Client) MainContext(ctx context.Context, opts ...llb.LocalOption) (*ll |
| 427 | 427 |
return nil, errors.Wrapf(err, "failed to read dockerignore patterns") |
| 428 | 428 |
} |
| 429 | 429 |
|
| 430 |
+ sessionID := bc.bopts.SessionID |
|
| 431 |
+ if v, ok := bc.localsSessionIDs[bctx.contextLocalName]; ok {
|
|
| 432 |
+ sessionID = v |
|
| 433 |
+ } |
|
| 434 |
+ |
|
| 430 | 435 |
opts = append([]llb.LocalOption{
|
| 431 |
- llb.SessionID(bc.bopts.SessionID), |
|
| 436 |
+ llb.SessionID(sessionID), |
|
| 432 | 437 |
llb.ExcludePatterns(excludes), |
| 433 | 438 |
llb.SharedKeyHint(bctx.contextLocalName), |
| 434 | 439 |
WithInternalName("load build context"),
|
| ... | ... |
@@ -500,8 +503,12 @@ func WithInternalName(name string) llb.ConstraintsOpt {
|
| 500 | 500 |
|
| 501 | 501 |
func (bc *Client) dockerIgnorePatterns(ctx context.Context, bctx *buildContext) ([]string, error) {
|
| 502 | 502 |
if bc.dockerignore == nil {
|
| 503 |
+ sessionID := bc.bopts.SessionID |
|
| 504 |
+ if v, ok := bc.localsSessionIDs[bctx.contextLocalName]; ok {
|
|
| 505 |
+ sessionID = v |
|
| 506 |
+ } |
|
| 503 | 507 |
st := llb.Local(bctx.contextLocalName, |
| 504 |
- llb.SessionID(bc.bopts.SessionID), |
|
| 508 |
+ llb.SessionID(sessionID), |
|
| 505 | 509 |
llb.FollowPaths([]string{DefaultDockerignoreName}),
|
| 506 | 510 |
llb.SharedKeyHint(bctx.contextLocalName+"-"+DefaultDockerignoreName), |
| 507 | 511 |
WithInternalName("load "+DefaultDockerignoreName),
|
| ... | ... |
@@ -187,8 +187,12 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi |
| 187 | 187 |
} |
| 188 | 188 |
return &st, &img, nil |
| 189 | 189 |
case "local": |
| 190 |
+ sessionID := bc.bopts.SessionID |
|
| 191 |
+ if v, ok := bc.localsSessionIDs[vv[1]]; ok {
|
|
| 192 |
+ sessionID = v |
|
| 193 |
+ } |
|
| 190 | 194 |
st := llb.Local(vv[1], |
| 191 |
- llb.SessionID(bc.bopts.SessionID), |
|
| 195 |
+ llb.SessionID(sessionID), |
|
| 192 | 196 |
llb.FollowPaths([]string{DefaultDockerignoreName}),
|
| 193 | 197 |
llb.SharedKeyHint("context:"+nameWithPlatform+"-"+DefaultDockerignoreName),
|
| 194 | 198 |
llb.WithCustomName("[context "+nameWithPlatform+"] load "+DefaultDockerignoreName),
|
| ... | ... |
@@ -226,7 +230,7 @@ func (bc *Client) namedContextRecursive(ctx context.Context, name string, nameWi |
| 226 | 226 |
localOutput := &asyncLocalOutput{
|
| 227 | 227 |
name: vv[1], |
| 228 | 228 |
nameWithPlatform: nameWithPlatform, |
| 229 |
- sessionID: bc.bopts.SessionID, |
|
| 229 |
+ sessionID: sessionID, |
|
| 230 | 230 |
excludes: excludes, |
| 231 | 231 |
extraOpts: opt.AsyncLocalOpts, |
| 232 | 232 |
} |
| ... | ... |
@@ -16,6 +16,8 @@ import ( |
| 16 | 16 |
"github.com/pkg/errors" |
| 17 | 17 |
) |
| 18 | 18 |
|
| 19 |
+type SourceInfoMap func(*pb.SourceInfo) *pb.SourceInfo |
|
| 20 |
+ |
|
| 19 | 21 |
const RequestLint = "frontend.lint" |
| 20 | 22 |
|
| 21 | 23 |
var SubrequestLintDefinition = subrequests.Request{
|
| ... | ... |
@@ -39,6 +41,27 @@ type Warning struct {
|
| 39 | 39 |
Location pb.Location `json:"location,omitempty"` |
| 40 | 40 |
} |
| 41 | 41 |
|
| 42 |
+func (w *Warning) PrintTo(wr io.Writer, sources []*pb.SourceInfo, scb SourceInfoMap) error {
|
|
| 43 |
+ fmt.Fprintf(wr, "\nWARNING: %s", w.RuleName) |
|
| 44 |
+ if w.URL != "" {
|
|
| 45 |
+ fmt.Fprintf(wr, " - %s", w.URL) |
|
| 46 |
+ } |
|
| 47 |
+ fmt.Fprintf(wr, "\n%s\n", w.Detail) |
|
| 48 |
+ |
|
| 49 |
+ if w.Location.SourceIndex < 0 {
|
|
| 50 |
+ return nil |
|
| 51 |
+ } |
|
| 52 |
+ sourceInfo := sources[w.Location.SourceIndex] |
|
| 53 |
+ if scb != nil {
|
|
| 54 |
+ sourceInfo = scb(sourceInfo) |
|
| 55 |
+ } |
|
| 56 |
+ source := errdefs.Source{
|
|
| 57 |
+ Info: sourceInfo, |
|
| 58 |
+ Ranges: w.Location.Ranges, |
|
| 59 |
+ } |
|
| 60 |
+ return source.Print(wr) |
|
| 61 |
+} |
|
| 62 |
+ |
|
| 42 | 63 |
type BuildError struct {
|
| 43 | 64 |
Message string `json:"message"` |
| 44 | 65 |
Location pb.Location `json:"location"` |
| ... | ... |
@@ -93,7 +116,7 @@ func (results *LintResults) AddWarning(rulename, description, url, fmtmsg string |
| 93 | 93 |
}) |
| 94 | 94 |
} |
| 95 | 95 |
|
| 96 |
-func (results *LintResults) ToResult() (*client.Result, error) {
|
|
| 96 |
+func (results *LintResults) ToResult(scb SourceInfoMap) (*client.Result, error) {
|
|
| 97 | 97 |
res := client.NewResult() |
| 98 | 98 |
dt, err := json.MarshalIndent(results, "", " ") |
| 99 | 99 |
if err != nil {
|
| ... | ... |
@@ -102,7 +125,7 @@ func (results *LintResults) ToResult() (*client.Result, error) {
|
| 102 | 102 |
res.AddMeta("result.json", dt)
|
| 103 | 103 |
|
| 104 | 104 |
b := bytes.NewBuffer(nil) |
| 105 |
- if err := PrintLintViolations(dt, b); err != nil {
|
|
| 105 |
+ if err := PrintLintViolations(dt, b, scb); err != nil {
|
|
| 106 | 106 |
return nil, err |
| 107 | 107 |
} |
| 108 | 108 |
res.AddMeta("result.txt", b.Bytes())
|
| ... | ... |
@@ -117,28 +140,7 @@ func (results *LintResults) ToResult() (*client.Result, error) {
|
| 117 | 117 |
return res, nil |
| 118 | 118 |
} |
| 119 | 119 |
|
| 120 |
-func (results *LintResults) validateWarnings() error {
|
|
| 121 |
- for _, warning := range results.Warnings {
|
|
| 122 |
- if int(warning.Location.SourceIndex) >= len(results.Sources) {
|
|
| 123 |
- return errors.Errorf("sourceIndex is out of range")
|
|
| 124 |
- } |
|
| 125 |
- if warning.Location.SourceIndex > 0 {
|
|
| 126 |
- warningSource := results.Sources[warning.Location.SourceIndex] |
|
| 127 |
- if warningSource == nil {
|
|
| 128 |
- return errors.Errorf("sourceIndex points to nil source")
|
|
| 129 |
- } |
|
| 130 |
- } |
|
| 131 |
- } |
|
| 132 |
- return nil |
|
| 133 |
-} |
|
| 134 |
- |
|
| 135 |
-func PrintLintViolations(dt []byte, w io.Writer) error {
|
|
| 136 |
- var results LintResults |
|
| 137 |
- |
|
| 138 |
- if err := json.Unmarshal(dt, &results); err != nil {
|
|
| 139 |
- return err |
|
| 140 |
- } |
|
| 141 |
- |
|
| 120 |
+func (results *LintResults) PrintTo(w io.Writer, scb SourceInfoMap) error {
|
|
| 142 | 121 |
if err := results.validateWarnings(); err != nil {
|
| 143 | 122 |
return err |
| 144 | 123 |
} |
| ... | ... |
@@ -169,21 +171,7 @@ func PrintLintViolations(dt []byte, w io.Writer) error {
|
| 169 | 169 |
}) |
| 170 | 170 |
|
| 171 | 171 |
for _, warning := range results.Warnings {
|
| 172 |
- fmt.Fprintf(w, "\nWARNING: %s", warning.RuleName) |
|
| 173 |
- if warning.URL != "" {
|
|
| 174 |
- fmt.Fprintf(w, " - %s", warning.URL) |
|
| 175 |
- } |
|
| 176 |
- fmt.Fprintf(w, "\n%s\n", warning.Detail) |
|
| 177 |
- |
|
| 178 |
- if warning.Location.SourceIndex < 0 {
|
|
| 179 |
- continue |
|
| 180 |
- } |
|
| 181 |
- sourceInfo := results.Sources[warning.Location.SourceIndex] |
|
| 182 |
- source := errdefs.Source{
|
|
| 183 |
- Info: sourceInfo, |
|
| 184 |
- Ranges: warning.Location.Ranges, |
|
| 185 |
- } |
|
| 186 |
- err := source.Print(w) |
|
| 172 |
+ err := warning.PrintTo(w, results.Sources, scb) |
|
| 187 | 173 |
if err != nil {
|
| 188 | 174 |
return err |
| 189 | 175 |
} |
| ... | ... |
@@ -192,6 +180,47 @@ func PrintLintViolations(dt []byte, w io.Writer) error {
|
| 192 | 192 |
return nil |
| 193 | 193 |
} |
| 194 | 194 |
|
| 195 |
+func (results *LintResults) PrintErrorTo(w io.Writer) {
|
|
| 196 |
+ // This prints out the error in LintResults to the writer in a format that |
|
| 197 |
+ // is consistent with the warnings for easier downstream consumption. |
|
| 198 |
+ if results.Error == nil {
|
|
| 199 |
+ return |
|
| 200 |
+ } |
|
| 201 |
+ |
|
| 202 |
+ fmt.Fprintln(w, results.Error.Message) |
|
| 203 |
+ sourceInfo := results.Sources[results.Error.Location.SourceIndex] |
|
| 204 |
+ source := errdefs.Source{
|
|
| 205 |
+ Info: sourceInfo, |
|
| 206 |
+ Ranges: results.Error.Location.Ranges, |
|
| 207 |
+ } |
|
| 208 |
+ source.Print(w) |
|
| 209 |
+} |
|
| 210 |
+ |
|
| 211 |
+func (results *LintResults) validateWarnings() error {
|
|
| 212 |
+ for _, warning := range results.Warnings {
|
|
| 213 |
+ if int(warning.Location.SourceIndex) >= len(results.Sources) {
|
|
| 214 |
+ return errors.Errorf("sourceIndex is out of range")
|
|
| 215 |
+ } |
|
| 216 |
+ if warning.Location.SourceIndex > 0 {
|
|
| 217 |
+ warningSource := results.Sources[warning.Location.SourceIndex] |
|
| 218 |
+ if warningSource == nil {
|
|
| 219 |
+ return errors.Errorf("sourceIndex points to nil source")
|
|
| 220 |
+ } |
|
| 221 |
+ } |
|
| 222 |
+ } |
|
| 223 |
+ return nil |
|
| 224 |
+} |
|
| 225 |
+ |
|
| 226 |
+func PrintLintViolations(dt []byte, w io.Writer, scb SourceInfoMap) error {
|
|
| 227 |
+ var results LintResults |
|
| 228 |
+ |
|
| 229 |
+ if err := json.Unmarshal(dt, &results); err != nil {
|
|
| 230 |
+ return err |
|
| 231 |
+ } |
|
| 232 |
+ |
|
| 233 |
+ return results.PrintTo(w, scb) |
|
| 234 |
+} |
|
| 235 |
+ |
|
| 195 | 236 |
func sourceInfoEqual(a, b *pb.SourceInfo) bool {
|
| 196 | 237 |
if a.Filename != b.Filename || a.Language != b.Language {
|
| 197 | 238 |
return false |
| ... | ... |
@@ -16,7 +16,6 @@ type Caller interface {
|
| 16 | 16 |
Context() context.Context |
| 17 | 17 |
Supports(method string) bool |
| 18 | 18 |
Conn() *grpc.ClientConn |
| 19 |
- Name() string |
|
| 20 | 19 |
SharedKey() string |
| 21 | 20 |
} |
| 22 | 21 |
|
| ... | ... |
@@ -106,7 +105,6 @@ func (sm *Manager) handleConn(ctx context.Context, conn net.Conn, opts map[strin |
| 106 | 106 |
|
| 107 | 107 |
h := http.Header(opts) |
| 108 | 108 |
id := h.Get(headerSessionID) |
| 109 |
- name := h.Get(headerSessionName) |
|
| 110 | 109 |
sharedKey := h.Get(headerSessionSharedKey) |
| 111 | 110 |
|
| 112 | 111 |
ctx, cc, err := grpcClientConn(ctx, conn) |
| ... | ... |
@@ -118,7 +116,6 @@ func (sm *Manager) handleConn(ctx context.Context, conn net.Conn, opts map[strin |
| 118 | 118 |
c := &client{
|
| 119 | 119 |
Session: Session{
|
| 120 | 120 |
id: id, |
| 121 |
- name: name, |
|
| 122 | 121 |
sharedKey: sharedKey, |
| 123 | 122 |
ctx: ctx, |
| 124 | 123 |
cancelCtx: cancel, |
| ... | ... |
@@ -197,10 +194,6 @@ func (c *client) Context() context.Context {
|
| 197 | 197 |
return c.context() |
| 198 | 198 |
} |
| 199 | 199 |
|
| 200 |
-func (c *client) Name() string {
|
|
| 201 |
- return c.name |
|
| 202 |
-} |
|
| 203 |
- |
|
| 204 | 200 |
func (c *client) SharedKey() string {
|
| 205 | 201 |
return c.sharedKey |
| 206 | 202 |
} |
| ... | ... |
@@ -38,7 +38,6 @@ type Attachable interface {
|
| 38 | 38 |
type Session struct {
|
| 39 | 39 |
mu sync.Mutex // synchronizes conn run and close |
| 40 | 40 |
id string |
| 41 |
- name string |
|
| 42 | 41 |
sharedKey string |
| 43 | 42 |
ctx context.Context |
| 44 | 43 |
cancelCtx func(error) |
| ... | ... |
@@ -49,7 +48,7 @@ type Session struct {
|
| 49 | 49 |
} |
| 50 | 50 |
|
| 51 | 51 |
// NewSession returns a new long running session |
| 52 |
-func NewSession(ctx context.Context, name, sharedKey string) (*Session, error) {
|
|
| 52 |
+func NewSession(ctx context.Context, sharedKey string) (*Session, error) {
|
|
| 53 | 53 |
id := identity.NewID() |
| 54 | 54 |
|
| 55 | 55 |
serverOpts := []grpc.ServerOption{
|
| ... | ... |
@@ -67,7 +66,6 @@ func NewSession(ctx context.Context, name, sharedKey string) (*Session, error) {
|
| 67 | 67 |
|
| 68 | 68 |
s := &Session{
|
| 69 | 69 |
id: id, |
| 70 |
- name: name, |
|
| 71 | 70 |
sharedKey: sharedKey, |
| 72 | 71 |
grpcServer: grpc.NewServer(serverOpts...), |
| 73 | 72 |
} |
| ... | ... |
@@ -103,7 +101,6 @@ func (s *Session) Run(ctx context.Context, dialer Dialer) error {
|
| 103 | 103 |
|
| 104 | 104 |
meta := make(map[string][]string) |
| 105 | 105 |
meta[headerSessionID] = []string{s.id}
|
| 106 |
- meta[headerSessionName] = []string{s.name}
|
|
| 107 | 106 |
meta[headerSessionSharedKey] = []string{s.sharedKey}
|
| 108 | 107 |
|
| 109 | 108 |
for name, svc := range s.grpcServer.GetServiceInfo() {
|
| 110 | 109 |
deleted file mode 100644 |
| ... | ... |
@@ -1,17 +0,0 @@ |
| 1 |
-package snapshot |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "context" |
|
| 5 |
- |
|
| 6 |
- "github.com/containerd/containerd/leases" |
|
| 7 |
- "github.com/containerd/containerd/snapshots" |
|
| 8 |
- "github.com/pkg/errors" |
|
| 9 |
-) |
|
| 10 |
- |
|
| 11 |
-func (sn *mergeSnapshotter) diffApply(_ context.Context, _ Mountable, _ ...Diff) (_ snapshots.Usage, rerr error) {
|
|
| 12 |
- return snapshots.Usage{}, errors.New("diffApply not yet supported on FreeBSD")
|
|
| 13 |
-} |
|
| 14 |
- |
|
| 15 |
-func needsUserXAttr(_ context.Context, _ Snapshotter, _ leases.Manager) (bool, error) {
|
|
| 16 |
- return false, errors.New("needs userxattr not supported on FreeBSD")
|
|
| 17 |
-} |
| 18 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,857 @@ |
| 0 |
+package snapshot |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "context" |
|
| 4 |
+ gofs "io/fs" |
|
| 5 |
+ "os" |
|
| 6 |
+ "path/filepath" |
|
| 7 |
+ "strings" |
|
| 8 |
+ "syscall" |
|
| 9 |
+ |
|
| 10 |
+ "github.com/containerd/containerd/leases" |
|
| 11 |
+ "github.com/containerd/containerd/mount" |
|
| 12 |
+ "github.com/containerd/containerd/snapshots" |
|
| 13 |
+ "github.com/containerd/containerd/snapshots/overlay/overlayutils" |
|
| 14 |
+ "github.com/containerd/continuity/fs" |
|
| 15 |
+ "github.com/containerd/continuity/sysx" |
|
| 16 |
+ "github.com/hashicorp/go-multierror" |
|
| 17 |
+ "github.com/moby/buildkit/identity" |
|
| 18 |
+ "github.com/moby/buildkit/util/bklog" |
|
| 19 |
+ "github.com/moby/buildkit/util/leaseutil" |
|
| 20 |
+ "github.com/moby/buildkit/util/overlay" |
|
| 21 |
+ "github.com/pkg/errors" |
|
| 22 |
+ "golang.org/x/sys/unix" |
|
| 23 |
+) |
|
| 24 |
+ |
|
| 25 |
+// diffApply applies the provided diffs to the dest Mountable and returns the correctly calculated disk usage |
|
| 26 |
+// that accounts for any hardlinks made from existing snapshots. ctx is expected to have a temporary lease |
|
| 27 |
+// associated with it. |
|
| 28 |
+func (sn *mergeSnapshotter) diffApply(ctx context.Context, dest Mountable, diffs ...Diff) (_ snapshots.Usage, rerr error) {
|
|
| 29 |
+ a, err := applierFor(dest, sn.tryCrossSnapshotLink, sn.userxattr) |
|
| 30 |
+ if err != nil {
|
|
| 31 |
+ return snapshots.Usage{}, errors.Wrapf(err, "failed to create applier")
|
|
| 32 |
+ } |
|
| 33 |
+ defer func() {
|
|
| 34 |
+ releaseErr := a.Release() |
|
| 35 |
+ if releaseErr != nil {
|
|
| 36 |
+ rerr = multierror.Append(rerr, errors.Wrapf(releaseErr, "failed to release applier")).ErrorOrNil() |
|
| 37 |
+ } |
|
| 38 |
+ }() |
|
| 39 |
+ |
|
| 40 |
+ // TODO:(sipsma) optimization: parallelize differ and applier in separate goroutines, connected with a buffered channel |
|
| 41 |
+ |
|
| 42 |
+ for _, diff := range diffs {
|
|
| 43 |
+ var lowerMntable Mountable |
|
| 44 |
+ if diff.Lower != "" {
|
|
| 45 |
+ if info, err := sn.Stat(ctx, diff.Lower); err != nil {
|
|
| 46 |
+ return snapshots.Usage{}, errors.Wrapf(err, "failed to stat lower snapshot %s", diff.Lower)
|
|
| 47 |
+ } else if info.Kind == snapshots.KindCommitted {
|
|
| 48 |
+ lowerMntable, err = sn.View(ctx, identity.NewID(), diff.Lower) |
|
| 49 |
+ if err != nil {
|
|
| 50 |
+ return snapshots.Usage{}, errors.Wrapf(err, "failed to mount lower snapshot view %s", diff.Lower)
|
|
| 51 |
+ } |
|
| 52 |
+ } else {
|
|
| 53 |
+ lowerMntable, err = sn.Mounts(ctx, diff.Lower) |
|
| 54 |
+ if err != nil {
|
|
| 55 |
+ return snapshots.Usage{}, errors.Wrapf(err, "failed to mount lower snapshot %s", diff.Lower)
|
|
| 56 |
+ } |
|
| 57 |
+ } |
|
| 58 |
+ } |
|
| 59 |
+ var upperMntable Mountable |
|
| 60 |
+ if diff.Upper != "" {
|
|
| 61 |
+ if info, err := sn.Stat(ctx, diff.Upper); err != nil {
|
|
| 62 |
+ return snapshots.Usage{}, errors.Wrapf(err, "failed to stat upper snapshot %s", diff.Upper)
|
|
| 63 |
+ } else if info.Kind == snapshots.KindCommitted {
|
|
| 64 |
+ upperMntable, err = sn.View(ctx, identity.NewID(), diff.Upper) |
|
| 65 |
+ if err != nil {
|
|
| 66 |
+ return snapshots.Usage{}, errors.Wrapf(err, "failed to mount upper snapshot view %s", diff.Upper)
|
|
| 67 |
+ } |
|
| 68 |
+ } else {
|
|
| 69 |
+ upperMntable, err = sn.Mounts(ctx, diff.Upper) |
|
| 70 |
+ if err != nil {
|
|
| 71 |
+ return snapshots.Usage{}, errors.Wrapf(err, "failed to mount upper snapshot %s", diff.Upper)
|
|
| 72 |
+ } |
|
| 73 |
+ } |
|
| 74 |
+ } else {
|
|
| 75 |
+ // create an empty view |
|
| 76 |
+ upperMntable, err = sn.View(ctx, identity.NewID(), "") |
|
| 77 |
+ if err != nil {
|
|
| 78 |
+ return snapshots.Usage{}, errors.Wrapf(err, "failed to mount empty upper snapshot view %s", diff.Upper)
|
|
| 79 |
+ } |
|
| 80 |
+ } |
|
| 81 |
+ d, err := differFor(lowerMntable, upperMntable) |
|
| 82 |
+ if err != nil {
|
|
| 83 |
+ return snapshots.Usage{}, errors.Wrapf(err, "failed to create differ")
|
|
| 84 |
+ } |
|
| 85 |
+ defer func() {
|
|
| 86 |
+ rerr = multierror.Append(rerr, d.Release()).ErrorOrNil() |
|
| 87 |
+ }() |
|
| 88 |
+ if err := d.HandleChanges(ctx, a.Apply); err != nil {
|
|
| 89 |
+ return snapshots.Usage{}, errors.Wrapf(err, "failed to handle changes")
|
|
| 90 |
+ } |
|
| 91 |
+ } |
|
| 92 |
+ |
|
| 93 |
+ if err := a.Flush(); err != nil {
|
|
| 94 |
+ return snapshots.Usage{}, errors.Wrapf(err, "failed to flush changes")
|
|
| 95 |
+ } |
|
| 96 |
+ return a.Usage() |
|
| 97 |
+} |
|
| 98 |
+ |
|
| 99 |
+type change struct {
|
|
| 100 |
+ kind fs.ChangeKind |
|
| 101 |
+ subPath string |
|
| 102 |
+ srcPath string |
|
| 103 |
+ srcStat *syscall.Stat_t |
|
| 104 |
+ // linkSubPath is set to a subPath of a previous change from the same |
|
| 105 |
+ // differ instance that is a hardlink to this one, if any. |
|
| 106 |
+ linkSubPath string |
|
| 107 |
+} |
|
| 108 |
+ |
|
| 109 |
+type changeApply struct {
|
|
| 110 |
+ *change |
|
| 111 |
+ dstPath string |
|
| 112 |
+ dstStat *syscall.Stat_t |
|
| 113 |
+ setOpaque bool |
|
| 114 |
+} |
|
| 115 |
+ |
|
| 116 |
+type inode struct {
|
|
| 117 |
+ ino uint64 |
|
| 118 |
+ dev uint64 |
|
| 119 |
+} |
|
| 120 |
+ |
|
| 121 |
+func statInode(stat *syscall.Stat_t) inode {
|
|
| 122 |
+ if stat == nil {
|
|
| 123 |
+ return inode{}
|
|
| 124 |
+ } |
|
| 125 |
+ return inode{
|
|
| 126 |
+ ino: stat.Ino, |
|
| 127 |
+ dev: stat.Dev, |
|
| 128 |
+ } |
|
| 129 |
+} |
|
| 130 |
+ |
|
| 131 |
+type applier struct {
|
|
| 132 |
+ root string |
|
| 133 |
+ release func() error |
|
| 134 |
+ lowerdirs []string // ordered highest -> lowest, the order we want to check them in |
|
| 135 |
+ crossSnapshotLinks map[inode]struct{}
|
|
| 136 |
+ createWhiteoutDelete bool |
|
| 137 |
+ userxattr bool |
|
| 138 |
+ dirModTimes map[string]unix.Timespec // map of dstPath -> mtime that should be set on that subPath |
|
| 139 |
+} |
|
| 140 |
+ |
|
| 141 |
+func applierFor(dest Mountable, tryCrossSnapshotLink, userxattr bool) (_ *applier, rerr error) {
|
|
| 142 |
+ a := &applier{
|
|
| 143 |
+ dirModTimes: make(map[string]unix.Timespec), |
|
| 144 |
+ userxattr: userxattr, |
|
| 145 |
+ } |
|
| 146 |
+ defer func() {
|
|
| 147 |
+ if rerr != nil {
|
|
| 148 |
+ rerr = multierror.Append(rerr, a.Release()).ErrorOrNil() |
|
| 149 |
+ } |
|
| 150 |
+ }() |
|
| 151 |
+ if tryCrossSnapshotLink {
|
|
| 152 |
+ a.crossSnapshotLinks = make(map[inode]struct{})
|
|
| 153 |
+ } |
|
| 154 |
+ |
|
| 155 |
+ mnts, release, err := dest.Mount() |
|
| 156 |
+ if err != nil {
|
|
| 157 |
+ return nil, nil |
|
| 158 |
+ } |
|
| 159 |
+ a.release = release |
|
| 160 |
+ |
|
| 161 |
+ if len(mnts) != 1 {
|
|
| 162 |
+ return nil, errors.Errorf("expected exactly one mount, got %d", len(mnts))
|
|
| 163 |
+ } |
|
| 164 |
+ mnt := mnts[0] |
|
| 165 |
+ |
|
| 166 |
+ if overlay.IsOverlayMountType(mnt) {
|
|
| 167 |
+ for _, opt := range mnt.Options {
|
|
| 168 |
+ if strings.HasPrefix(opt, "upperdir=") {
|
|
| 169 |
+ a.root = strings.TrimPrefix(opt, "upperdir=") |
|
| 170 |
+ } else if strings.HasPrefix(opt, "lowerdir=") {
|
|
| 171 |
+ a.lowerdirs = strings.Split(strings.TrimPrefix(opt, "lowerdir="), ":") |
|
| 172 |
+ } |
|
| 173 |
+ } |
|
| 174 |
+ if a.root == "" {
|
|
| 175 |
+ return nil, errors.Errorf("could not find upperdir in mount options %v", mnt.Options)
|
|
| 176 |
+ } |
|
| 177 |
+ if len(a.lowerdirs) == 0 {
|
|
| 178 |
+ return nil, errors.Errorf("could not find lowerdir in mount options %v", mnt.Options)
|
|
| 179 |
+ } |
|
| 180 |
+ a.createWhiteoutDelete = true |
|
| 181 |
+ } else if mnt.Type == "bind" || mnt.Type == "rbind" {
|
|
| 182 |
+ a.root = mnt.Source |
|
| 183 |
+ } else {
|
|
| 184 |
+ mnter := LocalMounter(dest) |
|
| 185 |
+ root, err := mnter.Mount() |
|
| 186 |
+ if err != nil {
|
|
| 187 |
+ return nil, err |
|
| 188 |
+ } |
|
| 189 |
+ a.root = root |
|
| 190 |
+ prevRelease := a.release |
|
| 191 |
+ a.release = func() error {
|
|
| 192 |
+ err := mnter.Unmount() |
|
| 193 |
+ return multierror.Append(err, prevRelease()).ErrorOrNil() |
|
| 194 |
+ } |
|
| 195 |
+ } |
|
| 196 |
+ |
|
| 197 |
+ a.root, err = filepath.EvalSymlinks(a.root) |
|
| 198 |
+ if err != nil {
|
|
| 199 |
+ return nil, errors.Wrapf(err, "failed to resolve symlinks in %s", a.root) |
|
| 200 |
+ } |
|
| 201 |
+ return a, nil |
|
| 202 |
+} |
|
| 203 |
+ |
|
| 204 |
+func (a *applier) Apply(ctx context.Context, c *change) error {
|
|
| 205 |
+ if c == nil {
|
|
| 206 |
+ return errors.New("nil change")
|
|
| 207 |
+ } |
|
| 208 |
+ |
|
| 209 |
+ if c.kind == fs.ChangeKindUnmodified {
|
|
| 210 |
+ return nil |
|
| 211 |
+ } |
|
| 212 |
+ |
|
| 213 |
+ dstPath, err := safeJoin(a.root, c.subPath) |
|
| 214 |
+ if err != nil {
|
|
| 215 |
+ return errors.Wrapf(err, "failed to join paths %q and %q", a.root, c.subPath) |
|
| 216 |
+ } |
|
| 217 |
+ var dstStat *syscall.Stat_t |
|
| 218 |
+ if dstfi, err := os.Lstat(dstPath); err == nil {
|
|
| 219 |
+ stat, ok := dstfi.Sys().(*syscall.Stat_t) |
|
| 220 |
+ if !ok {
|
|
| 221 |
+ return errors.Errorf("failed to get stat_t for %T", dstStat)
|
|
| 222 |
+ } |
|
| 223 |
+ dstStat = stat |
|
| 224 |
+ } else if !os.IsNotExist(err) {
|
|
| 225 |
+ return errors.Wrap(err, "failed to stat during copy apply") |
|
| 226 |
+ } |
|
| 227 |
+ |
|
| 228 |
+ ca := &changeApply{
|
|
| 229 |
+ change: c, |
|
| 230 |
+ dstPath: dstPath, |
|
| 231 |
+ dstStat: dstStat, |
|
| 232 |
+ } |
|
| 233 |
+ |
|
| 234 |
+ if done, err := a.applyDelete(ca); err != nil {
|
|
| 235 |
+ return errors.Wrap(err, "failed to delete during apply") |
|
| 236 |
+ } else if done {
|
|
| 237 |
+ return nil |
|
| 238 |
+ } |
|
| 239 |
+ |
|
| 240 |
+ if done, err := a.applyHardlink(ctx, ca); err != nil {
|
|
| 241 |
+ return errors.Wrapf(err, "failed to hardlink during apply") |
|
| 242 |
+ } else if done {
|
|
| 243 |
+ return nil |
|
| 244 |
+ } |
|
| 245 |
+ |
|
| 246 |
+ if err := a.applyCopy(ctx, ca); err != nil {
|
|
| 247 |
+ return errors.Wrapf(err, "failed to copy during apply") |
|
| 248 |
+ } |
|
| 249 |
+ return nil |
|
| 250 |
+} |
|
| 251 |
+ |
|
| 252 |
+func (a *applier) applyDelete(ca *changeApply) (bool, error) {
|
|
| 253 |
+ // Even when not deleting, we may be overwriting a file, in which case we should |
|
| 254 |
+ // delete the existing file at the path, if any. Don't delete when both are dirs |
|
| 255 |
+ // in this case though because they should get merged, not overwritten. |
|
| 256 |
+ deleteOnly := ca.kind == fs.ChangeKindDelete |
|
| 257 |
+ overwrite := !deleteOnly && ca.dstStat != nil && ca.srcStat.Mode&ca.dstStat.Mode&unix.S_IFMT != unix.S_IFDIR |
|
| 258 |
+ |
|
| 259 |
+ if !deleteOnly && !overwrite {
|
|
| 260 |
+ // nothing to delete, continue on |
|
| 261 |
+ return false, nil |
|
| 262 |
+ } |
|
| 263 |
+ |
|
| 264 |
+ if err := os.RemoveAll(ca.dstPath); err != nil {
|
|
| 265 |
+ return false, errors.Wrap(err, "failed to remove during apply") |
|
| 266 |
+ } |
|
| 267 |
+ ca.dstStat = nil |
|
| 268 |
+ |
|
| 269 |
+ if overwrite && a.createWhiteoutDelete && ca.srcStat.Mode&unix.S_IFMT == unix.S_IFDIR {
|
|
| 270 |
+ // If we are using an overlay snapshotter and overwriting an existing non-directory |
|
| 271 |
+ // with a directory, we need this new dir to be opaque so that any files from lowerdirs |
|
| 272 |
+ // under it are not visible. |
|
| 273 |
+ ca.setOpaque = true |
|
| 274 |
+ } |
|
| 275 |
+ |
|
| 276 |
+ if deleteOnly && a.createWhiteoutDelete {
|
|
| 277 |
+ // only create a whiteout device if there is something to delete |
|
| 278 |
+ var foundLower bool |
|
| 279 |
+ for _, lowerdir := range a.lowerdirs {
|
|
| 280 |
+ lowerPath, err := safeJoin(lowerdir, ca.subPath) |
|
| 281 |
+ if err != nil {
|
|
| 282 |
+ return false, errors.Wrapf(err, "failed to join lowerdir %q and subPath %q", lowerdir, ca.subPath) |
|
| 283 |
+ } |
|
| 284 |
+ if _, err := os.Lstat(lowerPath); err == nil {
|
|
| 285 |
+ foundLower = true |
|
| 286 |
+ break |
|
| 287 |
+ } else if !errors.Is(err, unix.ENOENT) && !errors.Is(err, unix.ENOTDIR) {
|
|
| 288 |
+ return false, errors.Wrapf(err, "failed to stat lowerPath %q", lowerPath) |
|
| 289 |
+ } |
|
| 290 |
+ } |
|
| 291 |
+ if foundLower {
|
|
| 292 |
+ ca.kind = fs.ChangeKindAdd |
|
| 293 |
+ if ca.srcStat == nil {
|
|
| 294 |
+ ca.srcStat = &syscall.Stat_t{
|
|
| 295 |
+ Mode: syscall.S_IFCHR, |
|
| 296 |
+ Rdev: unix.Mkdev(0, 0), |
|
| 297 |
+ } |
|
| 298 |
+ ca.srcPath = "" |
|
| 299 |
+ } |
|
| 300 |
+ return false, nil |
|
| 301 |
+ } |
|
| 302 |
+ } |
|
| 303 |
+ |
|
| 304 |
+ return deleteOnly, nil |
|
| 305 |
+} |
|
| 306 |
+ |
|
| 307 |
+func (a *applier) applyHardlink(ctx context.Context, ca *changeApply) (bool, error) {
|
|
| 308 |
+ switch ca.srcStat.Mode & unix.S_IFMT {
|
|
| 309 |
+ case unix.S_IFDIR, unix.S_IFIFO, unix.S_IFSOCK: |
|
| 310 |
+ // Directories can't be hard-linked, so they just have to be recreated. |
|
| 311 |
+ // Named pipes and sockets can be hard-linked but is best to avoid as it could enable IPC in weird cases. |
|
| 312 |
+ return false, nil |
|
| 313 |
+ |
|
| 314 |
+ default: |
|
| 315 |
+ var linkSrcPath string |
|
| 316 |
+ if ca.linkSubPath != "" {
|
|
| 317 |
+ // there's an already applied path that we should link from |
|
| 318 |
+ path, err := safeJoin(a.root, ca.linkSubPath) |
|
| 319 |
+ if err != nil {
|
|
| 320 |
+ return false, errors.Errorf("failed to get hardlink source path: %v", err)
|
|
| 321 |
+ } |
|
| 322 |
+ linkSrcPath = path |
|
| 323 |
+ } else if a.crossSnapshotLinks != nil {
|
|
| 324 |
+ // we can try to link across snapshots from the source file |
|
| 325 |
+ linkSrcPath = ca.srcPath |
|
| 326 |
+ a.crossSnapshotLinks[statInode(ca.srcStat)] = struct{}{}
|
|
| 327 |
+ } |
|
| 328 |
+ if linkSrcPath == "" {
|
|
| 329 |
+ // nothing to hardlink from, will have to copy the file |
|
| 330 |
+ return false, nil |
|
| 331 |
+ } |
|
| 332 |
+ |
|
| 333 |
+ if err := os.Link(linkSrcPath, ca.dstPath); errors.Is(err, unix.EXDEV) || errors.Is(err, unix.EMLINK) {
|
|
| 334 |
+ // These errors are expected when the hardlink would cross devices or would exceed the maximum number of links for the inode. |
|
| 335 |
+ // Just fallback to a copy. |
|
| 336 |
+ bklog.G(ctx).WithError(err).WithField("srcPath", linkSrcPath).WithField("dstPath", ca.dstPath).Debug("hardlink failed")
|
|
| 337 |
+ if a.crossSnapshotLinks != nil {
|
|
| 338 |
+ delete(a.crossSnapshotLinks, statInode(ca.srcStat)) |
|
| 339 |
+ } |
|
| 340 |
+ return false, nil |
|
| 341 |
+ } else if err != nil {
|
|
| 342 |
+ return false, errors.Wrap(err, "failed to hardlink during apply") |
|
| 343 |
+ } |
|
| 344 |
+ |
|
| 345 |
+ return true, nil |
|
| 346 |
+ } |
|
| 347 |
+} |
|
| 348 |
+ |
|
| 349 |
+func (a *applier) applyCopy(ctx context.Context, ca *changeApply) error {
|
|
| 350 |
+ switch ca.srcStat.Mode & unix.S_IFMT {
|
|
| 351 |
+ case unix.S_IFREG: |
|
| 352 |
+ if err := fs.CopyFile(ca.dstPath, ca.srcPath); err != nil {
|
|
| 353 |
+ return errors.Wrapf(err, "failed to copy from %s to %s during apply", ca.srcPath, ca.dstPath) |
|
| 354 |
+ } |
|
| 355 |
+ case unix.S_IFDIR: |
|
| 356 |
+ if ca.dstStat == nil {
|
|
| 357 |
+ // dstPath doesn't exist, make it a dir |
|
| 358 |
+ if err := unix.Mkdir(ca.dstPath, ca.srcStat.Mode); err != nil {
|
|
| 359 |
+ return errors.Wrapf(err, "failed to create applied dir at %q from %q", ca.dstPath, ca.srcPath) |
|
| 360 |
+ } |
|
| 361 |
+ } |
|
| 362 |
+ case unix.S_IFLNK: |
|
| 363 |
+ if target, err := os.Readlink(ca.srcPath); err != nil {
|
|
| 364 |
+ return errors.Wrap(err, "failed to read symlink during apply") |
|
| 365 |
+ } else if err := os.Symlink(target, ca.dstPath); err != nil {
|
|
| 366 |
+ return errors.Wrap(err, "failed to create symlink during apply") |
|
| 367 |
+ } |
|
| 368 |
+ case unix.S_IFBLK, unix.S_IFCHR, unix.S_IFIFO, unix.S_IFSOCK: |
|
| 369 |
+ if err := unix.Mknod(ca.dstPath, ca.srcStat.Mode, int(ca.srcStat.Rdev)); err != nil {
|
|
| 370 |
+ return errors.Wrap(err, "failed to mknod during apply") |
|
| 371 |
+ } |
|
| 372 |
+ default: |
|
| 373 |
+ // should never be here, all types should be handled |
|
| 374 |
+ return errors.Errorf("unhandled file type %d during merge at path %q", ca.srcStat.Mode&unix.S_IFMT, ca.srcPath)
|
|
| 375 |
+ } |
|
| 376 |
+ |
|
| 377 |
+ // NOTE: it's important that chown happens before setting xattrs due to the fact that chown will |
|
| 378 |
+ // reset the security.capabilities xattr which results in file capabilities being lost. |
|
| 379 |
+ if err := os.Lchown(ca.dstPath, int(ca.srcStat.Uid), int(ca.srcStat.Gid)); err != nil {
|
|
| 380 |
+ return errors.Wrap(err, "failed to chown during apply") |
|
| 381 |
+ } |
|
| 382 |
+ |
|
| 383 |
+ if ca.srcStat.Mode&unix.S_IFMT != unix.S_IFLNK {
|
|
| 384 |
+ if err := unix.Chmod(ca.dstPath, ca.srcStat.Mode); err != nil {
|
|
| 385 |
+ return errors.Wrapf(err, "failed to chmod path %q during apply", ca.dstPath) |
|
| 386 |
+ } |
|
| 387 |
+ } |
|
| 388 |
+ |
|
| 389 |
+ if ca.srcPath != "" {
|
|
| 390 |
+ xattrs, err := sysx.LListxattr(ca.srcPath) |
|
| 391 |
+ if err != nil {
|
|
| 392 |
+ return errors.Wrapf(err, "failed to list xattrs of src path %s", ca.srcPath) |
|
| 393 |
+ } |
|
| 394 |
+ for _, xattr := range xattrs {
|
|
| 395 |
+ if isOpaqueXattr(xattr) {
|
|
| 396 |
+ // Don't recreate opaque xattrs during merge based on the source file. The differs take care of converting |
|
| 397 |
+ // source path from the "opaque whiteout" format to the "explicit whiteout" format. The only time we set |
|
| 398 |
+ // opaque xattrs is handled after this loop below. |
|
| 399 |
+ continue |
|
| 400 |
+ } |
|
| 401 |
+ xattrVal, err := sysx.LGetxattr(ca.srcPath, xattr) |
|
| 402 |
+ if err != nil {
|
|
| 403 |
+ return errors.Wrapf(err, "failed to get xattr %s of src path %s", xattr, ca.srcPath) |
|
| 404 |
+ } |
|
| 405 |
+ if err := sysx.LSetxattr(ca.dstPath, xattr, xattrVal, 0); err != nil {
|
|
| 406 |
+ // This can often fail, so just log it: https://github.com/moby/buildkit/issues/1189 |
|
| 407 |
+ bklog.G(ctx).Debugf("failed to set xattr %s of path %s during apply", xattr, ca.dstPath)
|
|
| 408 |
+ } |
|
| 409 |
+ } |
|
| 410 |
+ } |
|
| 411 |
+ |
|
| 412 |
+ if ca.setOpaque {
|
|
| 413 |
+ // This is set in the case where we are creating a directory that is replacing a whiteout device |
|
| 414 |
+ xattr := opaqueXattr(a.userxattr) |
|
| 415 |
+ if err := sysx.LSetxattr(ca.dstPath, xattr, []byte{'y'}, 0); err != nil {
|
|
| 416 |
+ return errors.Wrapf(err, "failed to set opaque xattr %q of path %s", xattr, ca.dstPath) |
|
| 417 |
+ } |
|
| 418 |
+ } |
|
| 419 |
+ |
|
| 420 |
+ atimeSpec := unix.Timespec{Sec: ca.srcStat.Atim.Sec, Nsec: ca.srcStat.Atim.Nsec}
|
|
| 421 |
+ mtimeSpec := unix.Timespec{Sec: ca.srcStat.Mtim.Sec, Nsec: ca.srcStat.Mtim.Nsec}
|
|
| 422 |
+ if ca.srcStat.Mode&unix.S_IFMT != unix.S_IFDIR {
|
|
| 423 |
+ // apply times immediately for non-dirs |
|
| 424 |
+ if err := unix.UtimesNanoAt(unix.AT_FDCWD, ca.dstPath, []unix.Timespec{atimeSpec, mtimeSpec}, unix.AT_SYMLINK_NOFOLLOW); err != nil {
|
|
| 425 |
+ return err |
|
| 426 |
+ } |
|
| 427 |
+ } else {
|
|
| 428 |
+ // save the times we should set on this dir, to be applied after subfiles have been set |
|
| 429 |
+ a.dirModTimes[ca.dstPath] = mtimeSpec |
|
| 430 |
+ } |
|
| 431 |
+ |
|
| 432 |
+ return nil |
|
| 433 |
+} |
|
| 434 |
+ |
|
| 435 |
+func (a *applier) Flush() error {
|
|
| 436 |
+ // Set dir times now that everything has been modified. Walk the filesystem tree to ensure |
|
| 437 |
+ // that we never try to apply to a path that has been deleted or modified since times for it |
|
| 438 |
+ // were stored. This is needed for corner cases such as where a parent dir is removed and |
|
| 439 |
+ // replaced with a symlink. |
|
| 440 |
+ return filepath.WalkDir(a.root, func(path string, d gofs.DirEntry, prevErr error) error {
|
|
| 441 |
+ if prevErr != nil {
|
|
| 442 |
+ return prevErr |
|
| 443 |
+ } |
|
| 444 |
+ if !d.IsDir() {
|
|
| 445 |
+ return nil |
|
| 446 |
+ } |
|
| 447 |
+ if mtime, ok := a.dirModTimes[path]; ok {
|
|
| 448 |
+ if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, []unix.Timespec{{Nsec: unix.UTIME_OMIT}, mtime}, unix.AT_SYMLINK_NOFOLLOW); err != nil {
|
|
| 449 |
+ return err |
|
| 450 |
+ } |
|
| 451 |
+ } |
|
| 452 |
+ return nil |
|
| 453 |
+ }) |
|
| 454 |
+} |
|
| 455 |
+ |
|
| 456 |
+func (a *applier) Release() error {
|
|
| 457 |
+ if a.release != nil {
|
|
| 458 |
+ err := a.release() |
|
| 459 |
+ if err != nil {
|
|
| 460 |
+ return err |
|
| 461 |
+ } |
|
| 462 |
+ } |
|
| 463 |
+ a.release = nil |
|
| 464 |
+ return nil |
|
| 465 |
+} |
|
| 466 |
+ |
|
| 467 |
+func (a *applier) Usage() (snapshots.Usage, error) {
|
|
| 468 |
+ // Calculate the disk space used under the apply root, similar to the normal containerd snapshotter disk usage |
|
| 469 |
+ // calculations but with the extra ability to take into account hardlinks that were created between snapshots, ensuring that |
|
| 470 |
+ // they don't get double counted. |
|
| 471 |
+ inodes := make(map[inode]struct{})
|
|
| 472 |
+ var usage snapshots.Usage |
|
| 473 |
+ if err := filepath.WalkDir(a.root, func(path string, dirent gofs.DirEntry, err error) error {
|
|
| 474 |
+ if err != nil {
|
|
| 475 |
+ return err |
|
| 476 |
+ } |
|
| 477 |
+ info, err := dirent.Info() |
|
| 478 |
+ if err != nil {
|
|
| 479 |
+ return err |
|
| 480 |
+ } |
|
| 481 |
+ stat := info.Sys().(*syscall.Stat_t) |
|
| 482 |
+ inode := statInode(stat) |
|
| 483 |
+ if _, ok := inodes[inode]; ok {
|
|
| 484 |
+ return nil |
|
| 485 |
+ } |
|
| 486 |
+ inodes[inode] = struct{}{}
|
|
| 487 |
+ if a.crossSnapshotLinks != nil {
|
|
| 488 |
+ if _, ok := a.crossSnapshotLinks[statInode(stat)]; ok {
|
|
| 489 |
+ // don't count cross-snapshot hardlinks |
|
| 490 |
+ return nil |
|
| 491 |
+ } |
|
| 492 |
+ } |
|
| 493 |
+ usage.Inodes++ |
|
| 494 |
+ usage.Size += stat.Blocks * 512 // 512 is always block size, see "man 2 stat" |
|
| 495 |
+ return nil |
|
| 496 |
+ }); err != nil {
|
|
| 497 |
+ return snapshots.Usage{}, err
|
|
| 498 |
+ } |
|
| 499 |
+ return usage, nil |
|
| 500 |
+} |
|
| 501 |
+ |
|
| 502 |
+type differ struct {
|
|
| 503 |
+ lowerRoot string |
|
| 504 |
+ releaseLower func() error |
|
| 505 |
+ |
|
| 506 |
+ upperRoot string |
|
| 507 |
+ releaseUpper func() error |
|
| 508 |
+ |
|
| 509 |
+ upperBindSource string |
|
| 510 |
+ upperOverlayDirs []string // ordered lowest -> highest |
|
| 511 |
+ |
|
| 512 |
+ upperdir string |
|
| 513 |
+ |
|
| 514 |
+ visited map[string]struct{} // set of parent subPaths that have been visited
|
|
| 515 |
+ inodes map[inode]string // map of inode -> subPath |
|
| 516 |
+} |
|
| 517 |
+ |
|
| 518 |
+func differFor(lowerMntable, upperMntable Mountable) (_ *differ, rerr error) {
|
|
| 519 |
+ d := &differ{
|
|
| 520 |
+ visited: make(map[string]struct{}),
|
|
| 521 |
+ inodes: make(map[inode]string), |
|
| 522 |
+ } |
|
| 523 |
+ defer func() {
|
|
| 524 |
+ if rerr != nil {
|
|
| 525 |
+ rerr = multierror.Append(rerr, d.Release()).ErrorOrNil() |
|
| 526 |
+ } |
|
| 527 |
+ }() |
|
| 528 |
+ |
|
| 529 |
+ var lowerMnts []mount.Mount |
|
| 530 |
+ if lowerMntable != nil {
|
|
| 531 |
+ mnts, release, err := lowerMntable.Mount() |
|
| 532 |
+ if err != nil {
|
|
| 533 |
+ return nil, err |
|
| 534 |
+ } |
|
| 535 |
+ mounter := LocalMounterWithMounts(mnts) |
|
| 536 |
+ root, err := mounter.Mount() |
|
| 537 |
+ if err != nil {
|
|
| 538 |
+ return nil, err |
|
| 539 |
+ } |
|
| 540 |
+ d.lowerRoot = root |
|
| 541 |
+ lowerMnts = mnts |
|
| 542 |
+ d.releaseLower = func() error {
|
|
| 543 |
+ err := mounter.Unmount() |
|
| 544 |
+ return multierror.Append(err, release()).ErrorOrNil() |
|
| 545 |
+ } |
|
| 546 |
+ } |
|
| 547 |
+ |
|
| 548 |
+ var upperMnts []mount.Mount |
|
| 549 |
+ if upperMntable != nil {
|
|
| 550 |
+ mnts, release, err := upperMntable.Mount() |
|
| 551 |
+ if err != nil {
|
|
| 552 |
+ return nil, err |
|
| 553 |
+ } |
|
| 554 |
+ mounter := LocalMounterWithMounts(mnts) |
|
| 555 |
+ root, err := mounter.Mount() |
|
| 556 |
+ if err != nil {
|
|
| 557 |
+ return nil, err |
|
| 558 |
+ } |
|
| 559 |
+ d.upperRoot = root |
|
| 560 |
+ upperMnts = mnts |
|
| 561 |
+ d.releaseUpper = func() error {
|
|
| 562 |
+ err := mounter.Unmount() |
|
| 563 |
+ return multierror.Append(err, release()).ErrorOrNil() |
|
| 564 |
+ } |
|
| 565 |
+ } |
|
| 566 |
+ |
|
| 567 |
+ if len(upperMnts) == 1 {
|
|
| 568 |
+ if upperMnts[0].Type == "bind" || upperMnts[0].Type == "rbind" {
|
|
| 569 |
+ d.upperBindSource = upperMnts[0].Source |
|
| 570 |
+ } else if overlay.IsOverlayMountType(upperMnts[0]) {
|
|
| 571 |
+ overlayDirs, err := overlay.GetOverlayLayers(upperMnts[0]) |
|
| 572 |
+ if err != nil {
|
|
| 573 |
+ return nil, errors.Wrapf(err, "failed to get overlay layers from mount %+v", upperMnts[0]) |
|
| 574 |
+ } |
|
| 575 |
+ d.upperOverlayDirs = overlayDirs |
|
| 576 |
+ } |
|
| 577 |
+ } |
|
| 578 |
+ if len(lowerMnts) > 0 {
|
|
| 579 |
+ if upperdir, err := overlay.GetUpperdir(lowerMnts, upperMnts); err == nil {
|
|
| 580 |
+ d.upperdir = upperdir |
|
| 581 |
+ } |
|
| 582 |
+ } |
|
| 583 |
+ |
|
| 584 |
+ return d, nil |
|
| 585 |
+} |
|
| 586 |
+ |
|
| 587 |
+func (d *differ) HandleChanges(ctx context.Context, handle func(context.Context, *change) error) error {
|
|
| 588 |
+ if d.upperdir != "" {
|
|
| 589 |
+ return d.overlayChanges(ctx, handle) |
|
| 590 |
+ } |
|
| 591 |
+ return d.doubleWalkingChanges(ctx, handle) |
|
| 592 |
+} |
|
| 593 |
+ |
|
| 594 |
+func (d *differ) doubleWalkingChanges(ctx context.Context, handle func(context.Context, *change) error) error {
|
|
| 595 |
+ return fs.Changes(ctx, d.lowerRoot, d.upperRoot, func(kind fs.ChangeKind, subPath string, srcfi os.FileInfo, prevErr error) error {
|
|
| 596 |
+ if prevErr != nil {
|
|
| 597 |
+ return prevErr |
|
| 598 |
+ } |
|
| 599 |
+ select {
|
|
| 600 |
+ case <-ctx.Done(): |
|
| 601 |
+ return context.Cause(ctx) |
|
| 602 |
+ default: |
|
| 603 |
+ } |
|
| 604 |
+ |
|
| 605 |
+ if kind == fs.ChangeKindUnmodified {
|
|
| 606 |
+ return nil |
|
| 607 |
+ } |
|
| 608 |
+ |
|
| 609 |
+ // NOTE: it's tempting to skip creating parent dirs when change kind is Delete, but |
|
| 610 |
+ // that would make us incompatible with the image exporter code: |
|
| 611 |
+ // https://github.com/containerd/containerd/pull/2095 |
|
| 612 |
+ if err := d.checkParent(ctx, subPath, handle); err != nil {
|
|
| 613 |
+ return errors.Wrapf(err, "failed to check parent for %s", subPath) |
|
| 614 |
+ } |
|
| 615 |
+ |
|
| 616 |
+ c := &change{
|
|
| 617 |
+ kind: kind, |
|
| 618 |
+ subPath: subPath, |
|
| 619 |
+ } |
|
| 620 |
+ |
|
| 621 |
+ if srcfi != nil {
|
|
| 622 |
+ // Try to ensure that srcPath and srcStat are set to a file from the underlying filesystem |
|
| 623 |
+ // rather than the actual mount when possible. This allows hardlinking without getting EXDEV. |
|
| 624 |
+ switch {
|
|
| 625 |
+ case !srcfi.IsDir() && d.upperBindSource != "": |
|
| 626 |
+ srcPath, err := safeJoin(d.upperBindSource, c.subPath) |
|
| 627 |
+ if err != nil {
|
|
| 628 |
+ return errors.Wrapf(err, "failed to join %s and %s", d.upperBindSource, c.subPath) |
|
| 629 |
+ } |
|
| 630 |
+ c.srcPath = srcPath |
|
| 631 |
+ if fi, err := os.Lstat(c.srcPath); err == nil {
|
|
| 632 |
+ srcfi = fi |
|
| 633 |
+ } else {
|
|
| 634 |
+ return errors.Wrap(err, "failed to stat underlying file from bind mount") |
|
| 635 |
+ } |
|
| 636 |
+ case !srcfi.IsDir() && len(d.upperOverlayDirs) > 0: |
|
| 637 |
+ for i := range d.upperOverlayDirs {
|
|
| 638 |
+ dir := d.upperOverlayDirs[len(d.upperOverlayDirs)-1-i] |
|
| 639 |
+ path, err := safeJoin(dir, c.subPath) |
|
| 640 |
+ if err != nil {
|
|
| 641 |
+ return errors.Wrapf(err, "failed to join %s and %s", dir, c.subPath) |
|
| 642 |
+ } |
|
| 643 |
+ if stat, err := os.Lstat(path); err == nil {
|
|
| 644 |
+ c.srcPath = path |
|
| 645 |
+ srcfi = stat |
|
| 646 |
+ break |
|
| 647 |
+ } else if errors.Is(err, unix.ENOENT) {
|
|
| 648 |
+ continue |
|
| 649 |
+ } else {
|
|
| 650 |
+ return errors.Wrap(err, "failed to lstat when finding direct path of overlay file") |
|
| 651 |
+ } |
|
| 652 |
+ } |
|
| 653 |
+ default: |
|
| 654 |
+ srcPath, err := safeJoin(d.upperRoot, subPath) |
|
| 655 |
+ if err != nil {
|
|
| 656 |
+ return errors.Wrapf(err, "failed to join %s and %s", d.upperRoot, subPath) |
|
| 657 |
+ } |
|
| 658 |
+ c.srcPath = srcPath |
|
| 659 |
+ if fi, err := os.Lstat(c.srcPath); err == nil {
|
|
| 660 |
+ srcfi = fi |
|
| 661 |
+ } else {
|
|
| 662 |
+ return errors.Wrap(err, "failed to stat srcPath from differ") |
|
| 663 |
+ } |
|
| 664 |
+ } |
|
| 665 |
+ |
|
| 666 |
+ var ok bool |
|
| 667 |
+ c.srcStat, ok = srcfi.Sys().(*syscall.Stat_t) |
|
| 668 |
+ if !ok {
|
|
| 669 |
+ return errors.Errorf("unhandled stat type for %+v", srcfi)
|
|
| 670 |
+ } |
|
| 671 |
+ |
|
| 672 |
+ if !srcfi.IsDir() && c.srcStat.Nlink > 1 {
|
|
| 673 |
+ if linkSubPath, ok := d.inodes[statInode(c.srcStat)]; ok {
|
|
| 674 |
+ c.linkSubPath = linkSubPath |
|
| 675 |
+ } else {
|
|
| 676 |
+ d.inodes[statInode(c.srcStat)] = c.subPath |
|
| 677 |
+ } |
|
| 678 |
+ } |
|
| 679 |
+ } |
|
| 680 |
+ |
|
| 681 |
+ return handle(ctx, c) |
|
| 682 |
+ }) |
|
| 683 |
+} |
|
| 684 |
+ |
|
| 685 |
+func (d *differ) overlayChanges(ctx context.Context, handle func(context.Context, *change) error) error {
|
|
| 686 |
+ return overlay.Changes(ctx, func(kind fs.ChangeKind, subPath string, srcfi os.FileInfo, prevErr error) error {
|
|
| 687 |
+ if prevErr != nil {
|
|
| 688 |
+ return prevErr |
|
| 689 |
+ } |
|
| 690 |
+ |
|
| 691 |
+ select {
|
|
| 692 |
+ case <-ctx.Done(): |
|
| 693 |
+ return context.Cause(ctx) |
|
| 694 |
+ default: |
|
| 695 |
+ } |
|
| 696 |
+ |
|
| 697 |
+ if kind == fs.ChangeKindUnmodified {
|
|
| 698 |
+ return nil |
|
| 699 |
+ } |
|
| 700 |
+ |
|
| 701 |
+ if err := d.checkParent(ctx, subPath, handle); err != nil {
|
|
| 702 |
+ return errors.Wrapf(err, "failed to check parent for %s", subPath) |
|
| 703 |
+ } |
|
| 704 |
+ |
|
| 705 |
+ srcPath, err := safeJoin(d.upperdir, subPath) |
|
| 706 |
+ if err != nil {
|
|
| 707 |
+ return errors.Wrapf(err, "failed to join %s and %s", d.upperdir, subPath) |
|
| 708 |
+ } |
|
| 709 |
+ |
|
| 710 |
+ c := &change{
|
|
| 711 |
+ kind: kind, |
|
| 712 |
+ subPath: subPath, |
|
| 713 |
+ srcPath: srcPath, |
|
| 714 |
+ } |
|
| 715 |
+ |
|
| 716 |
+ if srcfi != nil {
|
|
| 717 |
+ var ok bool |
|
| 718 |
+ c.srcStat, ok = srcfi.Sys().(*syscall.Stat_t) |
|
| 719 |
+ if !ok {
|
|
| 720 |
+ return errors.Errorf("unhandled stat type for %+v", srcfi)
|
|
| 721 |
+ } |
|
| 722 |
+ |
|
| 723 |
+ // Changes with Delete kind may share the same inode even if they are unrelated. |
|
| 724 |
+ // Skip them to avoid creating hardlinks between whiteouts as whiteouts are not |
|
| 725 |
+ // always created and may leave the hardlink dangling. |
|
| 726 |
+ if !srcfi.IsDir() && c.srcStat.Nlink > 1 && c.kind != fs.ChangeKindDelete {
|
|
| 727 |
+ if linkSubPath, ok := d.inodes[statInode(c.srcStat)]; ok {
|
|
| 728 |
+ c.linkSubPath = linkSubPath |
|
| 729 |
+ } else {
|
|
| 730 |
+ d.inodes[statInode(c.srcStat)] = c.subPath |
|
| 731 |
+ } |
|
| 732 |
+ } |
|
| 733 |
+ } |
|
| 734 |
+ |
|
| 735 |
+ return handle(ctx, c) |
|
| 736 |
+ }, d.upperdir, d.upperRoot, d.lowerRoot) |
|
| 737 |
+} |
|
| 738 |
+ |
|
| 739 |
+func (d *differ) checkParent(ctx context.Context, subPath string, handle func(context.Context, *change) error) error {
|
|
| 740 |
+ parentSubPath := filepath.Dir(subPath) |
|
| 741 |
+ if parentSubPath == "/" {
|
|
| 742 |
+ return nil |
|
| 743 |
+ } |
|
| 744 |
+ if _, ok := d.visited[parentSubPath]; ok {
|
|
| 745 |
+ return nil |
|
| 746 |
+ } |
|
| 747 |
+ d.visited[parentSubPath] = struct{}{}
|
|
| 748 |
+ |
|
| 749 |
+ if err := d.checkParent(ctx, parentSubPath, handle); err != nil {
|
|
| 750 |
+ return err |
|
| 751 |
+ } |
|
| 752 |
+ parentSrcPath, err := safeJoin(d.upperRoot, parentSubPath) |
|
| 753 |
+ if err != nil {
|
|
| 754 |
+ return err |
|
| 755 |
+ } |
|
| 756 |
+ srcfi, err := os.Lstat(parentSrcPath) |
|
| 757 |
+ if err != nil {
|
|
| 758 |
+ return err |
|
| 759 |
+ } |
|
| 760 |
+ parentSrcStat, ok := srcfi.Sys().(*syscall.Stat_t) |
|
| 761 |
+ if !ok {
|
|
| 762 |
+ return errors.Errorf("unexpected type %T", srcfi)
|
|
| 763 |
+ } |
|
| 764 |
+ return handle(ctx, &change{
|
|
| 765 |
+ kind: fs.ChangeKindModify, |
|
| 766 |
+ subPath: parentSubPath, |
|
| 767 |
+ srcPath: parentSrcPath, |
|
| 768 |
+ srcStat: parentSrcStat, |
|
| 769 |
+ }) |
|
| 770 |
+} |
|
| 771 |
+ |
|
| 772 |
+func (d *differ) Release() error {
|
|
| 773 |
+ var err error |
|
| 774 |
+ if d.releaseLower != nil {
|
|
| 775 |
+ err = d.releaseLower() |
|
| 776 |
+ if err == nil {
|
|
| 777 |
+ d.releaseLower = nil |
|
| 778 |
+ } |
|
| 779 |
+ } |
|
| 780 |
+ if d.releaseUpper != nil {
|
|
| 781 |
+ err = multierror.Append(err, d.releaseUpper()).ErrorOrNil() |
|
| 782 |
+ if err == nil {
|
|
| 783 |
+ d.releaseUpper = nil |
|
| 784 |
+ } |
|
| 785 |
+ } |
|
| 786 |
+ return err |
|
| 787 |
+} |
|
| 788 |
+ |
|
| 789 |
+func safeJoin(root, path string) (string, error) {
|
|
| 790 |
+ dir, base := filepath.Split(path) |
|
| 791 |
+ parent, err := fs.RootPath(root, dir) |
|
| 792 |
+ if err != nil {
|
|
| 793 |
+ return "", err |
|
| 794 |
+ } |
|
| 795 |
+ return filepath.Join(parent, base), nil |
|
| 796 |
+} |
|
| 797 |
+ |
|
| 798 |
+const ( |
|
| 799 |
+ trustedOpaqueXattr = "trusted.overlay.opaque" |
|
| 800 |
+ userOpaqueXattr = "user.overlay.opaque" |
|
| 801 |
+) |
|
| 802 |
+ |
|
| 803 |
+func isOpaqueXattr(s string) bool {
|
|
| 804 |
+ for _, k := range []string{trustedOpaqueXattr, userOpaqueXattr} {
|
|
| 805 |
+ if s == k {
|
|
| 806 |
+ return true |
|
| 807 |
+ } |
|
| 808 |
+ } |
|
| 809 |
+ return false |
|
| 810 |
+} |
|
| 811 |
+ |
|
| 812 |
+func opaqueXattr(userxattr bool) string {
|
|
| 813 |
+ if userxattr {
|
|
| 814 |
+ return userOpaqueXattr |
|
| 815 |
+ } |
|
| 816 |
+ return trustedOpaqueXattr |
|
| 817 |
+} |
|
| 818 |
+ |
|
| 819 |
+// needsUserXAttr checks whether overlay mounts should be provided the userxattr option. We can't use |
|
| 820 |
+// NeedsUserXAttr from the overlayutils package directly because we don't always have direct knowledge |
|
| 821 |
+// of the root of the snapshotter state (such as when using a remote snapshotter). Instead, we create |
|
| 822 |
+// a temporary new snapshot and test using its root, which works because single layer snapshots will |
|
| 823 |
+// use bind-mounts even when created by an overlay based snapshotter. |
|
| 824 |
+func needsUserXAttr(ctx context.Context, sn Snapshotter, lm leases.Manager) (bool, error) {
|
|
| 825 |
+ key := identity.NewID() |
|
| 826 |
+ |
|
| 827 |
+ ctx, done, err := leaseutil.WithLease(ctx, lm, leaseutil.MakeTemporary) |
|
| 828 |
+ if err != nil {
|
|
| 829 |
+ return false, errors.Wrap(err, "failed to create lease for checking user xattr") |
|
| 830 |
+ } |
|
| 831 |
+ defer done(context.TODO()) |
|
| 832 |
+ |
|
| 833 |
+ err = sn.Prepare(ctx, key, "") |
|
| 834 |
+ if err != nil {
|
|
| 835 |
+ return false, err |
|
| 836 |
+ } |
|
| 837 |
+ mntable, err := sn.Mounts(ctx, key) |
|
| 838 |
+ if err != nil {
|
|
| 839 |
+ return false, err |
|
| 840 |
+ } |
|
| 841 |
+ mnts, unmount, err := mntable.Mount() |
|
| 842 |
+ if err != nil {
|
|
| 843 |
+ return false, err |
|
| 844 |
+ } |
|
| 845 |
+ defer unmount() |
|
| 846 |
+ |
|
| 847 |
+ var userxattr bool |
|
| 848 |
+ if err := mount.WithTempMount(ctx, mnts, func(root string) error {
|
|
| 849 |
+ var err error |
|
| 850 |
+ userxattr, err = overlayutils.NeedsUserXAttr(root) |
|
| 851 |
+ return err |
|
| 852 |
+ }); err != nil {
|
|
| 853 |
+ return false, err |
|
| 854 |
+ } |
|
| 855 |
+ return userxattr, nil |
|
| 856 |
+} |
| 0 | 857 |
deleted file mode 100644 |
| ... | ... |
@@ -1,860 +0,0 @@ |
| 1 |
-//go:build !windows && !freebsd |
|
| 2 |
-// +build !windows,!freebsd |
|
| 3 |
- |
|
| 4 |
-package snapshot |
|
| 5 |
- |
|
| 6 |
-import ( |
|
| 7 |
- "context" |
|
| 8 |
- gofs "io/fs" |
|
| 9 |
- "os" |
|
| 10 |
- "path/filepath" |
|
| 11 |
- "strings" |
|
| 12 |
- "syscall" |
|
| 13 |
- |
|
| 14 |
- "github.com/containerd/containerd/leases" |
|
| 15 |
- "github.com/containerd/containerd/mount" |
|
| 16 |
- "github.com/containerd/containerd/snapshots" |
|
| 17 |
- "github.com/containerd/containerd/snapshots/overlay/overlayutils" |
|
| 18 |
- "github.com/containerd/continuity/fs" |
|
| 19 |
- "github.com/containerd/continuity/sysx" |
|
| 20 |
- "github.com/hashicorp/go-multierror" |
|
| 21 |
- "github.com/moby/buildkit/identity" |
|
| 22 |
- "github.com/moby/buildkit/util/bklog" |
|
| 23 |
- "github.com/moby/buildkit/util/leaseutil" |
|
| 24 |
- "github.com/moby/buildkit/util/overlay" |
|
| 25 |
- "github.com/pkg/errors" |
|
| 26 |
- "golang.org/x/sys/unix" |
|
| 27 |
-) |
|
| 28 |
- |
|
| 29 |
-// diffApply applies the provided diffs to the dest Mountable and returns the correctly calculated disk usage |
|
| 30 |
-// that accounts for any hardlinks made from existing snapshots. ctx is expected to have a temporary lease |
|
| 31 |
-// associated with it. |
|
| 32 |
-func (sn *mergeSnapshotter) diffApply(ctx context.Context, dest Mountable, diffs ...Diff) (_ snapshots.Usage, rerr error) {
|
|
| 33 |
- a, err := applierFor(dest, sn.tryCrossSnapshotLink, sn.userxattr) |
|
| 34 |
- if err != nil {
|
|
| 35 |
- return snapshots.Usage{}, errors.Wrapf(err, "failed to create applier")
|
|
| 36 |
- } |
|
| 37 |
- defer func() {
|
|
| 38 |
- releaseErr := a.Release() |
|
| 39 |
- if releaseErr != nil {
|
|
| 40 |
- rerr = multierror.Append(rerr, errors.Wrapf(releaseErr, "failed to release applier")).ErrorOrNil() |
|
| 41 |
- } |
|
| 42 |
- }() |
|
| 43 |
- |
|
| 44 |
- // TODO:(sipsma) optimization: parallelize differ and applier in separate goroutines, connected with a buffered channel |
|
| 45 |
- |
|
| 46 |
- for _, diff := range diffs {
|
|
| 47 |
- var lowerMntable Mountable |
|
| 48 |
- if diff.Lower != "" {
|
|
| 49 |
- if info, err := sn.Stat(ctx, diff.Lower); err != nil {
|
|
| 50 |
- return snapshots.Usage{}, errors.Wrapf(err, "failed to stat lower snapshot %s", diff.Lower)
|
|
| 51 |
- } else if info.Kind == snapshots.KindCommitted {
|
|
| 52 |
- lowerMntable, err = sn.View(ctx, identity.NewID(), diff.Lower) |
|
| 53 |
- if err != nil {
|
|
| 54 |
- return snapshots.Usage{}, errors.Wrapf(err, "failed to mount lower snapshot view %s", diff.Lower)
|
|
| 55 |
- } |
|
| 56 |
- } else {
|
|
| 57 |
- lowerMntable, err = sn.Mounts(ctx, diff.Lower) |
|
| 58 |
- if err != nil {
|
|
| 59 |
- return snapshots.Usage{}, errors.Wrapf(err, "failed to mount lower snapshot %s", diff.Lower)
|
|
| 60 |
- } |
|
| 61 |
- } |
|
| 62 |
- } |
|
| 63 |
- var upperMntable Mountable |
|
| 64 |
- if diff.Upper != "" {
|
|
| 65 |
- if info, err := sn.Stat(ctx, diff.Upper); err != nil {
|
|
| 66 |
- return snapshots.Usage{}, errors.Wrapf(err, "failed to stat upper snapshot %s", diff.Upper)
|
|
| 67 |
- } else if info.Kind == snapshots.KindCommitted {
|
|
| 68 |
- upperMntable, err = sn.View(ctx, identity.NewID(), diff.Upper) |
|
| 69 |
- if err != nil {
|
|
| 70 |
- return snapshots.Usage{}, errors.Wrapf(err, "failed to mount upper snapshot view %s", diff.Upper)
|
|
| 71 |
- } |
|
| 72 |
- } else {
|
|
| 73 |
- upperMntable, err = sn.Mounts(ctx, diff.Upper) |
|
| 74 |
- if err != nil {
|
|
| 75 |
- return snapshots.Usage{}, errors.Wrapf(err, "failed to mount upper snapshot %s", diff.Upper)
|
|
| 76 |
- } |
|
| 77 |
- } |
|
| 78 |
- } else {
|
|
| 79 |
- // create an empty view |
|
| 80 |
- upperMntable, err = sn.View(ctx, identity.NewID(), "") |
|
| 81 |
- if err != nil {
|
|
| 82 |
- return snapshots.Usage{}, errors.Wrapf(err, "failed to mount empty upper snapshot view %s", diff.Upper)
|
|
| 83 |
- } |
|
| 84 |
- } |
|
| 85 |
- d, err := differFor(lowerMntable, upperMntable) |
|
| 86 |
- if err != nil {
|
|
| 87 |
- return snapshots.Usage{}, errors.Wrapf(err, "failed to create differ")
|
|
| 88 |
- } |
|
| 89 |
- defer func() {
|
|
| 90 |
- rerr = multierror.Append(rerr, d.Release()).ErrorOrNil() |
|
| 91 |
- }() |
|
| 92 |
- if err := d.HandleChanges(ctx, a.Apply); err != nil {
|
|
| 93 |
- return snapshots.Usage{}, errors.Wrapf(err, "failed to handle changes")
|
|
| 94 |
- } |
|
| 95 |
- } |
|
| 96 |
- |
|
| 97 |
- if err := a.Flush(); err != nil {
|
|
| 98 |
- return snapshots.Usage{}, errors.Wrapf(err, "failed to flush changes")
|
|
| 99 |
- } |
|
| 100 |
- return a.Usage() |
|
| 101 |
-} |
|
| 102 |
- |
|
| 103 |
-type change struct {
|
|
| 104 |
- kind fs.ChangeKind |
|
| 105 |
- subPath string |
|
| 106 |
- srcPath string |
|
| 107 |
- srcStat *syscall.Stat_t |
|
| 108 |
- // linkSubPath is set to a subPath of a previous change from the same |
|
| 109 |
- // differ instance that is a hardlink to this one, if any. |
|
| 110 |
- linkSubPath string |
|
| 111 |
-} |
|
| 112 |
- |
|
| 113 |
-type changeApply struct {
|
|
| 114 |
- *change |
|
| 115 |
- dstPath string |
|
| 116 |
- dstStat *syscall.Stat_t |
|
| 117 |
- setOpaque bool |
|
| 118 |
-} |
|
| 119 |
- |
|
| 120 |
-type inode struct {
|
|
| 121 |
- ino uint64 |
|
| 122 |
- dev uint64 |
|
| 123 |
-} |
|
| 124 |
- |
|
| 125 |
-func statInode(stat *syscall.Stat_t) inode {
|
|
| 126 |
- if stat == nil {
|
|
| 127 |
- return inode{}
|
|
| 128 |
- } |
|
| 129 |
- return inode{
|
|
| 130 |
- ino: stat.Ino, |
|
| 131 |
- dev: stat.Dev, |
|
| 132 |
- } |
|
| 133 |
-} |
|
| 134 |
- |
|
| 135 |
-type applier struct {
|
|
| 136 |
- root string |
|
| 137 |
- release func() error |
|
| 138 |
- lowerdirs []string // ordered highest -> lowest, the order we want to check them in |
|
| 139 |
- crossSnapshotLinks map[inode]struct{}
|
|
| 140 |
- createWhiteoutDelete bool |
|
| 141 |
- userxattr bool |
|
| 142 |
- dirModTimes map[string]unix.Timespec // map of dstPath -> mtime that should be set on that subPath |
|
| 143 |
-} |
|
| 144 |
- |
|
| 145 |
-func applierFor(dest Mountable, tryCrossSnapshotLink, userxattr bool) (_ *applier, rerr error) {
|
|
| 146 |
- a := &applier{
|
|
| 147 |
- dirModTimes: make(map[string]unix.Timespec), |
|
| 148 |
- userxattr: userxattr, |
|
| 149 |
- } |
|
| 150 |
- defer func() {
|
|
| 151 |
- if rerr != nil {
|
|
| 152 |
- rerr = multierror.Append(rerr, a.Release()).ErrorOrNil() |
|
| 153 |
- } |
|
| 154 |
- }() |
|
| 155 |
- if tryCrossSnapshotLink {
|
|
| 156 |
- a.crossSnapshotLinks = make(map[inode]struct{})
|
|
| 157 |
- } |
|
| 158 |
- |
|
| 159 |
- mnts, release, err := dest.Mount() |
|
| 160 |
- if err != nil {
|
|
| 161 |
- return nil, nil |
|
| 162 |
- } |
|
| 163 |
- a.release = release |
|
| 164 |
- |
|
| 165 |
- if len(mnts) != 1 {
|
|
| 166 |
- return nil, errors.Errorf("expected exactly one mount, got %d", len(mnts))
|
|
| 167 |
- } |
|
| 168 |
- mnt := mnts[0] |
|
| 169 |
- |
|
| 170 |
- if overlay.IsOverlayMountType(mnt) {
|
|
| 171 |
- for _, opt := range mnt.Options {
|
|
| 172 |
- if strings.HasPrefix(opt, "upperdir=") {
|
|
| 173 |
- a.root = strings.TrimPrefix(opt, "upperdir=") |
|
| 174 |
- } else if strings.HasPrefix(opt, "lowerdir=") {
|
|
| 175 |
- a.lowerdirs = strings.Split(strings.TrimPrefix(opt, "lowerdir="), ":") |
|
| 176 |
- } |
|
| 177 |
- } |
|
| 178 |
- if a.root == "" {
|
|
| 179 |
- return nil, errors.Errorf("could not find upperdir in mount options %v", mnt.Options)
|
|
| 180 |
- } |
|
| 181 |
- if len(a.lowerdirs) == 0 {
|
|
| 182 |
- return nil, errors.Errorf("could not find lowerdir in mount options %v", mnt.Options)
|
|
| 183 |
- } |
|
| 184 |
- a.createWhiteoutDelete = true |
|
| 185 |
- } else if mnt.Type == "bind" || mnt.Type == "rbind" {
|
|
| 186 |
- a.root = mnt.Source |
|
| 187 |
- } else {
|
|
| 188 |
- mnter := LocalMounter(dest) |
|
| 189 |
- root, err := mnter.Mount() |
|
| 190 |
- if err != nil {
|
|
| 191 |
- return nil, err |
|
| 192 |
- } |
|
| 193 |
- a.root = root |
|
| 194 |
- prevRelease := a.release |
|
| 195 |
- a.release = func() error {
|
|
| 196 |
- err := mnter.Unmount() |
|
| 197 |
- return multierror.Append(err, prevRelease()).ErrorOrNil() |
|
| 198 |
- } |
|
| 199 |
- } |
|
| 200 |
- |
|
| 201 |
- a.root, err = filepath.EvalSymlinks(a.root) |
|
| 202 |
- if err != nil {
|
|
| 203 |
- return nil, errors.Wrapf(err, "failed to resolve symlinks in %s", a.root) |
|
| 204 |
- } |
|
| 205 |
- return a, nil |
|
| 206 |
-} |
|
| 207 |
- |
|
| 208 |
-func (a *applier) Apply(ctx context.Context, c *change) error {
|
|
| 209 |
- if c == nil {
|
|
| 210 |
- return errors.New("nil change")
|
|
| 211 |
- } |
|
| 212 |
- |
|
| 213 |
- if c.kind == fs.ChangeKindUnmodified {
|
|
| 214 |
- return nil |
|
| 215 |
- } |
|
| 216 |
- |
|
| 217 |
- dstPath, err := safeJoin(a.root, c.subPath) |
|
| 218 |
- if err != nil {
|
|
| 219 |
- return errors.Wrapf(err, "failed to join paths %q and %q", a.root, c.subPath) |
|
| 220 |
- } |
|
| 221 |
- var dstStat *syscall.Stat_t |
|
| 222 |
- if dstfi, err := os.Lstat(dstPath); err == nil {
|
|
| 223 |
- stat, ok := dstfi.Sys().(*syscall.Stat_t) |
|
| 224 |
- if !ok {
|
|
| 225 |
- return errors.Errorf("failed to get stat_t for %T", dstStat)
|
|
| 226 |
- } |
|
| 227 |
- dstStat = stat |
|
| 228 |
- } else if !os.IsNotExist(err) {
|
|
| 229 |
- return errors.Wrap(err, "failed to stat during copy apply") |
|
| 230 |
- } |
|
| 231 |
- |
|
| 232 |
- ca := &changeApply{
|
|
| 233 |
- change: c, |
|
| 234 |
- dstPath: dstPath, |
|
| 235 |
- dstStat: dstStat, |
|
| 236 |
- } |
|
| 237 |
- |
|
| 238 |
- if done, err := a.applyDelete(ca); err != nil {
|
|
| 239 |
- return errors.Wrap(err, "failed to delete during apply") |
|
| 240 |
- } else if done {
|
|
| 241 |
- return nil |
|
| 242 |
- } |
|
| 243 |
- |
|
| 244 |
- if done, err := a.applyHardlink(ctx, ca); err != nil {
|
|
| 245 |
- return errors.Wrapf(err, "failed to hardlink during apply") |
|
| 246 |
- } else if done {
|
|
| 247 |
- return nil |
|
| 248 |
- } |
|
| 249 |
- |
|
| 250 |
- if err := a.applyCopy(ctx, ca); err != nil {
|
|
| 251 |
- return errors.Wrapf(err, "failed to copy during apply") |
|
| 252 |
- } |
|
| 253 |
- return nil |
|
| 254 |
-} |
|
| 255 |
- |
|
| 256 |
-func (a *applier) applyDelete(ca *changeApply) (bool, error) {
|
|
| 257 |
- // Even when not deleting, we may be overwriting a file, in which case we should |
|
| 258 |
- // delete the existing file at the path, if any. Don't delete when both are dirs |
|
| 259 |
- // in this case though because they should get merged, not overwritten. |
|
| 260 |
- deleteOnly := ca.kind == fs.ChangeKindDelete |
|
| 261 |
- overwrite := !deleteOnly && ca.dstStat != nil && ca.srcStat.Mode&ca.dstStat.Mode&unix.S_IFMT != unix.S_IFDIR |
|
| 262 |
- |
|
| 263 |
- if !deleteOnly && !overwrite {
|
|
| 264 |
- // nothing to delete, continue on |
|
| 265 |
- return false, nil |
|
| 266 |
- } |
|
| 267 |
- |
|
| 268 |
- if err := os.RemoveAll(ca.dstPath); err != nil {
|
|
| 269 |
- return false, errors.Wrap(err, "failed to remove during apply") |
|
| 270 |
- } |
|
| 271 |
- ca.dstStat = nil |
|
| 272 |
- |
|
| 273 |
- if overwrite && a.createWhiteoutDelete && ca.srcStat.Mode&unix.S_IFMT == unix.S_IFDIR {
|
|
| 274 |
- // If we are using an overlay snapshotter and overwriting an existing non-directory |
|
| 275 |
- // with a directory, we need this new dir to be opaque so that any files from lowerdirs |
|
| 276 |
- // under it are not visible. |
|
| 277 |
- ca.setOpaque = true |
|
| 278 |
- } |
|
| 279 |
- |
|
| 280 |
- if deleteOnly && a.createWhiteoutDelete {
|
|
| 281 |
- // only create a whiteout device if there is something to delete |
|
| 282 |
- var foundLower bool |
|
| 283 |
- for _, lowerdir := range a.lowerdirs {
|
|
| 284 |
- lowerPath, err := safeJoin(lowerdir, ca.subPath) |
|
| 285 |
- if err != nil {
|
|
| 286 |
- return false, errors.Wrapf(err, "failed to join lowerdir %q and subPath %q", lowerdir, ca.subPath) |
|
| 287 |
- } |
|
| 288 |
- if _, err := os.Lstat(lowerPath); err == nil {
|
|
| 289 |
- foundLower = true |
|
| 290 |
- break |
|
| 291 |
- } else if !errors.Is(err, unix.ENOENT) && !errors.Is(err, unix.ENOTDIR) {
|
|
| 292 |
- return false, errors.Wrapf(err, "failed to stat lowerPath %q", lowerPath) |
|
| 293 |
- } |
|
| 294 |
- } |
|
| 295 |
- if foundLower {
|
|
| 296 |
- ca.kind = fs.ChangeKindAdd |
|
| 297 |
- if ca.srcStat == nil {
|
|
| 298 |
- ca.srcStat = &syscall.Stat_t{
|
|
| 299 |
- Mode: syscall.S_IFCHR, |
|
| 300 |
- Rdev: unix.Mkdev(0, 0), |
|
| 301 |
- } |
|
| 302 |
- ca.srcPath = "" |
|
| 303 |
- } |
|
| 304 |
- return false, nil |
|
| 305 |
- } |
|
| 306 |
- } |
|
| 307 |
- |
|
| 308 |
- return deleteOnly, nil |
|
| 309 |
-} |
|
| 310 |
- |
|
| 311 |
-func (a *applier) applyHardlink(ctx context.Context, ca *changeApply) (bool, error) {
|
|
| 312 |
- switch ca.srcStat.Mode & unix.S_IFMT {
|
|
| 313 |
- case unix.S_IFDIR, unix.S_IFIFO, unix.S_IFSOCK: |
|
| 314 |
- // Directories can't be hard-linked, so they just have to be recreated. |
|
| 315 |
- // Named pipes and sockets can be hard-linked but is best to avoid as it could enable IPC in weird cases. |
|
| 316 |
- return false, nil |
|
| 317 |
- |
|
| 318 |
- default: |
|
| 319 |
- var linkSrcPath string |
|
| 320 |
- if ca.linkSubPath != "" {
|
|
| 321 |
- // there's an already applied path that we should link from |
|
| 322 |
- path, err := safeJoin(a.root, ca.linkSubPath) |
|
| 323 |
- if err != nil {
|
|
| 324 |
- return false, errors.Errorf("failed to get hardlink source path: %v", err)
|
|
| 325 |
- } |
|
| 326 |
- linkSrcPath = path |
|
| 327 |
- } else if a.crossSnapshotLinks != nil {
|
|
| 328 |
- // we can try to link across snapshots from the source file |
|
| 329 |
- linkSrcPath = ca.srcPath |
|
| 330 |
- a.crossSnapshotLinks[statInode(ca.srcStat)] = struct{}{}
|
|
| 331 |
- } |
|
| 332 |
- if linkSrcPath == "" {
|
|
| 333 |
- // nothing to hardlink from, will have to copy the file |
|
| 334 |
- return false, nil |
|
| 335 |
- } |
|
| 336 |
- |
|
| 337 |
- if err := os.Link(linkSrcPath, ca.dstPath); errors.Is(err, unix.EXDEV) || errors.Is(err, unix.EMLINK) {
|
|
| 338 |
- // These errors are expected when the hardlink would cross devices or would exceed the maximum number of links for the inode. |
|
| 339 |
- // Just fallback to a copy. |
|
| 340 |
- bklog.G(ctx).WithError(err).WithField("srcPath", linkSrcPath).WithField("dstPath", ca.dstPath).Debug("hardlink failed")
|
|
| 341 |
- if a.crossSnapshotLinks != nil {
|
|
| 342 |
- delete(a.crossSnapshotLinks, statInode(ca.srcStat)) |
|
| 343 |
- } |
|
| 344 |
- return false, nil |
|
| 345 |
- } else if err != nil {
|
|
| 346 |
- return false, errors.Wrap(err, "failed to hardlink during apply") |
|
| 347 |
- } |
|
| 348 |
- |
|
| 349 |
- return true, nil |
|
| 350 |
- } |
|
| 351 |
-} |
|
| 352 |
- |
|
| 353 |
-func (a *applier) applyCopy(ctx context.Context, ca *changeApply) error {
|
|
| 354 |
- switch ca.srcStat.Mode & unix.S_IFMT {
|
|
| 355 |
- case unix.S_IFREG: |
|
| 356 |
- if err := fs.CopyFile(ca.dstPath, ca.srcPath); err != nil {
|
|
| 357 |
- return errors.Wrapf(err, "failed to copy from %s to %s during apply", ca.srcPath, ca.dstPath) |
|
| 358 |
- } |
|
| 359 |
- case unix.S_IFDIR: |
|
| 360 |
- if ca.dstStat == nil {
|
|
| 361 |
- // dstPath doesn't exist, make it a dir |
|
| 362 |
- if err := unix.Mkdir(ca.dstPath, ca.srcStat.Mode); err != nil {
|
|
| 363 |
- return errors.Wrapf(err, "failed to create applied dir at %q from %q", ca.dstPath, ca.srcPath) |
|
| 364 |
- } |
|
| 365 |
- } |
|
| 366 |
- case unix.S_IFLNK: |
|
| 367 |
- if target, err := os.Readlink(ca.srcPath); err != nil {
|
|
| 368 |
- return errors.Wrap(err, "failed to read symlink during apply") |
|
| 369 |
- } else if err := os.Symlink(target, ca.dstPath); err != nil {
|
|
| 370 |
- return errors.Wrap(err, "failed to create symlink during apply") |
|
| 371 |
- } |
|
| 372 |
- case unix.S_IFBLK, unix.S_IFCHR, unix.S_IFIFO, unix.S_IFSOCK: |
|
| 373 |
- if err := unix.Mknod(ca.dstPath, ca.srcStat.Mode, int(ca.srcStat.Rdev)); err != nil {
|
|
| 374 |
- return errors.Wrap(err, "failed to mknod during apply") |
|
| 375 |
- } |
|
| 376 |
- default: |
|
| 377 |
- // should never be here, all types should be handled |
|
| 378 |
- return errors.Errorf("unhandled file type %d during merge at path %q", ca.srcStat.Mode&unix.S_IFMT, ca.srcPath)
|
|
| 379 |
- } |
|
| 380 |
- |
|
| 381 |
- // NOTE: it's important that chown happens before setting xattrs due to the fact that chown will |
|
| 382 |
- // reset the security.capabilities xattr which results in file capabilities being lost. |
|
| 383 |
- if err := os.Lchown(ca.dstPath, int(ca.srcStat.Uid), int(ca.srcStat.Gid)); err != nil {
|
|
| 384 |
- return errors.Wrap(err, "failed to chown during apply") |
|
| 385 |
- } |
|
| 386 |
- |
|
| 387 |
- if ca.srcStat.Mode&unix.S_IFMT != unix.S_IFLNK {
|
|
| 388 |
- if err := unix.Chmod(ca.dstPath, ca.srcStat.Mode); err != nil {
|
|
| 389 |
- return errors.Wrapf(err, "failed to chmod path %q during apply", ca.dstPath) |
|
| 390 |
- } |
|
| 391 |
- } |
|
| 392 |
- |
|
| 393 |
- if ca.srcPath != "" {
|
|
| 394 |
- xattrs, err := sysx.LListxattr(ca.srcPath) |
|
| 395 |
- if err != nil {
|
|
| 396 |
- return errors.Wrapf(err, "failed to list xattrs of src path %s", ca.srcPath) |
|
| 397 |
- } |
|
| 398 |
- for _, xattr := range xattrs {
|
|
| 399 |
- if isOpaqueXattr(xattr) {
|
|
| 400 |
- // Don't recreate opaque xattrs during merge based on the source file. The differs take care of converting |
|
| 401 |
- // source path from the "opaque whiteout" format to the "explicit whiteout" format. The only time we set |
|
| 402 |
- // opaque xattrs is handled after this loop below. |
|
| 403 |
- continue |
|
| 404 |
- } |
|
| 405 |
- xattrVal, err := sysx.LGetxattr(ca.srcPath, xattr) |
|
| 406 |
- if err != nil {
|
|
| 407 |
- return errors.Wrapf(err, "failed to get xattr %s of src path %s", xattr, ca.srcPath) |
|
| 408 |
- } |
|
| 409 |
- if err := sysx.LSetxattr(ca.dstPath, xattr, xattrVal, 0); err != nil {
|
|
| 410 |
- // This can often fail, so just log it: https://github.com/moby/buildkit/issues/1189 |
|
| 411 |
- bklog.G(ctx).Debugf("failed to set xattr %s of path %s during apply", xattr, ca.dstPath)
|
|
| 412 |
- } |
|
| 413 |
- } |
|
| 414 |
- } |
|
| 415 |
- |
|
| 416 |
- if ca.setOpaque {
|
|
| 417 |
- // This is set in the case where we are creating a directory that is replacing a whiteout device |
|
| 418 |
- xattr := opaqueXattr(a.userxattr) |
|
| 419 |
- if err := sysx.LSetxattr(ca.dstPath, xattr, []byte{'y'}, 0); err != nil {
|
|
| 420 |
- return errors.Wrapf(err, "failed to set opaque xattr %q of path %s", xattr, ca.dstPath) |
|
| 421 |
- } |
|
| 422 |
- } |
|
| 423 |
- |
|
| 424 |
- atimeSpec := unix.Timespec{Sec: ca.srcStat.Atim.Sec, Nsec: ca.srcStat.Atim.Nsec}
|
|
| 425 |
- mtimeSpec := unix.Timespec{Sec: ca.srcStat.Mtim.Sec, Nsec: ca.srcStat.Mtim.Nsec}
|
|
| 426 |
- if ca.srcStat.Mode&unix.S_IFMT != unix.S_IFDIR {
|
|
| 427 |
- // apply times immediately for non-dirs |
|
| 428 |
- if err := unix.UtimesNanoAt(unix.AT_FDCWD, ca.dstPath, []unix.Timespec{atimeSpec, mtimeSpec}, unix.AT_SYMLINK_NOFOLLOW); err != nil {
|
|
| 429 |
- return err |
|
| 430 |
- } |
|
| 431 |
- } else {
|
|
| 432 |
- // save the times we should set on this dir, to be applied after subfiles have been set |
|
| 433 |
- a.dirModTimes[ca.dstPath] = mtimeSpec |
|
| 434 |
- } |
|
| 435 |
- |
|
| 436 |
- return nil |
|
| 437 |
-} |
|
| 438 |
- |
|
| 439 |
-func (a *applier) Flush() error {
|
|
| 440 |
- // Set dir times now that everything has been modified. Walk the filesystem tree to ensure |
|
| 441 |
- // that we never try to apply to a path that has been deleted or modified since times for it |
|
| 442 |
- // were stored. This is needed for corner cases such as where a parent dir is removed and |
|
| 443 |
- // replaced with a symlink. |
|
| 444 |
- return filepath.WalkDir(a.root, func(path string, d gofs.DirEntry, prevErr error) error {
|
|
| 445 |
- if prevErr != nil {
|
|
| 446 |
- return prevErr |
|
| 447 |
- } |
|
| 448 |
- if !d.IsDir() {
|
|
| 449 |
- return nil |
|
| 450 |
- } |
|
| 451 |
- if mtime, ok := a.dirModTimes[path]; ok {
|
|
| 452 |
- if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, []unix.Timespec{{Nsec: unix.UTIME_OMIT}, mtime}, unix.AT_SYMLINK_NOFOLLOW); err != nil {
|
|
| 453 |
- return err |
|
| 454 |
- } |
|
| 455 |
- } |
|
| 456 |
- return nil |
|
| 457 |
- }) |
|
| 458 |
-} |
|
| 459 |
- |
|
| 460 |
-func (a *applier) Release() error {
|
|
| 461 |
- if a.release != nil {
|
|
| 462 |
- err := a.release() |
|
| 463 |
- if err != nil {
|
|
| 464 |
- return err |
|
| 465 |
- } |
|
| 466 |
- } |
|
| 467 |
- a.release = nil |
|
| 468 |
- return nil |
|
| 469 |
-} |
|
| 470 |
- |
|
| 471 |
-func (a *applier) Usage() (snapshots.Usage, error) {
|
|
| 472 |
- // Calculate the disk space used under the apply root, similar to the normal containerd snapshotter disk usage |
|
| 473 |
- // calculations but with the extra ability to take into account hardlinks that were created between snapshots, ensuring that |
|
| 474 |
- // they don't get double counted. |
|
| 475 |
- inodes := make(map[inode]struct{})
|
|
| 476 |
- var usage snapshots.Usage |
|
| 477 |
- if err := filepath.WalkDir(a.root, func(path string, dirent gofs.DirEntry, err error) error {
|
|
| 478 |
- if err != nil {
|
|
| 479 |
- return err |
|
| 480 |
- } |
|
| 481 |
- info, err := dirent.Info() |
|
| 482 |
- if err != nil {
|
|
| 483 |
- return err |
|
| 484 |
- } |
|
| 485 |
- stat := info.Sys().(*syscall.Stat_t) |
|
| 486 |
- inode := statInode(stat) |
|
| 487 |
- if _, ok := inodes[inode]; ok {
|
|
| 488 |
- return nil |
|
| 489 |
- } |
|
| 490 |
- inodes[inode] = struct{}{}
|
|
| 491 |
- if a.crossSnapshotLinks != nil {
|
|
| 492 |
- if _, ok := a.crossSnapshotLinks[statInode(stat)]; ok {
|
|
| 493 |
- // don't count cross-snapshot hardlinks |
|
| 494 |
- return nil |
|
| 495 |
- } |
|
| 496 |
- } |
|
| 497 |
- usage.Inodes++ |
|
| 498 |
- usage.Size += stat.Blocks * 512 // 512 is always block size, see "man 2 stat" |
|
| 499 |
- return nil |
|
| 500 |
- }); err != nil {
|
|
| 501 |
- return snapshots.Usage{}, err
|
|
| 502 |
- } |
|
| 503 |
- return usage, nil |
|
| 504 |
-} |
|
| 505 |
- |
|
| 506 |
-type differ struct {
|
|
| 507 |
- lowerRoot string |
|
| 508 |
- releaseLower func() error |
|
| 509 |
- |
|
| 510 |
- upperRoot string |
|
| 511 |
- releaseUpper func() error |
|
| 512 |
- |
|
| 513 |
- upperBindSource string |
|
| 514 |
- upperOverlayDirs []string // ordered lowest -> highest |
|
| 515 |
- |
|
| 516 |
- upperdir string |
|
| 517 |
- |
|
| 518 |
- visited map[string]struct{} // set of parent subPaths that have been visited
|
|
| 519 |
- inodes map[inode]string // map of inode -> subPath |
|
| 520 |
-} |
|
| 521 |
- |
|
| 522 |
-func differFor(lowerMntable, upperMntable Mountable) (_ *differ, rerr error) {
|
|
| 523 |
- d := &differ{
|
|
| 524 |
- visited: make(map[string]struct{}),
|
|
| 525 |
- inodes: make(map[inode]string), |
|
| 526 |
- } |
|
| 527 |
- defer func() {
|
|
| 528 |
- if rerr != nil {
|
|
| 529 |
- rerr = multierror.Append(rerr, d.Release()).ErrorOrNil() |
|
| 530 |
- } |
|
| 531 |
- }() |
|
| 532 |
- |
|
| 533 |
- var lowerMnts []mount.Mount |
|
| 534 |
- if lowerMntable != nil {
|
|
| 535 |
- mnts, release, err := lowerMntable.Mount() |
|
| 536 |
- if err != nil {
|
|
| 537 |
- return nil, err |
|
| 538 |
- } |
|
| 539 |
- mounter := LocalMounterWithMounts(mnts) |
|
| 540 |
- root, err := mounter.Mount() |
|
| 541 |
- if err != nil {
|
|
| 542 |
- return nil, err |
|
| 543 |
- } |
|
| 544 |
- d.lowerRoot = root |
|
| 545 |
- lowerMnts = mnts |
|
| 546 |
- d.releaseLower = func() error {
|
|
| 547 |
- err := mounter.Unmount() |
|
| 548 |
- return multierror.Append(err, release()).ErrorOrNil() |
|
| 549 |
- } |
|
| 550 |
- } |
|
| 551 |
- |
|
| 552 |
- var upperMnts []mount.Mount |
|
| 553 |
- if upperMntable != nil {
|
|
| 554 |
- mnts, release, err := upperMntable.Mount() |
|
| 555 |
- if err != nil {
|
|
| 556 |
- return nil, err |
|
| 557 |
- } |
|
| 558 |
- mounter := LocalMounterWithMounts(mnts) |
|
| 559 |
- root, err := mounter.Mount() |
|
| 560 |
- if err != nil {
|
|
| 561 |
- return nil, err |
|
| 562 |
- } |
|
| 563 |
- d.upperRoot = root |
|
| 564 |
- upperMnts = mnts |
|
| 565 |
- d.releaseUpper = func() error {
|
|
| 566 |
- err := mounter.Unmount() |
|
| 567 |
- return multierror.Append(err, release()).ErrorOrNil() |
|
| 568 |
- } |
|
| 569 |
- } |
|
| 570 |
- |
|
| 571 |
- if len(upperMnts) == 1 {
|
|
| 572 |
- if upperMnts[0].Type == "bind" || upperMnts[0].Type == "rbind" {
|
|
| 573 |
- d.upperBindSource = upperMnts[0].Source |
|
| 574 |
- } else if overlay.IsOverlayMountType(upperMnts[0]) {
|
|
| 575 |
- overlayDirs, err := overlay.GetOverlayLayers(upperMnts[0]) |
|
| 576 |
- if err != nil {
|
|
| 577 |
- return nil, errors.Wrapf(err, "failed to get overlay layers from mount %+v", upperMnts[0]) |
|
| 578 |
- } |
|
| 579 |
- d.upperOverlayDirs = overlayDirs |
|
| 580 |
- } |
|
| 581 |
- } |
|
| 582 |
- if len(lowerMnts) > 0 {
|
|
| 583 |
- if upperdir, err := overlay.GetUpperdir(lowerMnts, upperMnts); err == nil {
|
|
| 584 |
- d.upperdir = upperdir |
|
| 585 |
- } |
|
| 586 |
- } |
|
| 587 |
- |
|
| 588 |
- return d, nil |
|
| 589 |
-} |
|
| 590 |
- |
|
| 591 |
-func (d *differ) HandleChanges(ctx context.Context, handle func(context.Context, *change) error) error {
|
|
| 592 |
- if d.upperdir != "" {
|
|
| 593 |
- return d.overlayChanges(ctx, handle) |
|
| 594 |
- } |
|
| 595 |
- return d.doubleWalkingChanges(ctx, handle) |
|
| 596 |
-} |
|
| 597 |
- |
|
| 598 |
-func (d *differ) doubleWalkingChanges(ctx context.Context, handle func(context.Context, *change) error) error {
|
|
| 599 |
- return fs.Changes(ctx, d.lowerRoot, d.upperRoot, func(kind fs.ChangeKind, subPath string, srcfi os.FileInfo, prevErr error) error {
|
|
| 600 |
- if prevErr != nil {
|
|
| 601 |
- return prevErr |
|
| 602 |
- } |
|
| 603 |
- select {
|
|
| 604 |
- case <-ctx.Done(): |
|
| 605 |
- return context.Cause(ctx) |
|
| 606 |
- default: |
|
| 607 |
- } |
|
| 608 |
- |
|
| 609 |
- if kind == fs.ChangeKindUnmodified {
|
|
| 610 |
- return nil |
|
| 611 |
- } |
|
| 612 |
- |
|
| 613 |
- // NOTE: it's tempting to skip creating parent dirs when change kind is Delete, but |
|
| 614 |
- // that would make us incompatible with the image exporter code: |
|
| 615 |
- // https://github.com/containerd/containerd/pull/2095 |
|
| 616 |
- if err := d.checkParent(ctx, subPath, handle); err != nil {
|
|
| 617 |
- return errors.Wrapf(err, "failed to check parent for %s", subPath) |
|
| 618 |
- } |
|
| 619 |
- |
|
| 620 |
- c := &change{
|
|
| 621 |
- kind: kind, |
|
| 622 |
- subPath: subPath, |
|
| 623 |
- } |
|
| 624 |
- |
|
| 625 |
- if srcfi != nil {
|
|
| 626 |
- // Try to ensure that srcPath and srcStat are set to a file from the underlying filesystem |
|
| 627 |
- // rather than the actual mount when possible. This allows hardlinking without getting EXDEV. |
|
| 628 |
- switch {
|
|
| 629 |
- case !srcfi.IsDir() && d.upperBindSource != "": |
|
| 630 |
- srcPath, err := safeJoin(d.upperBindSource, c.subPath) |
|
| 631 |
- if err != nil {
|
|
| 632 |
- return errors.Wrapf(err, "failed to join %s and %s", d.upperBindSource, c.subPath) |
|
| 633 |
- } |
|
| 634 |
- c.srcPath = srcPath |
|
| 635 |
- if fi, err := os.Lstat(c.srcPath); err == nil {
|
|
| 636 |
- srcfi = fi |
|
| 637 |
- } else {
|
|
| 638 |
- return errors.Wrap(err, "failed to stat underlying file from bind mount") |
|
| 639 |
- } |
|
| 640 |
- case !srcfi.IsDir() && len(d.upperOverlayDirs) > 0: |
|
| 641 |
- for i := range d.upperOverlayDirs {
|
|
| 642 |
- dir := d.upperOverlayDirs[len(d.upperOverlayDirs)-1-i] |
|
| 643 |
- path, err := safeJoin(dir, c.subPath) |
|
| 644 |
- if err != nil {
|
|
| 645 |
- return errors.Wrapf(err, "failed to join %s and %s", dir, c.subPath) |
|
| 646 |
- } |
|
| 647 |
- if stat, err := os.Lstat(path); err == nil {
|
|
| 648 |
- c.srcPath = path |
|
| 649 |
- srcfi = stat |
|
| 650 |
- break |
|
| 651 |
- } else if errors.Is(err, unix.ENOENT) {
|
|
| 652 |
- continue |
|
| 653 |
- } else {
|
|
| 654 |
- return errors.Wrap(err, "failed to lstat when finding direct path of overlay file") |
|
| 655 |
- } |
|
| 656 |
- } |
|
| 657 |
- default: |
|
| 658 |
- srcPath, err := safeJoin(d.upperRoot, subPath) |
|
| 659 |
- if err != nil {
|
|
| 660 |
- return errors.Wrapf(err, "failed to join %s and %s", d.upperRoot, subPath) |
|
| 661 |
- } |
|
| 662 |
- c.srcPath = srcPath |
|
| 663 |
- if fi, err := os.Lstat(c.srcPath); err == nil {
|
|
| 664 |
- srcfi = fi |
|
| 665 |
- } else {
|
|
| 666 |
- return errors.Wrap(err, "failed to stat srcPath from differ") |
|
| 667 |
- } |
|
| 668 |
- } |
|
| 669 |
- |
|
| 670 |
- var ok bool |
|
| 671 |
- c.srcStat, ok = srcfi.Sys().(*syscall.Stat_t) |
|
| 672 |
- if !ok {
|
|
| 673 |
- return errors.Errorf("unhandled stat type for %+v", srcfi)
|
|
| 674 |
- } |
|
| 675 |
- |
|
| 676 |
- if !srcfi.IsDir() && c.srcStat.Nlink > 1 {
|
|
| 677 |
- if linkSubPath, ok := d.inodes[statInode(c.srcStat)]; ok {
|
|
| 678 |
- c.linkSubPath = linkSubPath |
|
| 679 |
- } else {
|
|
| 680 |
- d.inodes[statInode(c.srcStat)] = c.subPath |
|
| 681 |
- } |
|
| 682 |
- } |
|
| 683 |
- } |
|
| 684 |
- |
|
| 685 |
- return handle(ctx, c) |
|
| 686 |
- }) |
|
| 687 |
-} |
|
| 688 |
- |
|
| 689 |
-func (d *differ) overlayChanges(ctx context.Context, handle func(context.Context, *change) error) error {
|
|
| 690 |
- return overlay.Changes(ctx, func(kind fs.ChangeKind, subPath string, srcfi os.FileInfo, prevErr error) error {
|
|
| 691 |
- if prevErr != nil {
|
|
| 692 |
- return prevErr |
|
| 693 |
- } |
|
| 694 |
- |
|
| 695 |
- select {
|
|
| 696 |
- case <-ctx.Done(): |
|
| 697 |
- return context.Cause(ctx) |
|
| 698 |
- default: |
|
| 699 |
- } |
|
| 700 |
- |
|
| 701 |
- if kind == fs.ChangeKindUnmodified {
|
|
| 702 |
- return nil |
|
| 703 |
- } |
|
| 704 |
- |
|
| 705 |
- if err := d.checkParent(ctx, subPath, handle); err != nil {
|
|
| 706 |
- return errors.Wrapf(err, "failed to check parent for %s", subPath) |
|
| 707 |
- } |
|
| 708 |
- |
|
| 709 |
- srcPath, err := safeJoin(d.upperdir, subPath) |
|
| 710 |
- if err != nil {
|
|
| 711 |
- return errors.Wrapf(err, "failed to join %s and %s", d.upperdir, subPath) |
|
| 712 |
- } |
|
| 713 |
- |
|
| 714 |
- c := &change{
|
|
| 715 |
- kind: kind, |
|
| 716 |
- subPath: subPath, |
|
| 717 |
- srcPath: srcPath, |
|
| 718 |
- } |
|
| 719 |
- |
|
| 720 |
- if srcfi != nil {
|
|
| 721 |
- var ok bool |
|
| 722 |
- c.srcStat, ok = srcfi.Sys().(*syscall.Stat_t) |
|
| 723 |
- if !ok {
|
|
| 724 |
- return errors.Errorf("unhandled stat type for %+v", srcfi)
|
|
| 725 |
- } |
|
| 726 |
- |
|
| 727 |
- // Changes with Delete kind may share the same inode even if they are unrelated. |
|
| 728 |
- // Skip them to avoid creating hardlinks between whiteouts as whiteouts are not |
|
| 729 |
- // always created and may leave the hardlink dangling. |
|
| 730 |
- if !srcfi.IsDir() && c.srcStat.Nlink > 1 && c.kind != fs.ChangeKindDelete {
|
|
| 731 |
- if linkSubPath, ok := d.inodes[statInode(c.srcStat)]; ok {
|
|
| 732 |
- c.linkSubPath = linkSubPath |
|
| 733 |
- } else {
|
|
| 734 |
- d.inodes[statInode(c.srcStat)] = c.subPath |
|
| 735 |
- } |
|
| 736 |
- } |
|
| 737 |
- } |
|
| 738 |
- |
|
| 739 |
- return handle(ctx, c) |
|
| 740 |
- }, d.upperdir, d.upperRoot, d.lowerRoot) |
|
| 741 |
-} |
|
| 742 |
- |
|
| 743 |
-func (d *differ) checkParent(ctx context.Context, subPath string, handle func(context.Context, *change) error) error {
|
|
| 744 |
- parentSubPath := filepath.Dir(subPath) |
|
| 745 |
- if parentSubPath == "/" {
|
|
| 746 |
- return nil |
|
| 747 |
- } |
|
| 748 |
- if _, ok := d.visited[parentSubPath]; ok {
|
|
| 749 |
- return nil |
|
| 750 |
- } |
|
| 751 |
- d.visited[parentSubPath] = struct{}{}
|
|
| 752 |
- |
|
| 753 |
- if err := d.checkParent(ctx, parentSubPath, handle); err != nil {
|
|
| 754 |
- return err |
|
| 755 |
- } |
|
| 756 |
- parentSrcPath, err := safeJoin(d.upperRoot, parentSubPath) |
|
| 757 |
- if err != nil {
|
|
| 758 |
- return err |
|
| 759 |
- } |
|
| 760 |
- srcfi, err := os.Lstat(parentSrcPath) |
|
| 761 |
- if err != nil {
|
|
| 762 |
- return err |
|
| 763 |
- } |
|
| 764 |
- parentSrcStat, ok := srcfi.Sys().(*syscall.Stat_t) |
|
| 765 |
- if !ok {
|
|
| 766 |
- return errors.Errorf("unexpected type %T", srcfi)
|
|
| 767 |
- } |
|
| 768 |
- return handle(ctx, &change{
|
|
| 769 |
- kind: fs.ChangeKindModify, |
|
| 770 |
- subPath: parentSubPath, |
|
| 771 |
- srcPath: parentSrcPath, |
|
| 772 |
- srcStat: parentSrcStat, |
|
| 773 |
- }) |
|
| 774 |
-} |
|
| 775 |
- |
|
| 776 |
-func (d *differ) Release() error {
|
|
| 777 |
- var err error |
|
| 778 |
- if d.releaseLower != nil {
|
|
| 779 |
- err = d.releaseLower() |
|
| 780 |
- if err == nil {
|
|
| 781 |
- d.releaseLower = nil |
|
| 782 |
- } |
|
| 783 |
- } |
|
| 784 |
- if d.releaseUpper != nil {
|
|
| 785 |
- err = multierror.Append(err, d.releaseUpper()).ErrorOrNil() |
|
| 786 |
- if err == nil {
|
|
| 787 |
- d.releaseUpper = nil |
|
| 788 |
- } |
|
| 789 |
- } |
|
| 790 |
- return err |
|
| 791 |
-} |
|
| 792 |
- |
|
| 793 |
-func safeJoin(root, path string) (string, error) {
|
|
| 794 |
- dir, base := filepath.Split(path) |
|
| 795 |
- parent, err := fs.RootPath(root, dir) |
|
| 796 |
- if err != nil {
|
|
| 797 |
- return "", err |
|
| 798 |
- } |
|
| 799 |
- return filepath.Join(parent, base), nil |
|
| 800 |
-} |
|
| 801 |
- |
|
| 802 |
-const ( |
|
| 803 |
- trustedOpaqueXattr = "trusted.overlay.opaque" |
|
| 804 |
- userOpaqueXattr = "user.overlay.opaque" |
|
| 805 |
-) |
|
| 806 |
- |
|
| 807 |
-func isOpaqueXattr(s string) bool {
|
|
| 808 |
- for _, k := range []string{trustedOpaqueXattr, userOpaqueXattr} {
|
|
| 809 |
- if s == k {
|
|
| 810 |
- return true |
|
| 811 |
- } |
|
| 812 |
- } |
|
| 813 |
- return false |
|
| 814 |
-} |
|
| 815 |
- |
|
| 816 |
-func opaqueXattr(userxattr bool) string {
|
|
| 817 |
- if userxattr {
|
|
| 818 |
- return userOpaqueXattr |
|
| 819 |
- } |
|
| 820 |
- return trustedOpaqueXattr |
|
| 821 |
-} |
|
| 822 |
- |
|
| 823 |
-// needsUserXAttr checks whether overlay mounts should be provided the userxattr option. We can't use |
|
| 824 |
-// NeedsUserXAttr from the overlayutils package directly because we don't always have direct knowledge |
|
| 825 |
-// of the root of the snapshotter state (such as when using a remote snapshotter). Instead, we create |
|
| 826 |
-// a temporary new snapshot and test using its root, which works because single layer snapshots will |
|
| 827 |
-// use bind-mounts even when created by an overlay based snapshotter. |
|
| 828 |
-func needsUserXAttr(ctx context.Context, sn Snapshotter, lm leases.Manager) (bool, error) {
|
|
| 829 |
- key := identity.NewID() |
|
| 830 |
- |
|
| 831 |
- ctx, done, err := leaseutil.WithLease(ctx, lm, leaseutil.MakeTemporary) |
|
| 832 |
- if err != nil {
|
|
| 833 |
- return false, errors.Wrap(err, "failed to create lease for checking user xattr") |
|
| 834 |
- } |
|
| 835 |
- defer done(context.TODO()) |
|
| 836 |
- |
|
| 837 |
- err = sn.Prepare(ctx, key, "") |
|
| 838 |
- if err != nil {
|
|
| 839 |
- return false, err |
|
| 840 |
- } |
|
| 841 |
- mntable, err := sn.Mounts(ctx, key) |
|
| 842 |
- if err != nil {
|
|
| 843 |
- return false, err |
|
| 844 |
- } |
|
| 845 |
- mnts, unmount, err := mntable.Mount() |
|
| 846 |
- if err != nil {
|
|
| 847 |
- return false, err |
|
| 848 |
- } |
|
| 849 |
- defer unmount() |
|
| 850 |
- |
|
| 851 |
- var userxattr bool |
|
| 852 |
- if err := mount.WithTempMount(ctx, mnts, func(root string) error {
|
|
| 853 |
- var err error |
|
| 854 |
- userxattr, err = overlayutils.NeedsUserXAttr(root) |
|
| 855 |
- return err |
|
| 856 |
- }); err != nil {
|
|
| 857 |
- return false, err |
|
| 858 |
- } |
|
| 859 |
- return userxattr, nil |
|
| 860 |
-} |
| 861 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,21 @@ |
| 0 |
+//go:build !linux |
|
| 1 |
+// +build !linux |
|
| 2 |
+ |
|
| 3 |
+package snapshot |
|
| 4 |
+ |
|
| 5 |
+import ( |
|
| 6 |
+ "context" |
|
| 7 |
+ "runtime" |
|
| 8 |
+ |
|
| 9 |
+ "github.com/containerd/containerd/leases" |
|
| 10 |
+ "github.com/containerd/containerd/snapshots" |
|
| 11 |
+ "github.com/pkg/errors" |
|
| 12 |
+) |
|
| 13 |
+ |
|
| 14 |
+func (sn *mergeSnapshotter) diffApply(_ context.Context, _ Mountable, _ ...Diff) (_ snapshots.Usage, rerr error) {
|
|
| 15 |
+ return snapshots.Usage{}, errors.New("diffApply not yet supported on " + runtime.GOOS)
|
|
| 16 |
+} |
|
| 17 |
+ |
|
| 18 |
+func needsUserXAttr(_ context.Context, _ Snapshotter, _ leases.Manager) (bool, error) {
|
|
| 19 |
+ return false, errors.New("needs userxattr not supported on " + runtime.GOOS)
|
|
| 20 |
+} |
| 0 | 21 |
deleted file mode 100644 |
| ... | ... |
@@ -1,20 +0,0 @@ |
| 1 |
-//go:build windows |
|
| 2 |
-// +build windows |
|
| 3 |
- |
|
| 4 |
-package snapshot |
|
| 5 |
- |
|
| 6 |
-import ( |
|
| 7 |
- "context" |
|
| 8 |
- |
|
| 9 |
- "github.com/containerd/containerd/leases" |
|
| 10 |
- "github.com/containerd/containerd/snapshots" |
|
| 11 |
- "github.com/pkg/errors" |
|
| 12 |
-) |
|
| 13 |
- |
|
| 14 |
-func (sn *mergeSnapshotter) diffApply(_ context.Context, _ Mountable, _ ...Diff) (_ snapshots.Usage, rerr error) {
|
|
| 15 |
- return snapshots.Usage{}, errors.New("diffApply not yet supported on windows")
|
|
| 16 |
-} |
|
| 17 |
- |
|
| 18 |
-func needsUserXAttr(_ context.Context, _ Snapshotter, _ leases.Manager) (bool, error) {
|
|
| 19 |
- return false, errors.New("needs userxattr not supported on windows")
|
|
| 20 |
-} |
| ... | ... |
@@ -5,11 +5,11 @@ import ( |
| 5 | 5 |
"strconv" |
| 6 | 6 |
|
| 7 | 7 |
"github.com/containerd/containerd/leases" |
| 8 |
- "github.com/containerd/containerd/pkg/userns" |
|
| 9 | 8 |
"github.com/containerd/containerd/snapshots" |
| 10 | 9 |
"github.com/moby/buildkit/identity" |
| 11 | 10 |
"github.com/moby/buildkit/util/bklog" |
| 12 | 11 |
"github.com/moby/buildkit/util/leaseutil" |
| 12 |
+ "github.com/moby/sys/userns" |
|
| 13 | 13 |
"github.com/pkg/errors" |
| 14 | 14 |
) |
| 15 | 15 |
|
| ... | ... |
@@ -7,10 +7,10 @@ import ( |
| 7 | 7 |
"sync" |
| 8 | 8 |
|
| 9 | 9 |
"github.com/containerd/containerd/mount" |
| 10 |
- "github.com/containerd/containerd/pkg/userns" |
|
| 11 | 10 |
"github.com/containerd/containerd/snapshots" |
| 12 | 11 |
"github.com/docker/docker/pkg/idtools" |
| 13 | 12 |
"github.com/moby/buildkit/executor" |
| 13 |
+ "github.com/moby/sys/userns" |
|
| 14 | 14 |
"github.com/pkg/errors" |
| 15 | 15 |
) |
| 16 | 16 |
|
| ... | ... |
@@ -9,6 +9,8 @@ import ( |
| 9 | 9 |
"github.com/moby/buildkit/identity" |
| 10 | 10 |
"github.com/moby/buildkit/solver" |
| 11 | 11 |
"github.com/moby/buildkit/util/bklog" |
| 12 |
+ "github.com/moby/buildkit/util/db" |
|
| 13 |
+ "github.com/moby/buildkit/util/db/boltutil" |
|
| 12 | 14 |
digest "github.com/opencontainers/go-digest" |
| 13 | 15 |
"github.com/pkg/errors" |
| 14 | 16 |
bolt "go.etcd.io/bbolt" |
| ... | ... |
@@ -22,11 +24,13 @@ const ( |
| 22 | 22 |
) |
| 23 | 23 |
|
| 24 | 24 |
type Store struct {
|
| 25 |
- db *bolt.DB |
|
| 25 |
+ db db.DB |
|
| 26 | 26 |
} |
| 27 | 27 |
|
| 28 | 28 |
func NewStore(dbPath string) (*Store, error) {
|
| 29 |
- db, err := safeOpenDB(dbPath) |
|
| 29 |
+ db, err := safeOpenDB(dbPath, &bolt.Options{
|
|
| 30 |
+ NoSync: true, |
|
| 31 |
+ }) |
|
| 30 | 32 |
if err != nil {
|
| 31 | 33 |
return nil, err |
| 32 | 34 |
} |
| ... | ... |
@@ -42,7 +46,6 @@ func NewStore(dbPath string) (*Store, error) {
|
| 42 | 42 |
}); err != nil {
|
| 43 | 43 |
return nil, err |
| 44 | 44 |
} |
| 45 |
- db.NoSync = true |
|
| 46 | 45 |
return &Store{db: db}, nil
|
| 47 | 46 |
} |
| 48 | 47 |
|
| ... | ... |
@@ -465,7 +468,7 @@ func isEmptyBucket(b *bolt.Bucket) bool {
|
| 465 | 465 |
|
| 466 | 466 |
// safeOpenDB opens a bolt database and recovers from panic that |
| 467 | 467 |
// can be caused by a corrupted database file. |
| 468 |
-func safeOpenDB(dbPath string) (db *bolt.DB, err error) {
|
|
| 468 |
+func safeOpenDB(dbPath string, opts *bolt.Options) (db db.DB, err error) {
|
|
| 469 | 469 |
defer func() {
|
| 470 | 470 |
if r := recover(); r != nil {
|
| 471 | 471 |
err = errors.Errorf("%v", r)
|
| ... | ... |
@@ -476,16 +479,16 @@ func safeOpenDB(dbPath string) (db *bolt.DB, err error) {
|
| 476 | 476 |
// then fallback to resetting the database since the database |
| 477 | 477 |
// may be corrupt. |
| 478 | 478 |
if err != nil && fileHasContent(dbPath) {
|
| 479 |
- db, err = fallbackOpenDB(dbPath, err) |
|
| 479 |
+ db, err = fallbackOpenDB(dbPath, opts, err) |
|
| 480 | 480 |
} |
| 481 | 481 |
}() |
| 482 |
- return openDB(dbPath) |
|
| 482 |
+ return openDB(dbPath, opts) |
|
| 483 | 483 |
} |
| 484 | 484 |
|
| 485 | 485 |
// fallbackOpenDB performs database recovery and opens the new database |
| 486 | 486 |
// file when the database fails to open. Called after the first database |
| 487 | 487 |
// open fails. |
| 488 |
-func fallbackOpenDB(dbPath string, openErr error) (*bolt.DB, error) {
|
|
| 488 |
+func fallbackOpenDB(dbPath string, opts *bolt.Options, openErr error) (db.DB, error) {
|
|
| 489 | 489 |
backupPath := dbPath + "." + identity.NewID() + ".bak" |
| 490 | 490 |
bklog.L.Errorf("failed to open database file %s, resetting to empty. Old database is backed up to %s. "+
|
| 491 | 491 |
"This error signifies that buildkitd likely crashed or was sigkilled abrubtly, leaving the database corrupted. "+ |
| ... | ... |
@@ -496,12 +499,12 @@ func fallbackOpenDB(dbPath string, openErr error) (*bolt.DB, error) {
|
| 496 | 496 |
|
| 497 | 497 |
// Attempt to open the database again. This should be a new database. |
| 498 | 498 |
// If this fails, it is a permanent error. |
| 499 |
- return openDB(dbPath) |
|
| 499 |
+ return openDB(dbPath, opts) |
|
| 500 | 500 |
} |
| 501 | 501 |
|
| 502 | 502 |
// openDB opens a bolt database in user-only read/write mode. |
| 503 |
-func openDB(dbPath string) (*bolt.DB, error) {
|
|
| 504 |
- return bolt.Open(dbPath, 0600, nil) |
|
| 503 |
+func openDB(dbPath string, opts *bolt.Options) (db.DB, error) {
|
|
| 504 |
+ return boltutil.Open(dbPath, 0600, opts) |
|
| 505 | 505 |
} |
| 506 | 506 |
|
| 507 | 507 |
// fileHasContent checks if we have access to the file with appropriate |
| ... | ... |
@@ -27,10 +27,17 @@ func timestampToTime(ts int64) *time.Time {
|
| 27 | 27 |
return &tm |
| 28 | 28 |
} |
| 29 | 29 |
|
| 30 |
-func mkdir(d string, action pb.FileActionMkDir, user *copy.User, idmap *idtools.IdentityMapping) error {
|
|
| 30 |
+func mkdir(d string, action pb.FileActionMkDir, user *copy.User, idmap *idtools.IdentityMapping) (err error) {
|
|
| 31 |
+ defer func() {
|
|
| 32 |
+ var osErr *os.PathError |
|
| 33 |
+ if errors.As(err, &osErr) {
|
|
| 34 |
+ osErr.Path = strings.TrimPrefix(osErr.Path, d) |
|
| 35 |
+ } |
|
| 36 |
+ }() |
|
| 37 |
+ |
|
| 31 | 38 |
p, err := fs.RootPath(d, action.Path) |
| 32 | 39 |
if err != nil {
|
| 33 |
- return err |
|
| 40 |
+ return errors.WithStack(err) |
|
| 34 | 41 |
} |
| 35 | 42 |
|
| 36 | 43 |
ch, err := mapUserToChowner(user, idmap) |
| ... | ... |
@@ -47,23 +54,31 @@ func mkdir(d string, action pb.FileActionMkDir, user *copy.User, idmap *idtools. |
| 47 | 47 |
if errors.Is(err, os.ErrExist) {
|
| 48 | 48 |
return nil |
| 49 | 49 |
} |
| 50 |
- return err |
|
| 50 |
+ return errors.WithStack(err) |
|
| 51 | 51 |
} |
| 52 | 52 |
if err := copy.Chown(p, nil, ch); err != nil {
|
| 53 |
- return err |
|
| 53 |
+ return errors.WithStack(err) |
|
| 54 | 54 |
} |
| 55 | 55 |
if err := copy.Utimes(p, timestampToTime(action.Timestamp)); err != nil {
|
| 56 |
- return err |
|
| 56 |
+ return errors.WithStack(err) |
|
| 57 | 57 |
} |
| 58 | 58 |
} |
| 59 | 59 |
|
| 60 | 60 |
return nil |
| 61 | 61 |
} |
| 62 | 62 |
|
| 63 |
-func mkfile(d string, action pb.FileActionMkFile, user *copy.User, idmap *idtools.IdentityMapping) error {
|
|
| 63 |
+func mkfile(d string, action pb.FileActionMkFile, user *copy.User, idmap *idtools.IdentityMapping) (err error) {
|
|
| 64 |
+ defer func() {
|
|
| 65 |
+ var osErr *os.PathError |
|
| 66 |
+ if errors.As(err, &osErr) {
|
|
| 67 |
+ // remove system root from error path if present |
|
| 68 |
+ osErr.Path = strings.TrimPrefix(osErr.Path, d) |
|
| 69 |
+ } |
|
| 70 |
+ }() |
|
| 71 |
+ |
|
| 64 | 72 |
p, err := fs.RootPath(d, filepath.Join("/", action.Path))
|
| 65 | 73 |
if err != nil {
|
| 66 |
- return err |
|
| 74 |
+ return errors.WithStack(err) |
|
| 67 | 75 |
} |
| 68 | 76 |
|
| 69 | 77 |
ch, err := mapUserToChowner(user, idmap) |
| ... | ... |
@@ -72,21 +87,29 @@ func mkfile(d string, action pb.FileActionMkFile, user *copy.User, idmap *idtool |
| 72 | 72 |
} |
| 73 | 73 |
|
| 74 | 74 |
if err := os.WriteFile(p, action.Data, os.FileMode(action.Mode)&0777); err != nil {
|
| 75 |
- return err |
|
| 75 |
+ return errors.WithStack(err) |
|
| 76 | 76 |
} |
| 77 | 77 |
|
| 78 | 78 |
if err := copy.Chown(p, nil, ch); err != nil {
|
| 79 |
- return err |
|
| 79 |
+ return errors.WithStack(err) |
|
| 80 | 80 |
} |
| 81 | 81 |
|
| 82 | 82 |
if err := copy.Utimes(p, timestampToTime(action.Timestamp)); err != nil {
|
| 83 |
- return err |
|
| 83 |
+ return errors.WithStack(err) |
|
| 84 | 84 |
} |
| 85 | 85 |
|
| 86 | 86 |
return nil |
| 87 | 87 |
} |
| 88 | 88 |
|
| 89 |
-func rm(d string, action pb.FileActionRm) error {
|
|
| 89 |
+func rm(d string, action pb.FileActionRm) (err error) {
|
|
| 90 |
+ defer func() {
|
|
| 91 |
+ var osErr *os.PathError |
|
| 92 |
+ if errors.As(err, &osErr) {
|
|
| 93 |
+ // remove system root from error path if present |
|
| 94 |
+ osErr.Path = strings.TrimPrefix(osErr.Path, d) |
|
| 95 |
+ } |
|
| 96 |
+ }() |
|
| 97 |
+ |
|
| 90 | 98 |
if action.AllowWildcard {
|
| 91 | 99 |
src, err := cleanPath(action.Path) |
| 92 | 100 |
if err != nil {
|
| ... | ... |
@@ -94,7 +117,7 @@ func rm(d string, action pb.FileActionRm) error {
|
| 94 | 94 |
} |
| 95 | 95 |
m, err := copy.ResolveWildcards(d, src, false) |
| 96 | 96 |
if err != nil {
|
| 97 |
- return err |
|
| 97 |
+ return errors.WithStack(err) |
|
| 98 | 98 |
} |
| 99 | 99 |
|
| 100 | 100 |
for _, s := range m {
|
| ... | ... |
@@ -117,7 +140,7 @@ func rmPath(root, src string, allowNotFound bool) error {
|
| 117 | 117 |
} |
| 118 | 118 |
dir, err := fs.RootPath(root, filepath.Join("/", dir))
|
| 119 | 119 |
if err != nil {
|
| 120 |
- return err |
|
| 120 |
+ return errors.WithStack(err) |
|
| 121 | 121 |
} |
| 122 | 122 |
p := filepath.Join(dir, base) |
| 123 | 123 |
|
| ... | ... |
@@ -125,14 +148,14 @@ func rmPath(root, src string, allowNotFound bool) error {
|
| 125 | 125 |
_, err := os.Stat(p) |
| 126 | 126 |
|
| 127 | 127 |
if errors.Is(err, os.ErrNotExist) {
|
| 128 |
- return err |
|
| 128 |
+ return errors.WithStack(err) |
|
| 129 | 129 |
} |
| 130 | 130 |
} |
| 131 | 131 |
|
| 132 |
- return os.RemoveAll(p) |
|
| 132 |
+ return errors.WithStack(os.RemoveAll(p)) |
|
| 133 | 133 |
} |
| 134 | 134 |
|
| 135 |
-func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u *copy.User, idmap *idtools.IdentityMapping) error {
|
|
| 135 |
+func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u *copy.User, idmap *idtools.IdentityMapping) (err error) {
|
|
| 136 | 136 |
srcPath, err := cleanPath(action.Src) |
| 137 | 137 |
if err != nil {
|
| 138 | 138 |
return errors.Wrap(err, "cleaning source path") |
| ... | ... |
@@ -144,7 +167,7 @@ func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u * |
| 144 | 144 |
if !action.CreateDestPath {
|
| 145 | 145 |
p, err := fs.RootPath(dest, filepath.Join("/", action.Dest))
|
| 146 | 146 |
if err != nil {
|
| 147 |
- return err |
|
| 147 |
+ return errors.WithStack(err) |
|
| 148 | 148 |
} |
| 149 | 149 |
if _, err := os.Lstat(filepath.Dir(p)); err != nil {
|
| 150 | 150 |
return errors.Wrapf(err, "failed to stat %s", action.Dest) |
| ... | ... |
@@ -177,6 +200,15 @@ func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u * |
| 177 | 177 |
copy.WithXAttrErrorHandler(xattrErrorHandler), |
| 178 | 178 |
} |
| 179 | 179 |
|
| 180 |
+ defer func() {
|
|
| 181 |
+ var osErr *os.PathError |
|
| 182 |
+ if errors.As(err, &osErr) {
|
|
| 183 |
+ // remove system root from error path if present |
|
| 184 |
+ osErr.Path = strings.TrimPrefix(osErr.Path, src) |
|
| 185 |
+ osErr.Path = strings.TrimPrefix(osErr.Path, dest) |
|
| 186 |
+ } |
|
| 187 |
+ }() |
|
| 188 |
+ |
|
| 180 | 189 |
var m []string |
| 181 | 190 |
if !action.AllowWildcard {
|
| 182 | 191 |
m = []string{srcPath}
|
| ... | ... |
@@ -184,7 +216,7 @@ func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u * |
| 184 | 184 |
var err error |
| 185 | 185 |
m, err = copy.ResolveWildcards(src, srcPath, action.FollowSymlink) |
| 186 | 186 |
if err != nil {
|
| 187 |
- return err |
|
| 187 |
+ return errors.WithStack(err) |
|
| 188 | 188 |
} |
| 189 | 189 |
|
| 190 | 190 |
if len(m) == 0 {
|
| ... | ... |
@@ -198,13 +230,13 @@ func docopy(ctx context.Context, src, dest string, action pb.FileActionCopy, u * |
| 198 | 198 |
for _, s := range m {
|
| 199 | 199 |
if action.AttemptUnpackDockerCompatibility {
|
| 200 | 200 |
if ok, err := unpack(src, s, dest, destPath, ch, timestampToTime(action.Timestamp), idmap); err != nil {
|
| 201 |
- return err |
|
| 201 |
+ return errors.WithStack(err) |
|
| 202 | 202 |
} else if ok {
|
| 203 | 203 |
continue |
| 204 | 204 |
} |
| 205 | 205 |
} |
| 206 | 206 |
if err := copy.Copy(ctx, src, s, dest, destPath, opt...); err != nil {
|
| 207 |
- return err |
|
| 207 |
+ return errors.WithStack(err) |
|
| 208 | 208 |
} |
| 209 | 209 |
} |
| 210 | 210 |
|
| ... | ... |
@@ -5,6 +5,7 @@ package file |
| 5 | 5 |
|
| 6 | 6 |
import ( |
| 7 | 7 |
"github.com/docker/docker/pkg/idtools" |
| 8 |
+ "github.com/pkg/errors" |
|
| 8 | 9 |
copy "github.com/tonistiigi/fsutil/copy" |
| 9 | 10 |
) |
| 10 | 11 |
|
| ... | ... |
@@ -23,7 +24,7 @@ func mapUserToChowner(user *copy.User, idmap *idtools.IdentityMapping) (copy.Cho |
| 23 | 23 |
GID: old.GID, |
| 24 | 24 |
}) |
| 25 | 25 |
if err != nil {
|
| 26 |
- return nil, err |
|
| 26 |
+ return nil, errors.WithStack(err) |
|
| 27 | 27 |
} |
| 28 | 28 |
return ©.User{UID: identity.UID, GID: identity.GID}, nil
|
| 29 | 29 |
} |
| ... | ... |
@@ -38,7 +39,7 @@ func mapUserToChowner(user *copy.User, idmap *idtools.IdentityMapping) (copy.Cho |
| 38 | 38 |
GID: user.GID, |
| 39 | 39 |
}) |
| 40 | 40 |
if err != nil {
|
| 41 |
- return nil, err |
|
| 41 |
+ return nil, errors.WithStack(err) |
|
| 42 | 42 |
} |
| 43 | 43 |
u.UID = identity.UID |
| 44 | 44 |
u.GID = identity.GID |
| ... | ... |
@@ -22,6 +22,7 @@ import ( |
| 22 | 22 |
"github.com/moby/buildkit/cmd/buildkitd/config" |
| 23 | 23 |
"github.com/moby/buildkit/identity" |
| 24 | 24 |
containerdsnapshot "github.com/moby/buildkit/snapshot/containerd" |
| 25 |
+ "github.com/moby/buildkit/util/db" |
|
| 25 | 26 |
"github.com/moby/buildkit/util/grpcerrors" |
| 26 | 27 |
"github.com/moby/buildkit/util/iohelper" |
| 27 | 28 |
"github.com/moby/buildkit/util/leaseutil" |
| ... | ... |
@@ -39,7 +40,7 @@ const ( |
| 39 | 39 |
) |
| 40 | 40 |
|
| 41 | 41 |
type HistoryQueueOpt struct {
|
| 42 |
- DB *bolt.DB |
|
| 42 |
+ DB db.Transactor |
|
| 43 | 43 |
LeaseManager *leaseutil.Manager |
| 44 | 44 |
ContentStore *containerdsnapshot.Store |
| 45 | 45 |
CleanConfig *config.HistoryConfig |
| ... | ... |
@@ -71,6 +72,7 @@ type StatusImportResult struct {
|
| 71 | 71 |
NumCachedSteps int |
| 72 | 72 |
NumCompletedSteps int |
| 73 | 73 |
NumTotalSteps int |
| 74 |
+ NumWarnings int |
|
| 74 | 75 |
} |
| 75 | 76 |
|
| 76 | 77 |
func NewHistoryQueue(opt HistoryQueueOpt) (*HistoryQueue, error) {
|
| ... | ... |
@@ -779,9 +781,11 @@ func (h *HistoryQueue) ImportStatus(ctx context.Context, ch chan *client.SolveSt |
| 779 | 779 |
completed bool |
| 780 | 780 |
} |
| 781 | 781 |
vtxMap := make(map[digest.Digest]*vtxInfo) |
| 782 |
+ var numWarnings int |
|
| 782 | 783 |
|
| 783 | 784 |
buf := make([]byte, 32*1024) |
| 784 | 785 |
for st := range ch {
|
| 786 |
+ numWarnings += len(st.Warnings) |
|
| 785 | 787 |
for _, vtx := range st.Vertexes {
|
| 786 | 788 |
if _, ok := vtxMap[vtx.Digest]; !ok {
|
| 787 | 789 |
vtxMap[vtx.Digest] = &vtxInfo{}
|
| ... | ... |
@@ -837,6 +841,7 @@ func (h *HistoryQueue) ImportStatus(ctx context.Context, ch chan *client.SolveSt |
| 837 | 837 |
NumCachedSteps: numCached, |
| 838 | 838 |
NumCompletedSteps: numCompleted, |
| 839 | 839 |
NumTotalSteps: len(vtxMap), |
| 840 |
+ NumWarnings: numWarnings, |
|
| 840 | 841 |
}, release, nil |
| 841 | 842 |
} |
| 842 | 843 |
|
| ... | ... |
@@ -11,7 +11,6 @@ import ( |
| 11 | 11 |
"github.com/moby/buildkit/util/bklog" |
| 12 | 12 |
|
| 13 | 13 |
"github.com/containerd/containerd/mount" |
| 14 |
- "github.com/containerd/containerd/pkg/userns" |
|
| 15 | 14 |
"github.com/docker/docker/pkg/idtools" |
| 16 | 15 |
"github.com/moby/buildkit/cache" |
| 17 | 16 |
"github.com/moby/buildkit/client" |
| ... | ... |
@@ -23,6 +22,7 @@ import ( |
| 23 | 23 |
"github.com/moby/buildkit/solver/pb" |
| 24 | 24 |
"github.com/moby/buildkit/util/grpcerrors" |
| 25 | 25 |
"github.com/moby/locker" |
| 26 |
+ "github.com/moby/sys/userns" |
|
| 26 | 27 |
"github.com/pkg/errors" |
| 27 | 28 |
"google.golang.org/grpc/codes" |
| 28 | 29 |
) |
| ... | ... |
@@ -169,7 +169,7 @@ func (f *fileOp) Exec(ctx context.Context, g session.Group, inputs []solver.Resu |
| 169 | 169 |
|
| 170 | 170 |
backend, err := file.NewFileOpBackend(getReadUserFn(f.w)) |
| 171 | 171 |
if err != nil {
|
| 172 |
- return nil, err |
|
| 172 |
+ return nil, errors.WithStack(err) |
|
| 173 | 173 |
} |
| 174 | 174 |
|
| 175 | 175 |
fs := NewFileOpSolver(f.w, backend, f.refManager) |
| ... | ... |
@@ -474,7 +474,7 @@ func (s *FileOpSolver) getInput(ctx context.Context, idx int, inputs []fileoptyp |
| 474 | 474 |
if inp.ref != nil {
|
| 475 | 475 |
m, err := s.r.Prepare(ctx, inp.ref, false, g) |
| 476 | 476 |
if err != nil {
|
| 477 |
- return err |
|
| 477 |
+ return errors.WithStack(err) |
|
| 478 | 478 |
} |
| 479 | 479 |
inpMount = m |
| 480 | 480 |
return nil |
| ... | ... |
@@ -493,7 +493,7 @@ func (s *FileOpSolver) getInput(ctx context.Context, idx int, inputs []fileoptyp |
| 493 | 493 |
if inp.ref != nil {
|
| 494 | 494 |
m, err := s.r.Prepare(ctx, inp.ref, true, g) |
| 495 | 495 |
if err != nil {
|
| 496 |
- return err |
|
| 496 |
+ return errors.WithStack(err) |
|
| 497 | 497 |
} |
| 498 | 498 |
inpMountSecondary = m |
| 499 | 499 |
toRelease = append(toRelease, m) |
| ... | ... |
@@ -521,7 +521,7 @@ func (s *FileOpSolver) getInput(ctx context.Context, idx int, inputs []fileoptyp |
| 521 | 521 |
if inp.ref != nil {
|
| 522 | 522 |
mm, err := s.r.Prepare(ctx, inp.ref, true, g) |
| 523 | 523 |
if err != nil {
|
| 524 |
- return nil, err |
|
| 524 |
+ return nil, errors.WithStack(err) |
|
| 525 | 525 |
} |
| 526 | 526 |
toRelease = append(toRelease, mm) |
| 527 | 527 |
m = mm |
| ... | ... |
@@ -572,7 +572,7 @@ func (s *FileOpSolver) getInput(ctx context.Context, idx int, inputs []fileoptyp |
| 572 | 572 |
if inpMount == nil {
|
| 573 | 573 |
m, err := s.r.Prepare(ctx, nil, false, g) |
| 574 | 574 |
if err != nil {
|
| 575 |
- return input{}, err
|
|
| 575 |
+ return input{}, errors.WithStack(err)
|
|
| 576 | 576 |
} |
| 577 | 577 |
inpMount = m |
| 578 | 578 |
} |
| ... | ... |
@@ -18,6 +18,7 @@ import ( |
| 18 | 18 |
"github.com/moby/buildkit/cache/remotecache" |
| 19 | 19 |
"github.com/moby/buildkit/client" |
| 20 | 20 |
controlgateway "github.com/moby/buildkit/control/gateway" |
| 21 |
+ "github.com/moby/buildkit/errdefs" |
|
| 21 | 22 |
"github.com/moby/buildkit/executor/resources" |
| 22 | 23 |
resourcestypes "github.com/moby/buildkit/executor/resources/types" |
| 23 | 24 |
"github.com/moby/buildkit/exporter" |
| ... | ... |
@@ -158,7 +159,7 @@ func (s *Solver) Bridge(b solver.Builder) frontend.FrontendLLBBridge {
|
| 158 | 158 |
func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend.SolveRequest, exp ExporterRequest, j *solver.Job, usage *resources.SysSampler) (func(context.Context, *Result, []exporter.DescriptorReference, error) error, error) {
|
| 159 | 159 |
stopTrace, err := detect.Recorder.Record(ctx) |
| 160 | 160 |
if err != nil {
|
| 161 |
- return nil, err |
|
| 161 |
+ return nil, errdefs.Internal(err) |
|
| 162 | 162 |
} |
| 163 | 163 |
|
| 164 | 164 |
st := time.Now() |
| ... | ... |
@@ -183,7 +184,7 @@ func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend |
| 183 | 183 |
if stopTrace != nil {
|
| 184 | 184 |
stopTrace() |
| 185 | 185 |
} |
| 186 |
- return nil, err |
|
| 186 |
+ return nil, errdefs.Internal(err) |
|
| 187 | 187 |
} |
| 188 | 188 |
|
| 189 | 189 |
return func(ctx context.Context, res *Result, descrefs []exporter.DescriptorReference, err error) error {
|
| ... | ... |
@@ -329,6 +330,7 @@ func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend |
| 329 | 329 |
rec.NumCachedSteps = int32(st.NumCachedSteps) |
| 330 | 330 |
rec.NumCompletedSteps = int32(st.NumCompletedSteps) |
| 331 | 331 |
rec.NumTotalSteps = int32(st.NumTotalSteps) |
| 332 |
+ rec.NumWarnings = int32(st.NumWarnings) |
|
| 332 | 333 |
mu.Unlock() |
| 333 | 334 |
return nil |
| 334 | 335 |
}) |
| ... | ... |
@@ -370,7 +372,8 @@ func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend |
| 370 | 370 |
}) |
| 371 | 371 |
} |
| 372 | 372 |
if err1 := eg.Wait(); err == nil {
|
| 373 |
- err = err1 |
|
| 373 |
+ // any error from exporting history record is internal |
|
| 374 |
+ err = errdefs.Internal(err1) |
|
| 374 | 375 |
} |
| 375 | 376 |
|
| 376 | 377 |
defer func() {
|
| ... | ... |
@@ -398,7 +401,7 @@ func (s *Solver) recordBuildHistory(ctx context.Context, id string, req frontend |
| 398 | 398 |
Record: rec, |
| 399 | 399 |
}); err1 != nil {
|
| 400 | 400 |
if err == nil {
|
| 401 |
- err = err1 |
|
| 401 |
+ err = errdefs.Internal(err1) |
|
| 402 | 402 |
} |
| 403 | 403 |
} |
| 404 | 404 |
|
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"os" |
| 6 | 6 |
"sync" |
| 7 | 7 |
|
| 8 |
+ "github.com/moby/buildkit/errdefs" |
|
| 8 | 9 |
"github.com/moby/buildkit/solver/internal/pipe" |
| 9 | 10 |
"github.com/moby/buildkit/util/bklog" |
| 10 | 11 |
"github.com/moby/buildkit/util/cond" |
| ... | ... |
@@ -403,7 +404,7 @@ func (pf *pipeFactory) NewInputRequest(ee Edge, req *edgeRequest) pipe.Receiver |
| 403 | 403 |
WithField("edge_index", ee.Index).
|
| 404 | 404 |
Error("failed to get edge: inconsistent graph state")
|
| 405 | 405 |
return pf.NewFuncRequest(func(_ context.Context) (interface{}, error) {
|
| 406 |
- return nil, errors.Errorf("failed to get edge: inconsistent graph state in edge %s %s %d", ee.Vertex.Name(), ee.Vertex.Digest(), ee.Index)
|
|
| 406 |
+ return nil, errdefs.Internal(errors.Errorf("failed to get edge: inconsistent graph state in edge %s %s %d", ee.Vertex.Name(), ee.Vertex.Digest(), ee.Index))
|
|
| 407 | 407 |
}) |
| 408 | 408 |
} |
| 409 | 409 |
p := pf.s.newPipe(target, pf.e, pipe.Request{Payload: req})
|
| ... | ... |
@@ -25,6 +25,7 @@ import ( |
| 25 | 25 |
"github.com/moby/buildkit/util/imageutil" |
| 26 | 26 |
"github.com/moby/buildkit/util/pull" |
| 27 | 27 |
"github.com/moby/buildkit/util/resolver" |
| 28 |
+ "github.com/moby/buildkit/util/tracing" |
|
| 28 | 29 |
digest "github.com/opencontainers/go-digest" |
| 29 | 30 |
ocispecs "github.com/opencontainers/image-spec/specs-go/v1" |
| 30 | 31 |
"github.com/pkg/errors" |
| ... | ... |
@@ -148,7 +149,12 @@ func (is *Source) Resolve(ctx context.Context, id source.Identifier, sm *session |
| 148 | 148 |
return p, nil |
| 149 | 149 |
} |
| 150 | 150 |
|
| 151 |
-func (is *Source) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt, sm *session.Manager, g session.Group) (digest.Digest, []byte, error) {
|
|
| 151 |
+func (is *Source) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt, sm *session.Manager, g session.Group) (digest digest.Digest, config []byte, retErr error) {
|
|
| 152 |
+ span, ctx := tracing.StartSpan(ctx, "resolving "+ref) |
|
| 153 |
+ defer func() {
|
|
| 154 |
+ tracing.FinishWithError(span, retErr) |
|
| 155 |
+ }() |
|
| 156 |
+ |
|
| 152 | 157 |
key := ref |
| 153 | 158 |
var ( |
| 154 | 159 |
rm resolver.ResolveMode |
| 155 | 160 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,63 @@ |
| 0 |
+package git |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "context" |
|
| 4 |
+ "os/exec" |
|
| 5 |
+ "runtime" |
|
| 6 |
+ "syscall" |
|
| 7 |
+ "time" |
|
| 8 |
+ |
|
| 9 |
+ "golang.org/x/sys/unix" |
|
| 10 |
+) |
|
| 11 |
+ |
|
| 12 |
+func runWithStandardUmask(ctx context.Context, cmd *exec.Cmd) error {
|
|
| 13 |
+ errCh := make(chan error) |
|
| 14 |
+ |
|
| 15 |
+ go func() {
|
|
| 16 |
+ defer close(errCh) |
|
| 17 |
+ runtime.LockOSThread() |
|
| 18 |
+ |
|
| 19 |
+ if err := unshareAndRun(ctx, cmd); err != nil {
|
|
| 20 |
+ errCh <- err |
|
| 21 |
+ } |
|
| 22 |
+ }() |
|
| 23 |
+ |
|
| 24 |
+ return <-errCh |
|
| 25 |
+} |
|
| 26 |
+ |
|
| 27 |
+// unshareAndRun needs to be called in a locked thread. |
|
| 28 |
+func unshareAndRun(ctx context.Context, cmd *exec.Cmd) error {
|
|
| 29 |
+ if err := syscall.Unshare(syscall.CLONE_FS); err != nil {
|
|
| 30 |
+ return err |
|
| 31 |
+ } |
|
| 32 |
+ syscall.Umask(0022) |
|
| 33 |
+ return runProcessGroup(ctx, cmd) |
|
| 34 |
+} |
|
| 35 |
+ |
|
| 36 |
+func runProcessGroup(ctx context.Context, cmd *exec.Cmd) error {
|
|
| 37 |
+ cmd.SysProcAttr = &unix.SysProcAttr{
|
|
| 38 |
+ Setpgid: true, |
|
| 39 |
+ Pdeathsig: unix.SIGTERM, |
|
| 40 |
+ } |
|
| 41 |
+ if err := cmd.Start(); err != nil {
|
|
| 42 |
+ return err |
|
| 43 |
+ } |
|
| 44 |
+ waitDone := make(chan struct{})
|
|
| 45 |
+ go func() {
|
|
| 46 |
+ select {
|
|
| 47 |
+ case <-ctx.Done(): |
|
| 48 |
+ _ = unix.Kill(-cmd.Process.Pid, unix.SIGTERM) |
|
| 49 |
+ go func() {
|
|
| 50 |
+ select {
|
|
| 51 |
+ case <-waitDone: |
|
| 52 |
+ case <-time.After(10 * time.Second): |
|
| 53 |
+ _ = unix.Kill(-cmd.Process.Pid, unix.SIGKILL) |
|
| 54 |
+ } |
|
| 55 |
+ }() |
|
| 56 |
+ case <-waitDone: |
|
| 57 |
+ } |
|
| 58 |
+ }() |
|
| 59 |
+ err := cmd.Wait() |
|
| 60 |
+ close(waitDone) |
|
| 61 |
+ return err |
|
| 62 |
+} |
| 0 | 63 |
deleted file mode 100644 |
| ... | ... |
@@ -1,66 +0,0 @@ |
| 1 |
-//go:build !windows && !freebsd |
|
| 2 |
-// +build !windows,!freebsd |
|
| 3 |
- |
|
| 4 |
-package git |
|
| 5 |
- |
|
| 6 |
-import ( |
|
| 7 |
- "context" |
|
| 8 |
- "os/exec" |
|
| 9 |
- "runtime" |
|
| 10 |
- "syscall" |
|
| 11 |
- "time" |
|
| 12 |
- |
|
| 13 |
- "golang.org/x/sys/unix" |
|
| 14 |
-) |
|
| 15 |
- |
|
| 16 |
-func runWithStandardUmask(ctx context.Context, cmd *exec.Cmd) error {
|
|
| 17 |
- errCh := make(chan error) |
|
| 18 |
- |
|
| 19 |
- go func() {
|
|
| 20 |
- defer close(errCh) |
|
| 21 |
- runtime.LockOSThread() |
|
| 22 |
- |
|
| 23 |
- if err := unshareAndRun(ctx, cmd); err != nil {
|
|
| 24 |
- errCh <- err |
|
| 25 |
- } |
|
| 26 |
- }() |
|
| 27 |
- |
|
| 28 |
- return <-errCh |
|
| 29 |
-} |
|
| 30 |
- |
|
| 31 |
-// unshareAndRun needs to be called in a locked thread. |
|
| 32 |
-func unshareAndRun(ctx context.Context, cmd *exec.Cmd) error {
|
|
| 33 |
- if err := syscall.Unshare(syscall.CLONE_FS); err != nil {
|
|
| 34 |
- return err |
|
| 35 |
- } |
|
| 36 |
- syscall.Umask(0022) |
|
| 37 |
- return runProcessGroup(ctx, cmd) |
|
| 38 |
-} |
|
| 39 |
- |
|
| 40 |
-func runProcessGroup(ctx context.Context, cmd *exec.Cmd) error {
|
|
| 41 |
- cmd.SysProcAttr = &unix.SysProcAttr{
|
|
| 42 |
- Setpgid: true, |
|
| 43 |
- Pdeathsig: unix.SIGTERM, |
|
| 44 |
- } |
|
| 45 |
- if err := cmd.Start(); err != nil {
|
|
| 46 |
- return err |
|
| 47 |
- } |
|
| 48 |
- waitDone := make(chan struct{})
|
|
| 49 |
- go func() {
|
|
| 50 |
- select {
|
|
| 51 |
- case <-ctx.Done(): |
|
| 52 |
- _ = unix.Kill(-cmd.Process.Pid, unix.SIGTERM) |
|
| 53 |
- go func() {
|
|
| 54 |
- select {
|
|
| 55 |
- case <-waitDone: |
|
| 56 |
- case <-time.After(10 * time.Second): |
|
| 57 |
- _ = unix.Kill(-cmd.Process.Pid, unix.SIGKILL) |
|
| 58 |
- } |
|
| 59 |
- }() |
|
| 60 |
- case <-waitDone: |
|
| 61 |
- } |
|
| 62 |
- }() |
|
| 63 |
- err := cmd.Wait() |
|
| 64 |
- close(waitDone) |
|
| 65 |
- return err |
|
| 66 |
-} |
| ... | ... |
@@ -10,7 +10,6 @@ import ( |
| 10 | 10 |
) |
| 11 | 11 |
|
| 12 | 12 |
const ( |
| 13 |
- Address = "unix:///run/buildkit/buildkitd.sock" |
|
| 14 | 13 |
Root = "/var/lib/buildkit" |
| 15 | 14 |
ConfigDir = "/etc/buildkit" |
| 16 | 15 |
DefaultCNIBinDir = "/opt/cni/bin" |
| ... | ... |
@@ -82,5 +81,5 @@ func TraceSocketPath(inUserNS bool) string {
|
| 82 | 82 |
return filepath.Join(dirs[0], "buildkit", "otel-grpc.sock") |
| 83 | 83 |
} |
| 84 | 84 |
} |
| 85 |
- return "/run/buildkit/otel-grpc.sock" |
|
| 85 |
+ return traceSocketPath |
|
| 86 | 86 |
} |
| 0 | 8 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,16 @@ |
| 0 |
+package boltutil |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "io/fs" |
|
| 4 |
+ |
|
| 5 |
+ "github.com/moby/buildkit/util/db" |
|
| 6 |
+ bolt "go.etcd.io/bbolt" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+func Open(p string, mode fs.FileMode, options *bolt.Options) (db.DB, error) {
|
|
| 10 |
+ bdb, err := bolt.Open(p, mode, options) |
|
| 11 |
+ if err != nil {
|
|
| 12 |
+ return nil, err |
|
| 13 |
+ } |
|
| 14 |
+ return bdb, nil |
|
| 15 |
+} |
| 0 | 8 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,11 @@ |
| 0 |
+package db |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ bolt "go.etcd.io/bbolt" |
|
| 4 |
+) |
|
| 5 |
+ |
|
| 6 |
+// Transactor is the database interface for running transactions |
|
| 7 |
+type Transactor interface {
|
|
| 8 |
+ View(fn func(*bolt.Tx) error) error |
|
| 9 |
+ Update(fn func(*bolt.Tx) error) error |
|
| 10 |
+} |
| ... | ... |
@@ -9,8 +9,8 @@ import ( |
| 9 | 9 |
"github.com/containerd/containerd/containers" |
| 10 | 10 |
"github.com/containerd/containerd/oci" |
| 11 | 11 |
"github.com/containerd/containerd/pkg/cap" |
| 12 |
- "github.com/containerd/containerd/pkg/userns" |
|
| 13 | 12 |
"github.com/moby/buildkit/util/bklog" |
| 13 |
+ "github.com/moby/sys/userns" |
|
| 14 | 14 |
specs "github.com/opencontainers/runtime-spec/specs-go" |
| 15 | 15 |
"github.com/pkg/errors" |
| 16 | 16 |
"golang.org/x/sys/unix" |
| ... | ... |
@@ -10,6 +10,7 @@ import ( |
| 10 | 10 |
gogotypes "github.com/gogo/protobuf/types" |
| 11 | 11 |
"github.com/golang/protobuf/proto" //nolint:staticcheck |
| 12 | 12 |
"github.com/golang/protobuf/ptypes/any" |
| 13 |
+ "github.com/moby/buildkit/errdefs" |
|
| 13 | 14 |
"github.com/moby/buildkit/util/bklog" |
| 14 | 15 |
"github.com/moby/buildkit/util/stack" |
| 15 | 16 |
spb "google.golang.org/genproto/googleapis/rpc/status" |
| ... | ... |
@@ -94,6 +95,13 @@ func withDetails(ctx context.Context, s *status.Status, details ...proto.Message |
| 94 | 94 |
} |
| 95 | 95 |
|
| 96 | 96 |
func Code(err error) codes.Code {
|
| 97 |
+ if errdefs.IsInternal(err) {
|
|
| 98 |
+ if errdefs.IsResourceExhausted(err) {
|
|
| 99 |
+ return codes.ResourceExhausted |
|
| 100 |
+ } |
|
| 101 |
+ return codes.Internal |
|
| 102 |
+ } |
|
| 103 |
+ |
|
| 97 | 104 |
if se, ok := err.(interface {
|
| 98 | 105 |
Code() codes.Code |
| 99 | 106 |
}); ok {
|
| ... | ... |
@@ -64,11 +64,7 @@ func retryError(err error) bool {
|
| 64 | 64 |
return true |
| 65 | 65 |
} |
| 66 | 66 |
// catches TLS timeout or other network-related temporary errors |
| 67 |
- if ne, ok := errors.Cause(err).(net.Error); ok && ne.Temporary() { //nolint:staticcheck // ignoring "SA1019: Temporary is deprecated", continue to propagate net.Error through the "temporary" status
|
|
| 68 |
- return true |
|
| 69 |
- } |
|
| 70 |
- // https://github.com/containerd/containerd/pull/4724 |
|
| 71 |
- if errors.Cause(err).Error() == "no response" {
|
|
| 67 |
+ if ne := net.Error(nil); errors.As(err, &ne) && ne.Temporary() { // ignoring "SA1019: Temporary is deprecated", continue to propagate net.Error through the "temporary" status
|
|
| 72 | 68 |
return true |
| 73 | 69 |
} |
| 74 | 70 |
|
| 75 | 71 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,67 @@ |
| 0 |
+package stack |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "slices" |
|
| 4 |
+) |
|
| 5 |
+ |
|
| 6 |
+func compressStacks(st []*Stack) []*Stack {
|
|
| 7 |
+ if len(st) == 0 {
|
|
| 8 |
+ return nil |
|
| 9 |
+ } |
|
| 10 |
+ |
|
| 11 |
+ slices.SortFunc(st, func(a, b *Stack) int {
|
|
| 12 |
+ return len(b.Frames) - len(a.Frames) |
|
| 13 |
+ }) |
|
| 14 |
+ |
|
| 15 |
+ out := []*Stack{st[0]}
|
|
| 16 |
+ |
|
| 17 |
+loop0: |
|
| 18 |
+ for _, st := range st[1:] {
|
|
| 19 |
+ maxIdx := -1 |
|
| 20 |
+ for _, prev := range out {
|
|
| 21 |
+ idx := subFrames(st.Frames, prev.Frames) |
|
| 22 |
+ if idx == -1 {
|
|
| 23 |
+ continue |
|
| 24 |
+ } |
|
| 25 |
+ // full match, potentially skip all |
|
| 26 |
+ if idx == len(st.Frames)-1 {
|
|
| 27 |
+ if st.Pid == prev.Pid && st.Version == prev.Version && slices.Compare(st.Cmdline, st.Cmdline) == 0 {
|
|
| 28 |
+ continue loop0 |
|
| 29 |
+ } |
|
| 30 |
+ } |
|
| 31 |
+ if idx > maxIdx {
|
|
| 32 |
+ maxIdx = idx |
|
| 33 |
+ } |
|
| 34 |
+ } |
|
| 35 |
+ |
|
| 36 |
+ if maxIdx > 0 {
|
|
| 37 |
+ st.Frames = st.Frames[:len(st.Frames)-maxIdx] |
|
| 38 |
+ } |
|
| 39 |
+ out = append(out, st) |
|
| 40 |
+ } |
|
| 41 |
+ |
|
| 42 |
+ return out |
|
| 43 |
+} |
|
| 44 |
+ |
|
| 45 |
+func subFrames(a, b []*Frame) int {
|
|
| 46 |
+ idx := -1 |
|
| 47 |
+ i := len(a) - 1 |
|
| 48 |
+ j := len(b) - 1 |
|
| 49 |
+ for i >= 0 {
|
|
| 50 |
+ if j < 0 {
|
|
| 51 |
+ break |
|
| 52 |
+ } |
|
| 53 |
+ if a[i].Equal(b[j]) {
|
|
| 54 |
+ idx++ |
|
| 55 |
+ i-- |
|
| 56 |
+ j-- |
|
| 57 |
+ } else {
|
|
| 58 |
+ break |
|
| 59 |
+ } |
|
| 60 |
+ } |
|
| 61 |
+ return idx |
|
| 62 |
+} |
|
| 63 |
+ |
|
| 64 |
+func (a *Frame) Equal(b *Frame) bool {
|
|
| 65 |
+ return a.File == b.File && a.Line == b.Line && a.Name == b.Name |
|
| 66 |
+} |
| 50 | 54 |
deleted file mode 100644 |
| ... | ... |
@@ -1,201 +0,0 @@ |
| 1 |
- Apache License |
|
| 2 |
- Version 2.0, January 2004 |
|
| 3 |
- http://www.apache.org/licenses/ |
|
| 4 |
- |
|
| 5 |
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
|
| 6 |
- |
|
| 7 |
- 1. Definitions. |
|
| 8 |
- |
|
| 9 |
- "License" shall mean the terms and conditions for use, reproduction, |
|
| 10 |
- and distribution as defined by Sections 1 through 9 of this document. |
|
| 11 |
- |
|
| 12 |
- "Licensor" shall mean the copyright owner or entity authorized by |
|
| 13 |
- the copyright owner that is granting the License. |
|
| 14 |
- |
|
| 15 |
- "Legal Entity" shall mean the union of the acting entity and all |
|
| 16 |
- other entities that control, are controlled by, or are under common |
|
| 17 |
- control with that entity. For the purposes of this definition, |
|
| 18 |
- "control" means (i) the power, direct or indirect, to cause the |
|
| 19 |
- direction or management of such entity, whether by contract or |
|
| 20 |
- otherwise, or (ii) ownership of fifty percent (50%) or more of the |
|
| 21 |
- outstanding shares, or (iii) beneficial ownership of such entity. |
|
| 22 |
- |
|
| 23 |
- "You" (or "Your") shall mean an individual or Legal Entity |
|
| 24 |
- exercising permissions granted by this License. |
|
| 25 |
- |
|
| 26 |
- "Source" form shall mean the preferred form for making modifications, |
|
| 27 |
- including but not limited to software source code, documentation |
|
| 28 |
- source, and configuration files. |
|
| 29 |
- |
|
| 30 |
- "Object" form shall mean any form resulting from mechanical |
|
| 31 |
- transformation or translation of a Source form, including but |
|
| 32 |
- not limited to compiled object code, generated documentation, |
|
| 33 |
- and conversions to other media types. |
|
| 34 |
- |
|
| 35 |
- "Work" shall mean the work of authorship, whether in Source or |
|
| 36 |
- Object form, made available under the License, as indicated by a |
|
| 37 |
- copyright notice that is included in or attached to the work |
|
| 38 |
- (an example is provided in the Appendix below). |
|
| 39 |
- |
|
| 40 |
- "Derivative Works" shall mean any work, whether in Source or Object |
|
| 41 |
- form, that is based on (or derived from) the Work and for which the |
|
| 42 |
- editorial revisions, annotations, elaborations, or other modifications |
|
| 43 |
- represent, as a whole, an original work of authorship. For the purposes |
|
| 44 |
- of this License, Derivative Works shall not include works that remain |
|
| 45 |
- separable from, or merely link (or bind by name) to the interfaces of, |
|
| 46 |
- the Work and Derivative Works thereof. |
|
| 47 |
- |
|
| 48 |
- "Contribution" shall mean any work of authorship, including |
|
| 49 |
- the original version of the Work and any modifications or additions |
|
| 50 |
- to that Work or Derivative Works thereof, that is intentionally |
|
| 51 |
- submitted to Licensor for inclusion in the Work by the copyright owner |
|
| 52 |
- or by an individual or Legal Entity authorized to submit on behalf of |
|
| 53 |
- the copyright owner. For the purposes of this definition, "submitted" |
|
| 54 |
- means any form of electronic, verbal, or written communication sent |
|
| 55 |
- to the Licensor or its representatives, including but not limited to |
|
| 56 |
- communication on electronic mailing lists, source code control systems, |
|
| 57 |
- and issue tracking systems that are managed by, or on behalf of, the |
|
| 58 |
- Licensor for the purpose of discussing and improving the Work, but |
|
| 59 |
- excluding communication that is conspicuously marked or otherwise |
|
| 60 |
- designated in writing by the copyright owner as "Not a Contribution." |
|
| 61 |
- |
|
| 62 |
- "Contributor" shall mean Licensor and any individual or Legal Entity |
|
| 63 |
- on behalf of whom a Contribution has been received by Licensor and |
|
| 64 |
- subsequently incorporated within the Work. |
|
| 65 |
- |
|
| 66 |
- 2. Grant of Copyright License. Subject to the terms and conditions of |
|
| 67 |
- this License, each Contributor hereby grants to You a perpetual, |
|
| 68 |
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|
| 69 |
- copyright license to reproduce, prepare Derivative Works of, |
|
| 70 |
- publicly display, publicly perform, sublicense, and distribute the |
|
| 71 |
- Work and such Derivative Works in Source or Object form. |
|
| 72 |
- |
|
| 73 |
- 3. Grant of Patent License. Subject to the terms and conditions of |
|
| 74 |
- this License, each Contributor hereby grants to You a perpetual, |
|
| 75 |
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|
| 76 |
- (except as stated in this section) patent license to make, have made, |
|
| 77 |
- use, offer to sell, sell, import, and otherwise transfer the Work, |
|
| 78 |
- where such license applies only to those patent claims licensable |
|
| 79 |
- by such Contributor that are necessarily infringed by their |
|
| 80 |
- Contribution(s) alone or by combination of their Contribution(s) |
|
| 81 |
- with the Work to which such Contribution(s) was submitted. If You |
|
| 82 |
- institute patent litigation against any entity (including a |
|
| 83 |
- cross-claim or counterclaim in a lawsuit) alleging that the Work |
|
| 84 |
- or a Contribution incorporated within the Work constitutes direct |
|
| 85 |
- or contributory patent infringement, then any patent licenses |
|
| 86 |
- granted to You under this License for that Work shall terminate |
|
| 87 |
- as of the date such litigation is filed. |
|
| 88 |
- |
|
| 89 |
- 4. Redistribution. You may reproduce and distribute copies of the |
|
| 90 |
- Work or Derivative Works thereof in any medium, with or without |
|
| 91 |
- modifications, and in Source or Object form, provided that You |
|
| 92 |
- meet the following conditions: |
|
| 93 |
- |
|
| 94 |
- (a) You must give any other recipients of the Work or |
|
| 95 |
- Derivative Works a copy of this License; and |
|
| 96 |
- |
|
| 97 |
- (b) You must cause any modified files to carry prominent notices |
|
| 98 |
- stating that You changed the files; and |
|
| 99 |
- |
|
| 100 |
- (c) You must retain, in the Source form of any Derivative Works |
|
| 101 |
- that You distribute, all copyright, patent, trademark, and |
|
| 102 |
- attribution notices from the Source form of the Work, |
|
| 103 |
- excluding those notices that do not pertain to any part of |
|
| 104 |
- the Derivative Works; and |
|
| 105 |
- |
|
| 106 |
- (d) If the Work includes a "NOTICE" text file as part of its |
|
| 107 |
- distribution, then any Derivative Works that You distribute must |
|
| 108 |
- include a readable copy of the attribution notices contained |
|
| 109 |
- within such NOTICE file, excluding those notices that do not |
|
| 110 |
- pertain to any part of the Derivative Works, in at least one |
|
| 111 |
- of the following places: within a NOTICE text file distributed |
|
| 112 |
- as part of the Derivative Works; within the Source form or |
|
| 113 |
- documentation, if provided along with the Derivative Works; or, |
|
| 114 |
- within a display generated by the Derivative Works, if and |
|
| 115 |
- wherever such third-party notices normally appear. The contents |
|
| 116 |
- of the NOTICE file are for informational purposes only and |
|
| 117 |
- do not modify the License. You may add Your own attribution |
|
| 118 |
- notices within Derivative Works that You distribute, alongside |
|
| 119 |
- or as an addendum to the NOTICE text from the Work, provided |
|
| 120 |
- that such additional attribution notices cannot be construed |
|
| 121 |
- as modifying the License. |
|
| 122 |
- |
|
| 123 |
- You may add Your own copyright statement to Your modifications and |
|
| 124 |
- may provide additional or different license terms and conditions |
|
| 125 |
- for use, reproduction, or distribution of Your modifications, or |
|
| 126 |
- for any such Derivative Works as a whole, provided Your use, |
|
| 127 |
- reproduction, and distribution of the Work otherwise complies with |
|
| 128 |
- the conditions stated in this License. |
|
| 129 |
- |
|
| 130 |
- 5. Submission of Contributions. Unless You explicitly state otherwise, |
|
| 131 |
- any Contribution intentionally submitted for inclusion in the Work |
|
| 132 |
- by You to the Licensor shall be under the terms and conditions of |
|
| 133 |
- this License, without any additional terms or conditions. |
|
| 134 |
- Notwithstanding the above, nothing herein shall supersede or modify |
|
| 135 |
- the terms of any separate license agreement you may have executed |
|
| 136 |
- with Licensor regarding such Contributions. |
|
| 137 |
- |
|
| 138 |
- 6. Trademarks. This License does not grant permission to use the trade |
|
| 139 |
- names, trademarks, service marks, or product names of the Licensor, |
|
| 140 |
- except as required for reasonable and customary use in describing the |
|
| 141 |
- origin of the Work and reproducing the content of the NOTICE file. |
|
| 142 |
- |
|
| 143 |
- 7. Disclaimer of Warranty. Unless required by applicable law or |
|
| 144 |
- agreed to in writing, Licensor provides the Work (and each |
|
| 145 |
- Contributor provides its Contributions) on an "AS IS" BASIS, |
|
| 146 |
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|
| 147 |
- implied, including, without limitation, any warranties or conditions |
|
| 148 |
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
|
| 149 |
- PARTICULAR PURPOSE. You are solely responsible for determining the |
|
| 150 |
- appropriateness of using or redistributing the Work and assume any |
|
| 151 |
- risks associated with Your exercise of permissions under this License. |
|
| 152 |
- |
|
| 153 |
- 8. Limitation of Liability. In no event and under no legal theory, |
|
| 154 |
- whether in tort (including negligence), contract, or otherwise, |
|
| 155 |
- unless required by applicable law (such as deliberate and grossly |
|
| 156 |
- negligent acts) or agreed to in writing, shall any Contributor be |
|
| 157 |
- liable to You for damages, including any direct, indirect, special, |
|
| 158 |
- incidental, or consequential damages of any character arising as a |
|
| 159 |
- result of this License or out of the use or inability to use the |
|
| 160 |
- Work (including but not limited to damages for loss of goodwill, |
|
| 161 |
- work stoppage, computer failure or malfunction, or any and all |
|
| 162 |
- other commercial damages or losses), even if such Contributor |
|
| 163 |
- has been advised of the possibility of such damages. |
|
| 164 |
- |
|
| 165 |
- 9. Accepting Warranty or Additional Liability. While redistributing |
|
| 166 |
- the Work or Derivative Works thereof, You may choose to offer, |
|
| 167 |
- and charge a fee for, acceptance of support, warranty, indemnity, |
|
| 168 |
- or other liability obligations and/or rights consistent with this |
|
| 169 |
- License. However, in accepting such obligations, You may act only |
|
| 170 |
- on Your own behalf and on Your sole responsibility, not on behalf |
|
| 171 |
- of any other Contributor, and only if You agree to indemnify, |
|
| 172 |
- defend, and hold each Contributor harmless for any liability |
|
| 173 |
- incurred by, or claims asserted against, such Contributor by reason |
|
| 174 |
- of your accepting any such warranty or additional liability. |
|
| 175 |
- |
|
| 176 |
- END OF TERMS AND CONDITIONS |
|
| 177 |
- |
|
| 178 |
- APPENDIX: How to apply the Apache License to your work. |
|
| 179 |
- |
|
| 180 |
- To apply the Apache License to your work, attach the following |
|
| 181 |
- boilerplate notice, with the fields enclosed by brackets "[]" |
|
| 182 |
- replaced with your own identifying information. (Don't include |
|
| 183 |
- the brackets!) The text should be enclosed in the appropriate |
|
| 184 |
- comment syntax for the file format. We also recommend that a |
|
| 185 |
- file or class name and description of purpose be included on the |
|
| 186 |
- same "printed page" as the copyright notice for easier |
|
| 187 |
- identification within third-party archives. |
|
| 188 |
- |
|
| 189 |
- Copyright [yyyy] [name of copyright owner] |
|
| 190 |
- |
|
| 191 |
- Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 192 |
- you may not use this file except in compliance with the License. |
|
| 193 |
- You may obtain a copy of the License at |
|
| 194 |
- |
|
| 195 |
- http://www.apache.org/licenses/LICENSE-2.0 |
|
| 196 |
- |
|
| 197 |
- Unless required by applicable law or agreed to in writing, software |
|
| 198 |
- distributed under the License is distributed on an "AS IS" BASIS, |
|
| 199 |
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 200 |
- See the License for the specific language governing permissions and |
|
| 201 |
- limitations under the License. |
| 202 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,20 +0,0 @@ |
| 1 |
-// Copyright The OpenTelemetry Authors |
|
| 2 |
-// |
|
| 3 |
-// Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 4 |
-// you may not use this file except in compliance with the License. |
|
| 5 |
-// You may obtain a copy of the License at |
|
| 6 |
-// |
|
| 7 |
-// http://www.apache.org/licenses/LICENSE-2.0 |
|
| 8 |
-// |
|
| 9 |
-// Unless required by applicable law or agreed to in writing, software |
|
| 10 |
-// distributed under the License is distributed on an "AS IS" BASIS, |
|
| 11 |
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 12 |
-// See the License for the specific language governing permissions and |
|
| 13 |
-// limitations under the License. |
|
| 14 |
- |
|
| 15 |
-// Package otlpmetric provides an OpenTelemetry metric Exporter that can be |
|
| 16 |
-// used with PeriodicReader. It transforms metricdata into OTLP and transmits |
|
| 17 |
-// the transformed data to OTLP receivers. The Exporter is configurable to use |
|
| 18 |
-// different Clients, each using a distinct transport protocol to communicate |
|
| 19 |
-// to an OTLP receiving endpoint. |
|
| 20 |
-package otlpmetric // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric" |
| ... | ... |
@@ -61,7 +61,11 @@ func newClient(ctx context.Context, cfg oconf.Config) (*client, error) {
|
| 61 | 61 |
if c.conn == nil {
|
| 62 | 62 |
// If the caller did not provide a ClientConn when the client was |
| 63 | 63 |
// created, create one using the configuration they did provide. |
| 64 |
- conn, err := grpc.DialContext(ctx, cfg.Metrics.Endpoint, cfg.DialOptions...) |
|
| 64 |
+ userAgent := "OTel Go OTLP over gRPC metrics exporter/" + Version() |
|
| 65 |
+ dialOpts := []grpc.DialOption{grpc.WithUserAgent(userAgent)}
|
|
| 66 |
+ dialOpts = append(dialOpts, cfg.DialOptions...) |
|
| 67 |
+ |
|
| 68 |
+ conn, err := grpc.DialContext(ctx, cfg.Metrics.Endpoint, dialOpts...) |
|
| 65 | 69 |
if err != nil {
|
| 66 | 70 |
return nil, err |
| 67 | 71 |
} |
| ... | ... |
@@ -172,28 +176,36 @@ func (c *client) exportContext(parent context.Context) (context.Context, context |
| 172 | 172 |
// duration to wait for if an explicit throttle time is included in err. |
| 173 | 173 |
func retryable(err error) (bool, time.Duration) {
|
| 174 | 174 |
s := status.Convert(err) |
| 175 |
+ return retryableGRPCStatus(s) |
|
| 176 |
+} |
|
| 177 |
+ |
|
| 178 |
+func retryableGRPCStatus(s *status.Status) (bool, time.Duration) {
|
|
| 175 | 179 |
switch s.Code() {
|
| 176 | 180 |
case codes.Canceled, |
| 177 | 181 |
codes.DeadlineExceeded, |
| 178 |
- codes.ResourceExhausted, |
|
| 179 | 182 |
codes.Aborted, |
| 180 | 183 |
codes.OutOfRange, |
| 181 | 184 |
codes.Unavailable, |
| 182 | 185 |
codes.DataLoss: |
| 183 |
- return true, throttleDelay(s) |
|
| 186 |
+ // Additionally, handle RetryInfo. |
|
| 187 |
+ _, d := throttleDelay(s) |
|
| 188 |
+ return true, d |
|
| 189 |
+ case codes.ResourceExhausted: |
|
| 190 |
+ // Retry only if the server signals that the recovery from resource exhaustion is possible. |
|
| 191 |
+ return throttleDelay(s) |
|
| 184 | 192 |
} |
| 185 | 193 |
|
| 186 | 194 |
// Not a retry-able error. |
| 187 | 195 |
return false, 0 |
| 188 | 196 |
} |
| 189 | 197 |
|
| 190 |
-// throttleDelay returns a duration to wait for if an explicit throttle time |
|
| 191 |
-// is included in the response status. |
|
| 192 |
-func throttleDelay(s *status.Status) time.Duration {
|
|
| 198 |
+// throttleDelay returns if the status is RetryInfo |
|
| 199 |
+// and the duration to wait for if an explicit throttle time is included. |
|
| 200 |
+func throttleDelay(s *status.Status) (bool, time.Duration) {
|
|
| 193 | 201 |
for _, detail := range s.Details() {
|
| 194 | 202 |
if t, ok := detail.(*errdetails.RetryInfo); ok {
|
| 195 |
- return t.RetryDelay.AsDuration() |
|
| 203 |
+ return true, t.RetryDelay.AsDuration() |
|
| 196 | 204 |
} |
| 197 | 205 |
} |
| 198 |
- return 0 |
|
| 206 |
+ return false, 0 |
|
| 199 | 207 |
} |
| ... | ... |
@@ -109,13 +109,7 @@ func compressorToCompression(compressor string) oconf.Compression {
|
| 109 | 109 |
} |
| 110 | 110 |
|
| 111 | 111 |
// WithCompressor sets the compressor the gRPC client uses. |
| 112 |
-// |
|
| 113 |
-// It is the responsibility of the caller to ensure that the compressor set |
|
| 114 |
-// has been registered with google.golang.org/grpc/encoding (see |
|
| 115 |
-// encoding.RegisterCompressor for more information). For example, to register |
|
| 116 |
-// the gzip compressor import the package: |
|
| 117 |
-// |
|
| 118 |
-// import _ "google.golang.org/grpc/encoding/gzip" |
|
| 112 |
+// Supported compressor values: "gzip". |
|
| 119 | 113 |
// |
| 120 | 114 |
// If the OTEL_EXPORTER_OTLP_COMPRESSION or |
| 121 | 115 |
// OTEL_EXPORTER_OTLP_METRICS_COMPRESSION environment variable is set, and |
| ... | ... |
@@ -12,6 +12,85 @@ |
| 12 | 12 |
// See the License for the specific language governing permissions and |
| 13 | 13 |
// limitations under the License. |
| 14 | 14 |
|
| 15 |
-// Package otlpmetricgrpc provides an otlpmetric.Exporter that communicates |
|
| 16 |
-// with an OTLP receiving endpoint using gRPC. |
|
| 15 |
+/* |
|
| 16 |
+Package otlpmetricgrpc provides an OTLP metrics exporter using gRPC. |
|
| 17 |
+By default the telemetry is sent to https://localhost:4317. |
|
| 18 |
+ |
|
| 19 |
+Exporter should be created using [New] and used with a [metric.PeriodicReader]. |
|
| 20 |
+ |
|
| 21 |
+The environment variables described below can be used for configuration. |
|
| 22 |
+ |
|
| 23 |
+OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT (default: "https://localhost:4317") - |
|
| 24 |
+target to which the exporter sends telemetry. |
|
| 25 |
+The target syntax is defined in https://github.com/grpc/grpc/blob/master/doc/naming.md. |
|
| 26 |
+The value must contain a host. |
|
| 27 |
+The value may additionally a port, a scheme, and a path. |
|
| 28 |
+The value accepts "http" and "https" scheme. |
|
| 29 |
+The value should not contain a query string or fragment. |
|
| 30 |
+OTEL_EXPORTER_OTLP_METRICS_ENDPOINT takes precedence over OTEL_EXPORTER_OTLP_ENDPOINT. |
|
| 31 |
+The configuration can be overridden by [WithEndpoint], [WithInsecure], [WithGRPCConn] options. |
|
| 32 |
+ |
|
| 33 |
+OTEL_EXPORTER_OTLP_INSECURE, OTEL_EXPORTER_OTLP_METRICS_INSECURE (default: "false") - |
|
| 34 |
+setting "true" disables client transport security for the exporter's gRPC connection. |
|
| 35 |
+You can use this only when an endpoint is provided without the http or https scheme. |
|
| 36 |
+OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT setting overrides |
|
| 37 |
+the scheme defined via OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT. |
|
| 38 |
+OTEL_EXPORTER_OTLP_METRICS_INSECURE takes precedence over OTEL_EXPORTER_OTLP_INSECURE. |
|
| 39 |
+The configuration can be overridden by [WithInsecure], [WithGRPCConn] options. |
|
| 40 |
+ |
|
| 41 |
+OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_METRICS_HEADERS (default: none) - |
|
| 42 |
+key-value pairs used as gRPC metadata associated with gRPC requests. |
|
| 43 |
+The value is expected to be represented in a format matching to the [W3C Baggage HTTP Header Content Format], |
|
| 44 |
+except that additional semi-colon delimited metadata is not supported. |
|
| 45 |
+Example value: "key1=value1,key2=value2". |
|
| 46 |
+OTEL_EXPORTER_OTLP_METRICS_HEADERS takes precedence over OTEL_EXPORTER_OTLP_HEADERS. |
|
| 47 |
+The configuration can be overridden by [WithHeaders] option. |
|
| 48 |
+ |
|
| 49 |
+OTEL_EXPORTER_OTLP_TIMEOUT, OTEL_EXPORTER_OTLP_METRICS_TIMEOUT (default: "10000") - |
|
| 50 |
+maximum time in milliseconds the OTLP exporter waits for each batch export. |
|
| 51 |
+OTEL_EXPORTER_OTLP_METRICS_TIMEOUT takes precedence over OTEL_EXPORTER_OTLP_TIMEOUT. |
|
| 52 |
+The configuration can be overridden by [WithTimeout] option. |
|
| 53 |
+ |
|
| 54 |
+OTEL_EXPORTER_OTLP_COMPRESSION, OTEL_EXPORTER_OTLP_METRICS_COMPRESSION (default: none) - |
|
| 55 |
+the gRPC compressor the exporter uses. |
|
| 56 |
+Supported value: "gzip". |
|
| 57 |
+OTEL_EXPORTER_OTLP_METRICS_COMPRESSION takes precedence over OTEL_EXPORTER_OTLP_COMPRESSION. |
|
| 58 |
+The configuration can be overridden by [WithCompressor], [WithGRPCConn] options. |
|
| 59 |
+ |
|
| 60 |
+OTEL_EXPORTER_OTLP_CERTIFICATE, OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE (default: none) - |
|
| 61 |
+the filepath to the trusted certificate to use when verifying a server's TLS credentials. |
|
| 62 |
+OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE takes precedence over OTEL_EXPORTER_OTLP_CERTIFICATE. |
|
| 63 |
+The configuration can be overridden by [WithTLSCredentials], [WithGRPCConn] options. |
|
| 64 |
+ |
|
| 65 |
+OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE, OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE (default: none) - |
|
| 66 |
+the filepath to the client certificate/chain trust for clients private key to use in mTLS communication in PEM format. |
|
| 67 |
+OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE takes precedence over OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE. |
|
| 68 |
+The configuration can be overridden by [WithTLSCredentials], [WithGRPCConn] options. |
|
| 69 |
+ |
|
| 70 |
+OTEL_EXPORTER_OTLP_CLIENT_KEY, OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY (default: none) - |
|
| 71 |
+the filepath to the clients private key to use in mTLS communication in PEM format. |
|
| 72 |
+OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY takes precedence over OTEL_EXPORTER_OTLP_CLIENT_KEY. |
|
| 73 |
+The configuration can be overridden by [WithTLSCredentials], [WithGRPCConn] option. |
|
| 74 |
+ |
|
| 75 |
+OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE (default: "cumulative") - |
|
| 76 |
+aggregation temporality to use on the basis of instrument kind. Supported values: |
|
| 77 |
+ - "cumulative" - Cumulative aggregation temporality for all instrument kinds, |
|
| 78 |
+ - "delta" - Delta aggregation temporality for Counter, Asynchronous Counter and Histogram instrument kinds; |
|
| 79 |
+ Cumulative aggregation for UpDownCounter and Asynchronous UpDownCounter instrument kinds, |
|
| 80 |
+ - "lowmemory" - Delta aggregation temporality for Synchronous Counter and Histogram instrument kinds; |
|
| 81 |
+ Cumulative aggregation temporality for Synchronous UpDownCounter, Asynchronous Counter, and Asynchronous UpDownCounter instrument kinds. |
|
| 82 |
+ |
|
| 83 |
+The configuration can be overridden by [WithTemporalitySelector] option. |
|
| 84 |
+ |
|
| 85 |
+OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION (default: "explicit_bucket_histogram") - |
|
| 86 |
+default aggregation to use for histogram instruments. Supported values: |
|
| 87 |
+ - "explicit_bucket_histogram" - [Explicit Bucket Histogram Aggregation], |
|
| 88 |
+ - "base2_exponential_bucket_histogram" - [Base2 Exponential Bucket Histogram Aggregation]. |
|
| 89 |
+ |
|
| 90 |
+The configuration can be overridden by [WithAggregationSelector] option. |
|
| 91 |
+ |
|
| 92 |
+[W3C Baggage HTTP Header Content Format]: https://www.w3.org/TR/baggage/#header-content |
|
| 93 |
+[Explicit Bucket Histogram Aggregation]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.26.0/specification/metrics/sdk.md#explicit-bucket-histogram-aggregation |
|
| 94 |
+[Base2 Exponential Bucket Histogram Aggregation]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.26.0/specification/metrics/sdk.md#base2-exponential-bucket-histogram-aggregation |
|
| 95 |
+*/ |
|
| 17 | 96 |
package otlpmetricgrpc // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" |
| ... | ... |
@@ -174,13 +174,13 @@ func stringToHeader(value string) map[string]string {
|
| 174 | 174 |
global.Error(errors.New("missing '="), "parse headers", "input", header)
|
| 175 | 175 |
continue |
| 176 | 176 |
} |
| 177 |
- name, err := url.QueryUnescape(n) |
|
| 177 |
+ name, err := url.PathUnescape(n) |
|
| 178 | 178 |
if err != nil {
|
| 179 | 179 |
global.Error(err, "escape header key", "key", n) |
| 180 | 180 |
continue |
| 181 | 181 |
} |
| 182 | 182 |
trimmedName := strings.TrimSpace(name) |
| 183 |
- value, err := url.QueryUnescape(v) |
|
| 183 |
+ value, err := url.PathUnescape(v) |
|
| 184 | 184 |
if err != nil {
|
| 185 | 185 |
global.Error(err, "escape header value", "value", v) |
| 186 | 186 |
continue |
| ... | ... |
@@ -30,7 +30,6 @@ import ( |
| 30 | 30 |
"google.golang.org/grpc/credentials/insecure" |
| 31 | 31 |
"google.golang.org/grpc/encoding/gzip" |
| 32 | 32 |
|
| 33 |
- "go.opentelemetry.io/otel/exporters/otlp/otlpmetric" |
|
| 34 | 33 |
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry" |
| 35 | 34 |
"go.opentelemetry.io/otel/sdk/metric" |
| 36 | 35 |
) |
| ... | ... |
@@ -122,7 +121,6 @@ func cleanPath(urlPath string, defaultPath string) string {
|
| 122 | 122 |
// NewGRPCConfig returns a new Config with all settings applied from opts and |
| 123 | 123 |
// any unset setting using the default gRPC config values. |
| 124 | 124 |
func NewGRPCConfig(opts ...GRPCOption) Config {
|
| 125 |
- userAgent := "OTel OTLP Exporter Go/" + otlpmetric.Version() |
|
| 126 | 125 |
cfg := Config{
|
| 127 | 126 |
Metrics: SignalConfig{
|
| 128 | 127 |
Endpoint: fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorGRPCPort),
|
| ... | ... |
@@ -134,7 +132,6 @@ func NewGRPCConfig(opts ...GRPCOption) Config {
|
| 134 | 134 |
AggregationSelector: metric.DefaultAggregationSelector, |
| 135 | 135 |
}, |
| 136 | 136 |
RetryConfig: retry.DefaultConfig, |
| 137 |
- DialOptions: []grpc.DialOption{grpc.WithUserAgent(userAgent)},
|
|
| 138 | 137 |
} |
| 139 | 138 |
cfg = ApplyGRPCEnvConfigs(cfg) |
| 140 | 139 |
for _, opt := range opts {
|
| ... | ... |
@@ -158,9 +155,6 @@ func NewGRPCConfig(opts ...GRPCOption) Config {
|
| 158 | 158 |
if cfg.Metrics.Compression == GzipCompression {
|
| 159 | 159 |
cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name))) |
| 160 | 160 |
} |
| 161 |
- if len(cfg.DialOptions) != 0 {
|
|
| 162 |
- cfg.DialOptions = append(cfg.DialOptions, cfg.DialOptions...) |
|
| 163 |
- } |
|
| 164 | 161 |
if cfg.ReconnectionPeriod != 0 {
|
| 165 | 162 |
p := grpc.ConnectParams{
|
| 166 | 163 |
Backoff: backoff.DefaultConfig, |
| 167 | 164 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,20 @@ |
| 0 |
+// Copyright The OpenTelemetry Authors |
|
| 1 |
+// |
|
| 2 |
+// Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 3 |
+// you may not use this file except in compliance with the License. |
|
| 4 |
+// You may obtain a copy of the License at |
|
| 5 |
+// |
|
| 6 |
+// http://www.apache.org/licenses/LICENSE-2.0 |
|
| 7 |
+// |
|
| 8 |
+// Unless required by applicable law or agreed to in writing, software |
|
| 9 |
+// distributed under the License is distributed on an "AS IS" BASIS, |
|
| 10 |
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 11 |
+// See the License for the specific language governing permissions and |
|
| 12 |
+// limitations under the License. |
|
| 13 |
+ |
|
| 14 |
+package otlpmetricgrpc // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" |
|
| 15 |
+ |
|
| 16 |
+// Version is the current release version of the OpenTelemetry OTLP over gRPC metrics exporter in use. |
|
| 17 |
+func Version() string {
|
|
| 18 |
+ return "0.44.0" |
|
| 19 |
+} |
| ... | ... |
@@ -18,6 +18,7 @@ import ( |
| 18 | 18 |
"bytes" |
| 19 | 19 |
"compress/gzip" |
| 20 | 20 |
"context" |
| 21 |
+ "errors" |
|
| 21 | 22 |
"fmt" |
| 22 | 23 |
"io" |
| 23 | 24 |
"net" |
| ... | ... |
@@ -30,7 +31,6 @@ import ( |
| 30 | 30 |
"google.golang.org/protobuf/proto" |
| 31 | 31 |
|
| 32 | 32 |
"go.opentelemetry.io/otel" |
| 33 |
- "go.opentelemetry.io/otel/exporters/otlp/otlpmetric" |
|
| 34 | 33 |
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal" |
| 35 | 34 |
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/oconf" |
| 36 | 35 |
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry" |
| ... | ... |
@@ -89,7 +89,7 @@ func newClient(cfg oconf.Config) (*client, error) {
|
| 89 | 89 |
return nil, err |
| 90 | 90 |
} |
| 91 | 91 |
|
| 92 |
- userAgent := "OTel OTLP Exporter Go/" + otlpmetric.Version() |
|
| 92 |
+ userAgent := "OTel Go OTLP over HTTP/protobuf metrics exporter/" + Version() |
|
| 93 | 93 |
req.Header.Set("User-Agent", userAgent)
|
| 94 | 94 |
|
| 95 | 95 |
if n := len(cfg.Metrics.Headers); n > 0 {
|
| ... | ... |
@@ -148,6 +148,10 @@ func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.Resou |
| 148 | 148 |
|
| 149 | 149 |
request.reset(iCtx) |
| 150 | 150 |
resp, err := c.httpClient.Do(request.Request) |
| 151 |
+ var urlErr *url.Error |
|
| 152 |
+ if errors.As(err, &urlErr) && urlErr.Temporary() {
|
|
| 153 |
+ return newResponseError(http.Header{})
|
|
| 154 |
+ } |
|
| 151 | 155 |
if err != nil {
|
| 152 | 156 |
return err |
| 153 | 157 |
} |
| ... | ... |
@@ -162,8 +166,11 @@ func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.Resou |
| 162 | 162 |
if _, err := io.Copy(&respData, resp.Body); err != nil {
|
| 163 | 163 |
return err |
| 164 | 164 |
} |
| 165 |
+ if respData.Len() == 0 {
|
|
| 166 |
+ return nil |
|
| 167 |
+ } |
|
| 165 | 168 |
|
| 166 |
- if respData.Len() != 0 {
|
|
| 169 |
+ if resp.Header.Get("Content-Type") == "application/x-protobuf" {
|
|
| 167 | 170 |
var respProto colmetricpb.ExportMetricsServiceResponse |
| 168 | 171 |
if err := proto.Unmarshal(respData.Bytes(), &respProto); err != nil {
|
| 169 | 172 |
return err |
| ... | ... |
@@ -179,7 +186,10 @@ func (c *client) UploadMetrics(ctx context.Context, protoMetrics *metricpb.Resou |
| 179 | 179 |
} |
| 180 | 180 |
} |
| 181 | 181 |
return nil |
| 182 |
- case sc == http.StatusTooManyRequests, sc == http.StatusServiceUnavailable: |
|
| 182 |
+ case sc == http.StatusTooManyRequests, |
|
| 183 |
+ sc == http.StatusBadGateway, |
|
| 184 |
+ sc == http.StatusServiceUnavailable, |
|
| 185 |
+ sc == http.StatusGatewayTimeout: |
|
| 183 | 186 |
// Retry-able failure. |
| 184 | 187 |
rErr = newResponseError(resp.Header) |
| 185 | 188 |
|
| ... | ... |
@@ -12,7 +12,82 @@ |
| 12 | 12 |
// See the License for the specific language governing permissions and |
| 13 | 13 |
// limitations under the License. |
| 14 | 14 |
|
| 15 |
-// Package otlpmetrichttp provides an otlpmetric.Exporter that communicates |
|
| 16 |
-// with an OTLP receiving endpoint using protobuf encoded metric data over |
|
| 17 |
-// HTTP. |
|
| 15 |
+/* |
|
| 16 |
+Package otlpmetrichttp provides an OTLP metrics exporter using HTTP with protobuf payloads. |
|
| 17 |
+By default the telemetry is sent to https://localhost:4318/v1/metrics. |
|
| 18 |
+ |
|
| 19 |
+Exporter should be created using [New] and used with a [metric.PeriodicReader]. |
|
| 20 |
+ |
|
| 21 |
+The environment variables described below can be used for configuration. |
|
| 22 |
+ |
|
| 23 |
+OTEL_EXPORTER_OTLP_ENDPOINT (default: "https://localhost:4318") - |
|
| 24 |
+target base URL ("/v1/metrics" is appended) to which the exporter sends telemetry.
|
|
| 25 |
+The value must contain a scheme ("http" or "https") and host.
|
|
| 26 |
+The value may additionally contain a port and a path. |
|
| 27 |
+The value should not contain a query string or fragment. |
|
| 28 |
+The configuration can be overridden by OTEL_EXPORTER_OTLP_METRICS_ENDPOINT |
|
| 29 |
+environment variable and by [WithEndpoint], [WithInsecure] options. |
|
| 30 |
+ |
|
| 31 |
+OTEL_EXPORTER_OTLP_METRICS_ENDPOINT (default: "https://localhost:4318/v1/metrics") - |
|
| 32 |
+target URL to which the exporter sends telemetry. |
|
| 33 |
+The value must contain a scheme ("http" or "https") and host.
|
|
| 34 |
+The value may additionally contain a port and a path. |
|
| 35 |
+The value should not contain a query string or fragment. |
|
| 36 |
+The configuration can be overridden by [WithEndpoint], [WitnInsecure], [WithURLPath] options. |
|
| 37 |
+ |
|
| 38 |
+OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_METRICS_HEADERS (default: none) - |
|
| 39 |
+key-value pairs used as headers associated with HTTP requests. |
|
| 40 |
+The value is expected to be represented in a format matching to the [W3C Baggage HTTP Header Content Format], |
|
| 41 |
+except that additional semi-colon delimited metadata is not supported. |
|
| 42 |
+Example value: "key1=value1,key2=value2". |
|
| 43 |
+OTEL_EXPORTER_OTLP_METRICS_HEADERS takes precedence over OTEL_EXPORTER_OTLP_HEADERS. |
|
| 44 |
+The configuration can be overridden by [WithHeaders] option. |
|
| 45 |
+ |
|
| 46 |
+OTEL_EXPORTER_OTLP_TIMEOUT, OTEL_EXPORTER_OTLP_METRICS_TIMEOUT (default: "10000") - |
|
| 47 |
+maximum time in milliseconds the OTLP exporter waits for each batch export. |
|
| 48 |
+OTEL_EXPORTER_OTLP_METRICS_TIMEOUT takes precedence over OTEL_EXPORTER_OTLP_TIMEOUT. |
|
| 49 |
+The configuration can be overridden by [WithTimeout] option. |
|
| 50 |
+ |
|
| 51 |
+OTEL_EXPORTER_OTLP_COMPRESSION, OTEL_EXPORTER_OTLP_METRICS_COMPRESSION (default: none) - |
|
| 52 |
+compression strategy the exporter uses to compress the HTTP body. |
|
| 53 |
+Supported values: "gzip". |
|
| 54 |
+OTEL_EXPORTER_OTLP_METRICS_COMPRESSION takes precedence over OTEL_EXPORTER_OTLP_COMPRESSION. |
|
| 55 |
+The configuration can be overridden by [WithCompression] option. |
|
| 56 |
+ |
|
| 57 |
+OTEL_EXPORTER_OTLP_CERTIFICATE, OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE (default: none) - |
|
| 58 |
+filepath to the trusted certificate to use when verifying a server's TLS credentials. |
|
| 59 |
+OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE takes precedence over OTEL_EXPORTER_OTLP_CERTIFICATE. |
|
| 60 |
+The configuration can be overridden by [WithTLSClientConfig] option. |
|
| 61 |
+ |
|
| 62 |
+OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE, OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE (default: none) - |
|
| 63 |
+filepath to the client certificate/chain trust for clients private key to use in mTLS communication in PEM format. |
|
| 64 |
+OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE takes precedence over OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE. |
|
| 65 |
+The configuration can be overridden by [WithTLSClientConfig] option. |
|
| 66 |
+ |
|
| 67 |
+OTEL_EXPORTER_OTLP_CLIENT_KEY, OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY (default: none) - |
|
| 68 |
+filepath to the clients private key to use in mTLS communication in PEM format. |
|
| 69 |
+OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY takes precedence over OTEL_EXPORTER_OTLP_CLIENT_KEY. |
|
| 70 |
+The configuration can be overridden by [WithTLSClientConfig] option. |
|
| 71 |
+ |
|
| 72 |
+OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE (default: "cumulative") - |
|
| 73 |
+aggregation temporality to use on the basis of instrument kind. Supported values: |
|
| 74 |
+ - "cumulative" - Cumulative aggregation temporality for all instrument kinds, |
|
| 75 |
+ - "delta" - Delta aggregation temporality for Counter, Asynchronous Counter and Histogram instrument kinds; |
|
| 76 |
+ Cumulative aggregation for UpDownCounter and Asynchronous UpDownCounter instrument kinds, |
|
| 77 |
+ - "lowmemory" - Delta aggregation temporality for Synchronous Counter and Histogram instrument kinds; |
|
| 78 |
+ Cumulative aggregation temporality for Synchronous UpDownCounter, Asynchronous Counter, and Asynchronous UpDownCounter instrument kinds. |
|
| 79 |
+ |
|
| 80 |
+The configuration can be overridden by [WithTemporalitySelector] option. |
|
| 81 |
+ |
|
| 82 |
+OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION (default: "explicit_bucket_histogram") - |
|
| 83 |
+default aggregation to use for histogram instruments. Supported values: |
|
| 84 |
+ - "explicit_bucket_histogram" - [Explicit Bucket Histogram Aggregation], |
|
| 85 |
+ - "base2_exponential_bucket_histogram" - [Base2 Exponential Bucket Histogram Aggregation]. |
|
| 86 |
+ |
|
| 87 |
+The configuration can be overridden by [WithAggregationSelector] option. |
|
| 88 |
+ |
|
| 89 |
+[W3C Baggage HTTP Header Content Format]: https://www.w3.org/TR/baggage/#header-content |
|
| 90 |
+[Explicit Bucket Histogram Aggregation]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.26.0/specification/metrics/sdk.md#explicit-bucket-histogram-aggregation |
|
| 91 |
+[Base2 Exponential Bucket Histogram Aggregation]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.26.0/specification/metrics/sdk.md#base2-exponential-bucket-histogram-aggregation |
|
| 92 |
+*/ |
|
| 18 | 93 |
package otlpmetrichttp // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" |
| ... | ... |
@@ -174,13 +174,13 @@ func stringToHeader(value string) map[string]string {
|
| 174 | 174 |
global.Error(errors.New("missing '="), "parse headers", "input", header)
|
| 175 | 175 |
continue |
| 176 | 176 |
} |
| 177 |
- name, err := url.QueryUnescape(n) |
|
| 177 |
+ name, err := url.PathUnescape(n) |
|
| 178 | 178 |
if err != nil {
|
| 179 | 179 |
global.Error(err, "escape header key", "key", n) |
| 180 | 180 |
continue |
| 181 | 181 |
} |
| 182 | 182 |
trimmedName := strings.TrimSpace(name) |
| 183 |
- value, err := url.QueryUnescape(v) |
|
| 183 |
+ value, err := url.PathUnescape(v) |
|
| 184 | 184 |
if err != nil {
|
| 185 | 185 |
global.Error(err, "escape header value", "value", v) |
| 186 | 186 |
continue |
| ... | ... |
@@ -30,7 +30,6 @@ import ( |
| 30 | 30 |
"google.golang.org/grpc/credentials/insecure" |
| 31 | 31 |
"google.golang.org/grpc/encoding/gzip" |
| 32 | 32 |
|
| 33 |
- "go.opentelemetry.io/otel/exporters/otlp/otlpmetric" |
|
| 34 | 33 |
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal/retry" |
| 35 | 34 |
"go.opentelemetry.io/otel/sdk/metric" |
| 36 | 35 |
) |
| ... | ... |
@@ -122,7 +121,6 @@ func cleanPath(urlPath string, defaultPath string) string {
|
| 122 | 122 |
// NewGRPCConfig returns a new Config with all settings applied from opts and |
| 123 | 123 |
// any unset setting using the default gRPC config values. |
| 124 | 124 |
func NewGRPCConfig(opts ...GRPCOption) Config {
|
| 125 |
- userAgent := "OTel OTLP Exporter Go/" + otlpmetric.Version() |
|
| 126 | 125 |
cfg := Config{
|
| 127 | 126 |
Metrics: SignalConfig{
|
| 128 | 127 |
Endpoint: fmt.Sprintf("%s:%d", DefaultCollectorHost, DefaultCollectorGRPCPort),
|
| ... | ... |
@@ -134,7 +132,6 @@ func NewGRPCConfig(opts ...GRPCOption) Config {
|
| 134 | 134 |
AggregationSelector: metric.DefaultAggregationSelector, |
| 135 | 135 |
}, |
| 136 | 136 |
RetryConfig: retry.DefaultConfig, |
| 137 |
- DialOptions: []grpc.DialOption{grpc.WithUserAgent(userAgent)},
|
|
| 138 | 137 |
} |
| 139 | 138 |
cfg = ApplyGRPCEnvConfigs(cfg) |
| 140 | 139 |
for _, opt := range opts {
|
| ... | ... |
@@ -158,9 +155,6 @@ func NewGRPCConfig(opts ...GRPCOption) Config {
|
| 158 | 158 |
if cfg.Metrics.Compression == GzipCompression {
|
| 159 | 159 |
cfg.DialOptions = append(cfg.DialOptions, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name))) |
| 160 | 160 |
} |
| 161 |
- if len(cfg.DialOptions) != 0 {
|
|
| 162 |
- cfg.DialOptions = append(cfg.DialOptions, cfg.DialOptions...) |
|
| 163 |
- } |
|
| 164 | 161 |
if cfg.ReconnectionPeriod != 0 {
|
| 165 | 162 |
p := grpc.ConnectParams{
|
| 166 | 163 |
Backoff: backoff.DefaultConfig, |
| 167 | 164 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,20 @@ |
| 0 |
+// Copyright The OpenTelemetry Authors |
|
| 1 |
+// |
|
| 2 |
+// Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 3 |
+// you may not use this file except in compliance with the License. |
|
| 4 |
+// You may obtain a copy of the License at |
|
| 5 |
+// |
|
| 6 |
+// http://www.apache.org/licenses/LICENSE-2.0 |
|
| 7 |
+// |
|
| 8 |
+// Unless required by applicable law or agreed to in writing, software |
|
| 9 |
+// distributed under the License is distributed on an "AS IS" BASIS, |
|
| 10 |
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 11 |
+// See the License for the specific language governing permissions and |
|
| 12 |
+// limitations under the License. |
|
| 13 |
+ |
|
| 14 |
+package otlpmetrichttp // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp" |
|
| 15 |
+ |
|
| 16 |
+// Version is the current release version of the OpenTelemetry OTLP over HTTP/protobuf metrics exporter in use. |
|
| 17 |
+func Version() string {
|
|
| 18 |
+ return "0.44.0" |
|
| 19 |
+} |
| 0 | 20 |
deleted file mode 100644 |
| ... | ... |
@@ -1,20 +0,0 @@ |
| 1 |
-// Copyright The OpenTelemetry Authors |
|
| 2 |
-// |
|
| 3 |
-// Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 4 |
-// you may not use this file except in compliance with the License. |
|
| 5 |
-// You may obtain a copy of the License at |
|
| 6 |
-// |
|
| 7 |
-// http://www.apache.org/licenses/LICENSE-2.0 |
|
| 8 |
-// |
|
| 9 |
-// Unless required by applicable law or agreed to in writing, software |
|
| 10 |
-// distributed under the License is distributed on an "AS IS" BASIS, |
|
| 11 |
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 12 |
-// See the License for the specific language governing permissions and |
|
| 13 |
-// limitations under the License. |
|
| 14 |
- |
|
| 15 |
-package otlpmetric // import "go.opentelemetry.io/otel/exporters/otlp/otlpmetric" |
|
| 16 |
- |
|
| 17 |
-// Version is the current release version of the OpenTelemetry OTLP metrics exporter in use. |
|
| 18 |
-func Version() string {
|
|
| 19 |
- return "0.42.0" |
|
| 20 |
-} |
| ... | ... |
@@ -304,7 +304,6 @@ github.com/containerd/containerd/pkg/transfer |
| 304 | 304 |
github.com/containerd/containerd/pkg/transfer/proxy |
| 305 | 305 |
github.com/containerd/containerd/pkg/transfer/streaming |
| 306 | 306 |
github.com/containerd/containerd/pkg/unpack |
| 307 |
-github.com/containerd/containerd/pkg/userns |
|
| 308 | 307 |
github.com/containerd/containerd/plugin |
| 309 | 308 |
github.com/containerd/containerd/protobuf |
| 310 | 309 |
github.com/containerd/containerd/protobuf/proto |
| ... | ... |
@@ -388,8 +387,8 @@ github.com/containerd/stargz-snapshotter/estargz/errorutil |
| 388 | 388 |
# github.com/containerd/ttrpc v1.2.5 |
| 389 | 389 |
## explicit; go 1.19 |
| 390 | 390 |
github.com/containerd/ttrpc |
| 391 |
-# github.com/containerd/typeurl/v2 v2.1.1 |
|
| 392 |
-## explicit; go 1.13 |
|
| 391 |
+# github.com/containerd/typeurl/v2 v2.2.0 |
|
| 392 |
+## explicit; go 1.21 |
|
| 393 | 393 |
github.com/containerd/typeurl/v2 |
| 394 | 394 |
# github.com/containernetworking/cni v1.2.2 |
| 395 | 395 |
## explicit; go 1.21 |
| ... | ... |
@@ -703,7 +702,7 @@ github.com/mitchellh/hashstructure/v2 |
| 703 | 703 |
# github.com/mitchellh/reflectwalk v1.0.2 |
| 704 | 704 |
## explicit |
| 705 | 705 |
github.com/mitchellh/reflectwalk |
| 706 |
-# github.com/moby/buildkit v0.15.2 |
|
| 706 |
+# github.com/moby/buildkit v0.16.0-rc1 |
|
| 707 | 707 |
## explicit; go 1.21.0 |
| 708 | 708 |
github.com/moby/buildkit/api/services/control |
| 709 | 709 |
github.com/moby/buildkit/api/types |
| ... | ... |
@@ -728,6 +727,7 @@ github.com/moby/buildkit/client/ociindex |
| 728 | 728 |
github.com/moby/buildkit/cmd/buildkitd/config |
| 729 | 729 |
github.com/moby/buildkit/control |
| 730 | 730 |
github.com/moby/buildkit/control/gateway |
| 731 |
+github.com/moby/buildkit/errdefs |
|
| 731 | 732 |
github.com/moby/buildkit/executor |
| 732 | 733 |
github.com/moby/buildkit/executor/containerdexecutor |
| 733 | 734 |
github.com/moby/buildkit/executor/oci |
| ... | ... |
@@ -812,6 +812,8 @@ github.com/moby/buildkit/util/cond |
| 812 | 812 |
github.com/moby/buildkit/util/contentutil |
| 813 | 813 |
github.com/moby/buildkit/util/converter |
| 814 | 814 |
github.com/moby/buildkit/util/converter/tarconverter |
| 815 |
+github.com/moby/buildkit/util/db |
|
| 816 |
+github.com/moby/buildkit/util/db/boltutil |
|
| 815 | 817 |
github.com/moby/buildkit/util/entitlements |
| 816 | 818 |
github.com/moby/buildkit/util/entitlements/security |
| 817 | 819 |
github.com/moby/buildkit/util/estargz |
| ... | ... |
@@ -1212,10 +1214,7 @@ go.opentelemetry.io/otel/internal/global |
| 1212 | 1212 |
go.opentelemetry.io/otel/propagation |
| 1213 | 1213 |
go.opentelemetry.io/otel/semconv/v1.17.0 |
| 1214 | 1214 |
go.opentelemetry.io/otel/semconv/v1.21.0 |
| 1215 |
-# go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 |
|
| 1216 |
-## explicit; go 1.20 |
|
| 1217 |
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric |
|
| 1218 |
-# go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 |
|
| 1215 |
+# go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 |
|
| 1219 | 1216 |
## explicit; go 1.20 |
| 1220 | 1217 |
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc |
| 1221 | 1218 |
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal |
| ... | ... |
@@ -1223,7 +1222,7 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/envco |
| 1223 | 1223 |
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/oconf |
| 1224 | 1224 |
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/retry |
| 1225 | 1225 |
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc/internal/transform |
| 1226 |
-# go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 |
|
| 1226 |
+# go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0 |
|
| 1227 | 1227 |
## explicit; go 1.20 |
| 1228 | 1228 |
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp |
| 1229 | 1229 |
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp/internal |