update cadvisor to v0.31.0

This commit is contained in:
David Ashpole
2018-09-10 10:31:56 -07:00
parent ba33abd528
commit 788196e45b
118 changed files with 190025 additions and 318 deletions

201
vendor/github.com/mesos/mesos-go/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

13
vendor/github.com/mesos/mesos-go/NOTICE generated vendored Normal file
View File

@@ -0,0 +1,13 @@
Copyright 2013-2015, Mesosphere, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

50
vendor/github.com/mesos/mesos-go/api/v1/lib/BUILD generated vendored Normal file
View File

@@ -0,0 +1,50 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"client.go",
"doc.go",
"filters.go",
"fixedpoint.go",
"labels.go",
"mesos.pb.go",
"mesos.pb_ffjson.go",
"ranges.go",
"resources.go",
"values.go",
],
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib",
importpath = "github.com/mesos/mesos-go/api/v1/lib",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/gogo/protobuf/gogoproto:go_default_library",
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/roles:go_default_library",
"//vendor/github.com/pquerna/ffjson/fflib/v1:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/agent:all-srcs",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/client:all-srcs",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/debug:all-srcs",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding:all-srcs",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli:all-srcs",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/recordio:all-srcs",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/roles:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,35 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"agent.pb.go",
"agent.pb_ffjson.go",
],
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/agent",
importpath = "github.com/mesos/mesos-go/api/v1/lib/agent",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/gogo/protobuf/gogoproto:go_default_library",
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib:go_default_library",
"//vendor/github.com/pquerna/ffjson/fflib/v1:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/agent/calls:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,706 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto2";
package mesos.agent;
import "github.com/mesos/mesos-go/api/v1/lib/mesos.proto";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option go_package = "agent";
option (gogoproto.benchgen_all) = true;
option (gogoproto.enum_stringer_all) = true;
option (gogoproto.equal_all) = true;
option (gogoproto.goproto_enum_prefix_all) = false;
option (gogoproto.goproto_enum_stringer_all) = false;
option (gogoproto.goproto_stringer_all) = false;
option (gogoproto.goproto_unrecognized_all) = false;
option (gogoproto.gostring_all) = true;
option (gogoproto.marshaler_all) = true;
option (gogoproto.populate_all) = true;
option (gogoproto.protosizer_all) = true;
option (gogoproto.stringer_all) = true;
option (gogoproto.testgen_all) = true;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.verbose_equal_all) = true;
/**
* Calls that can be sent to the v1 agent API.
*
* A call is described using the standard protocol buffer "union"
* trick, see
* https://developers.google.com/protocol-buffers/docs/techniques#union.
*/
message Call {
// If a call of type `Call::FOO` requires additional parameters they can be
// included in the corresponding `Call::Foo` message. Similarly, if a call
// receives a synchronous response it will be returned as a `Response`
// message of type `Response::FOO`; see `Call::LaunchNestedContainerSession`
// and `Call::AttachContainerOutput` for exceptions.
enum Type {
UNKNOWN = 0;
GET_HEALTH = 1; // Retrieves the agent's health status.
GET_FLAGS = 2; // Retrieves the agent's flag configuration.
GET_VERSION = 3; // Retrieves the agent's version information.
GET_METRICS = 4; // See 'GetMetrics' below.
GET_LOGGING_LEVEL = 5; // Retrieves the agent's logging level.
SET_LOGGING_LEVEL = 6; // See 'SetLoggingLevel' below.
LIST_FILES = 7;
READ_FILE = 8; // See 'ReadFile' below.
GET_STATE = 9;
GET_CONTAINERS = 10;
// Retrieves the information about known frameworks.
GET_FRAMEWORKS = 11;
// Retrieves the information about known executors.
GET_EXECUTORS = 12;
// Retrieves the information about known operations.
GET_OPERATIONS = 31;
// Retrieves the information about known tasks.
GET_TASKS = 13;
// Retrieves the agent information.
GET_AGENT = 20;
// Retrieves the information about known resource providers.
GET_RESOURCE_PROVIDERS = 26;
// Calls for managing nested containers underneath an executor's container.
// Some of these calls are deprecated in favor of the calls
// for both standalone or nested containers further below.
LAUNCH_NESTED_CONTAINER = 14 [deprecated = true];
WAIT_NESTED_CONTAINER = 15 [deprecated = true];
KILL_NESTED_CONTAINER = 16 [deprecated = true];
REMOVE_NESTED_CONTAINER = 21 [deprecated = true];
// See 'LaunchNestedContainerSession' below.
LAUNCH_NESTED_CONTAINER_SESSION = 17;
ATTACH_CONTAINER_INPUT = 18; // See 'AttachContainerInput' below.
ATTACH_CONTAINER_OUTPUT = 19; // see 'AttachContainerOutput' below.
// Calls for managing standalone containers
// or containers nested underneath another container.
LAUNCH_CONTAINER = 22; // See 'LaunchContainer' below.
WAIT_CONTAINER = 23; // See 'WaitContainer' below.
KILL_CONTAINER = 24; // See 'KillContainer' below.
REMOVE_CONTAINER = 25; // See 'RemoveContainer' below.
ADD_RESOURCE_PROVIDER_CONFIG = 27; // See 'AddResourceProviderConfig' below. // NOLINT
UPDATE_RESOURCE_PROVIDER_CONFIG = 28; // See 'UpdateResourceProviderConfig' below. // NOLINT
REMOVE_RESOURCE_PROVIDER_CONFIG = 29; // See 'RemoveResourceProviderConfig' below. // NOLINT
// Prune unused container images.
PRUNE_IMAGES = 30;
option (gogoproto.goproto_enum_prefix) = true;
}
// Provides a snapshot of the current metrics tracked by the agent.
message GetMetrics {
// If set, `timeout` would be used to determines the maximum amount of time
// the API will take to respond. If the timeout is exceeded, some metrics
// may not be included in the response.
optional DurationInfo timeout = 1;
}
// Sets the logging verbosity level for a specified duration. Mesos uses
// [glog](https://github.com/google/glog) for logging. The library only uses
// verbose logging which means nothing will be output unless the verbosity
// level is set (by default it's 0, libprocess uses levels 1, 2, and 3).
message SetLoggingLevel {
// The verbosity level.
required uint32 level = 1 [(gogoproto.nullable) = false];
// The duration to keep verbosity level toggled. After this duration, the
// verbosity level of log would revert to the original level.
required DurationInfo duration = 2 [(gogoproto.nullable) = false];
}
// Provides the file listing for a directory.
message ListFiles {
required string path = 1 [(gogoproto.nullable) = false];
}
// Reads data from a file.
message ReadFile {
// The path of file.
required string path = 1 [(gogoproto.nullable) = false];
// Initial offset in file to start reading from.
required uint64 offset = 2 [(gogoproto.nullable) = false];
// The maximum number of bytes to read. The read length is capped at 16
// memory pages.
optional uint64 length = 3;
}
// Lists active containers on the agent.
message GetContainers {
optional bool show_nested = 1;
optional bool show_standalone = 2;
}
// Deprecated in favor of `LaunchContainer`.
message LaunchNestedContainer {
required ContainerID container_id = 1 [(gogoproto.customname) = "ContainerID", (gogoproto.nullable) = false];
optional CommandInfo command = 2;
optional ContainerInfo container = 3;
}
// Deprecated in favor of `WaitContainer`.
message WaitNestedContainer {
required ContainerID container_id = 1 [(gogoproto.customname) = "ContainerID", (gogoproto.nullable) = false];
}
// Deprecated in favor of `KillContainer`.
message KillNestedContainer {
required ContainerID container_id = 1 [(gogoproto.customname) = "ContainerID", (gogoproto.nullable) = false];
optional int32 signal = 2;
}
// Deprecated in favor of `RemoveContainer`.
message RemoveNestedContainer {
required ContainerID container_id = 1 [(gogoproto.customname) = "ContainerID", (gogoproto.nullable) = false];
}
// Launches a nested container within an executor's tree of containers.
// The differences between this call and `LaunchNestedContainer` are:
// 1) The container's life-cycle is tied to the lifetime of the
// connection used to make this call, i.e., if the connection ever
// breaks, the container will be destroyed.
// 2) The nested container shares the same namespaces and cgroups as
// its parent container.
// 3) Results in a streaming response of type `ProcessIO`. So the call
// needs to be made on a persistent connection.
message LaunchNestedContainerSession {
required ContainerID container_id = 1 [(gogoproto.customname) = "ContainerID", (gogoproto.nullable) = false];
optional CommandInfo command = 2;
optional ContainerInfo container = 3;
}
// Attaches the caller to the STDIN of the entry point of the container.
// Clients can use this to stream input data to a container.
// Note that this call needs to be made on a persistent connection by
// streaming a CONTAINER_ID message followed by one or more PROCESS_IO
// messages.
message AttachContainerInput {
enum Type {
UNKNOWN = 0;
CONTAINER_ID = 1;
PROCESS_IO = 2;
option (gogoproto.goproto_enum_prefix) = true;
}
optional Type type = 1 [(gogoproto.nullable) = false];
optional ContainerID container_id = 2 [(gogoproto.customname) = "ContainerID"];
optional ProcessIO process_io = 3 [(gogoproto.customname) = "ProcessIO"];
}
// Attaches the caller to the STDOUT and STDERR of the entrypoint of
// the container. Clients can use this to stream output/error from the
// container. This call will result in a streaming response of `ProcessIO`;
// so this call needs to be made on a persistent connection.
message AttachContainerOutput {
required ContainerID container_id = 1 [(gogoproto.customname) = "ContainerID", (gogoproto.nullable) = false];
}
// Launches a either a "standalone" container on this agent
// or a nested container within another tree of containers.
//
// A standalone container is launched by specifying a ContainerID
// with no parent. Standalone containers bypass the normal offer cycle
// between the master and agent. Unlike other containers, a standalone
// container does not have an executor or any tasks. This means the
// standalone container does not report back to Mesos or any framework
// and must be supervised separately.
//
// A nested container is launched by specifying a ContainerID with
// another existing container (including standalone containers)
// as the parent.
//
// Returns 200 OK if the new container launch succeeds.
// Returns 202 Accepted if the requested ContainerID is already in use
// by a standalone or nested container.
// Returns 400 Bad Request if the container launch fails.
message LaunchContainer {
// NOTE: Some characters cannot be used in the ID. All characters
// must be valid filesystem path characters. In addition, '/' and '.'
// are reserved.
required ContainerID container_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "ContainerID"];
optional CommandInfo command = 2;
// NOTE: Nested containers may not specify resources and instead
// share resources with its parent container.
//
// TODO(josephw): These resources are purely used for isolation
// and are not accounted for by the Mesos master (if connected).
// It is the caller's responsibility to ensure that resources are
// not overcommitted (e.g. CPU and memory) or conflicting (e.g. ports
// and volumes). Once there is support for preempting tasks and a
// way to update the resources advertised by the agent, these standalone
// container resources should be accounted for by the master.
repeated Resource resources = 3 [(gogoproto.nullable) = false];
optional ContainerInfo container = 4;
}
// Waits for the standalone or nested container to terminate
// and returns the exit status.
//
// Returns 200 OK if and when the container exits.
// Returns 404 Not Found if the container does not exist.
message WaitContainer {
required ContainerID container_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "ContainerID"];
}
// Kills the standalone or nested container. The signal to be sent
// to the container can be specified in the 'signal' field.
//
// Returns 200 OK if the signal is sent successfully.
// Returns 404 Not Found if the container does not exist.
message KillContainer {
required ContainerID container_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "ContainerID"];
// Defaults to SIGKILL.
optional int32 signal = 2;
}
// Removes a container's artifacts (runtime and sandbox directories).
//
// For nested containers, it is important to use this call if multiple
// nested containers are launched under the same parent container, because
// garbage collection only takes place at the parent container. Artifacts
// belonging to nested containers will not be garbage collected while
// the parent container is running.
//
// TODO(josephw): A standalone container's runtime directory is currently
// garbage collected as soon as the container exits. To allow the user to
// retrieve the exit status reliably, the runtime directory cannot be
// garbage collected immediately. Instead, the user will eventually be
// required to make this call after the standalone container has exited.
// Also, a standalone container's sandbox directory is currently not
// garbage collected and is only deleted via this call.
//
// Returns 200 OK if the removal is successful or if the parent container
// (for nested containers) does not exist.
// Returns 500 Internal Server Error if anything goes wrong, including
// if the container is still running or does not exist.
//
// TODO(josephw): Consider returning a 400 Bad Request instead of 500
// Internal Server Error when the user tries to remove a running or
// nonexistent nested container.
message RemoveContainer {
required ContainerID container_id = 1 [(gogoproto.nullable) = false, (gogoproto.customname) = "ContainerID"];
}
// Adds a new resource provider config file.
//
// The content of the `info` field will be written into a new config file in
// the resource provider config directory, and a new resource provider will be
// launched asynchronously based on the config. Callers must not set the
// `info.id` field. This call is idempotent, so if a config file identical to
// the content of the `info` field already exists, this call will return
// without launching a resource provider. Note that if a config file is
// placed into the resource provider config directory out-of-band after the
// agent starts up, it will not be checked against this call.
//
// Returns 200 OK if a new config file is created, or an identical config file
// exists.
// Returns 400 Bad Request if `info` is not well-formed.
// Returns 403 Forbidden if the call is not authorized.
// Returns 409 Conflict if another config file that describes a
// resource provider of the same type and name exists, but the content is
// not identical.
// Returns 500 Internal Server Error if anything goes wrong.
message AddResourceProviderConfig {
required ResourceProviderInfo info = 1 [(gogoproto.nullable) = false];
}
// Updates an existing resource provider config file.
//
// The content of the `info` field will be written into an existing config
// file that describes a resource provider of the specified type and name in
// the resource provider config directory, and the corresponding resource
// provider will be relaunched asynchronously to reflect the changes in the
// config. Callers must not set the `info.id` field. This call is idempotent,
// so if there is no change in the config, this call will return without
// relaunching the resource provider. Note that if a config file is placed
// into the resource provider config directory out-of-band after the agent
// starts up, it will not be checked against this call.
//
// Returns 200 OK if an existing config file is updated, or there is no change
// in the config file.
// Returns 400 Bad Request if `info` is not well-formed.
// Returns 403 Forbidden if the call is not authorized.
// Returns 404 Not Found if no config file describes a resource
// provider of the same type and name exists.
// Returns 500 Internal Server Error if anything goes wrong.
message UpdateResourceProviderConfig {
required ResourceProviderInfo info = 1 [(gogoproto.nullable) = false];
}
// Removes a config file from the resource provider config directory.
//
// The config file that describes the resource provider of the specified type
// and name will be removed, and the corresponding resource provider will be
// terminated asynchronously. This call is idempotent, so if no matching
// config file exists, this call will return without terminating any resource
// provider. Note that if a config file is placed into the resource provider
// config directory out-of-band after the agent starts up, it will not be
// checked against this call.
//
// Returns 200 OK if the config file is removed, or no matching config file
// exists.
// Returns 403 Forbidden if the call is not authorized.
// Returns 500 Internal Server Error if anything goes wrong.
message RemoveResourceProviderConfig {
required string type = 1 [(gogoproto.nullable) = false];
required string name = 2 [(gogoproto.nullable) = false];
}
// Prune unused container images from image store.
//
// Images and layers referenced by active containers as well as
// image references specified in `excluded_images` will not be pruned.
message PruneImages {
repeated Image excluded_images = 1 [(gogoproto.nullable) = false];
}
optional Type type = 1 [(gogoproto.nullable) = false];
optional GetMetrics get_metrics = 2;
optional SetLoggingLevel set_logging_level = 3;
optional ListFiles list_files = 4;
optional ReadFile read_file = 5;
optional GetContainers get_containers = 20;
optional LaunchNestedContainer launch_nested_container = 6
[deprecated = true];
optional WaitNestedContainer wait_nested_container = 7 [deprecated = true];
optional KillNestedContainer kill_nested_container = 8 [deprecated = true];
optional RemoveNestedContainer remove_nested_container = 12
[deprecated = true];
optional LaunchNestedContainerSession launch_nested_container_session = 9;
optional AttachContainerInput attach_container_input = 10;
optional AttachContainerOutput attach_container_output = 11;
optional LaunchContainer launch_container = 13;
optional WaitContainer wait_container = 14;
optional KillContainer kill_container = 15;
optional RemoveContainer remove_container = 16;
optional AddResourceProviderConfig add_resource_provider_config = 17;
optional UpdateResourceProviderConfig update_resource_provider_config = 18;
optional RemoveResourceProviderConfig remove_resource_provider_config = 19;
optional PruneImages prune_images = 21;
}
/**
* Synchronous responses for all calls made to the v1 agent API.
*/
message Response {
// Each of the responses of type `FOO` corresponds to `Foo` message below.
enum Type {
UNKNOWN = 0;
GET_HEALTH = 1; // See 'GetHealth' below.
GET_FLAGS = 2; // See 'GetFlags' below.
GET_VERSION = 3; // See 'GetVersion' below.
GET_METRICS = 4; // See 'GetMetrics' below.
GET_LOGGING_LEVEL = 5; // See 'GetLoggingLevel' below.
LIST_FILES = 6;
READ_FILE = 7; // See 'ReadFile' below.
GET_STATE = 8;
GET_CONTAINERS = 9;
GET_FRAMEWORKS = 10; // See 'GetFrameworks' below.
GET_EXECUTORS = 11; // See 'GetExecutors' below.
GET_OPERATIONS = 17; // See 'GetOperations' below.
GET_TASKS = 12; // See 'GetTasks' below.
GET_AGENT = 14; // See 'GetAgent' below.
GET_RESOURCE_PROVIDERS = 16; // See 'GetResourceProviders' below.
WAIT_NESTED_CONTAINER = 13 [deprecated = true];
WAIT_CONTAINER = 15; // See 'WaitContainer' below.
option (gogoproto.goproto_enum_prefix) = true;
}
// `healthy` would be true if the agent is healthy. Delayed responses are also
// indicative of the poor health of the agent.
message GetHealth {
required bool healthy = 1 [(gogoproto.nullable) = false];
}
// Contains the flag configuration of the agent.
message GetFlags {
repeated Flag flags = 1 [(gogoproto.nullable) = false];
}
// Contains the version information of the agent.
message GetVersion {
required VersionInfo version_info = 1 [(gogoproto.nullable) = false];
}
// Contains a snapshot of the current metrics.
message GetMetrics {
repeated Metric metrics = 1 [(gogoproto.nullable) = false];
}
// Contains the logging level of the agent.
message GetLoggingLevel {
required uint32 level = 1 [(gogoproto.nullable) = false];
}
// Contains the file listing(similar to `ls -l`) for a directory.
message ListFiles {
repeated FileInfo file_infos = 1 [(gogoproto.nullable) = false];
}
// Contains the file data.
message ReadFile {
// The size of file (in bytes).
required uint64 size = 1 [(gogoproto.nullable) = false];
required bytes data = 2;
}
// Contains full state of the agent i.e. information about the tasks,
// frameworks and executors running in the cluster.
message GetState {
optional GetTasks get_tasks = 1;
optional GetExecutors get_executors = 2;
optional GetFrameworks get_frameworks = 3;
}
// Information about containers running on this agent. It contains
// ContainerStatus and ResourceStatistics along with some metadata
// of the containers.
message GetContainers {
message Container {
optional FrameworkID framework_id = 1 [(gogoproto.customname) = "FrameworkID"];
optional ExecutorID executor_id = 2 [(gogoproto.customname) = "ExecutorID"];
optional string executor_name = 3;
required ContainerID container_id = 4 [(gogoproto.customname) = "ContainerID", (gogoproto.nullable) = false];
optional ContainerStatus container_status = 5;
optional ResourceStatistics resource_statistics = 6;
}
repeated Container containers = 1 [(gogoproto.nullable) = false];
}
// Information about all the frameworks known to the agent at the current
// time.
message GetFrameworks {
message Framework {
required FrameworkInfo framework_info = 1 [(gogoproto.nullable) = false];
}
repeated Framework frameworks = 1 [(gogoproto.nullable) = false];
repeated Framework completed_frameworks = 2 [(gogoproto.nullable) = false];
}
// Lists information about all the executors known to the agent at the
// current time.
message GetExecutors {
message Executor {
required ExecutorInfo executor_info = 1 [(gogoproto.nullable) = false];
}
repeated Executor executors = 1 [(gogoproto.nullable) = false];
repeated Executor completed_executors = 2 [(gogoproto.nullable) = false];
}
// Lists information about all operations known to the agent at the
// current time.
message GetOperations {
repeated Operation operations = 1 [(gogoproto.nullable) = false];
}
// Lists information about all the tasks known to the agent at the current
// time.
message GetTasks {
// Tasks that are pending in the agent's queue before an executor is
// launched.
repeated Task pending_tasks = 1 [(gogoproto.nullable) = false];
// Tasks that are enqueued for a launched executor that has not yet
// registered.
repeated Task queued_tasks = 2 [(gogoproto.nullable) = false];
// Tasks that are running.
repeated Task launched_tasks = 3 [(gogoproto.nullable) = false];
// Tasks that are terminated but pending updates.
repeated Task terminated_tasks = 4 [(gogoproto.nullable) = false];
// Tasks that are terminated and updates acked.
repeated Task completed_tasks = 5 [(gogoproto.nullable) = false];
}
// Contains the agent's information.
message GetAgent {
optional AgentInfo agent_info = 1;
}
// Lists information about all resource providers known to the agent
// at the current time.
message GetResourceProviders {
message ResourceProvider {
required ResourceProviderInfo resource_provider_info = 1 [(gogoproto.nullable) = false];
repeated Resource total_resources = 2 [(gogoproto.nullable) = false];
}
repeated ResourceProvider resource_providers = 1 [(gogoproto.nullable) = false];
}
// Returns termination information about the nested container.
message WaitNestedContainer {
// Wait status of the lead process in the container. Note that this
// is the return value of `wait(2)`, so callers must use the `wait(2)`
// family of macros to extract whether the process exited cleanly and
// what the exit code was.
optional int32 exit_status = 1;
// The `state` and `reason` fields may be populated if the Mesos agent
// terminates the container. In the absence of any special knowledge,
// executors should propagate this information via the `status` field
// of an `Update` call for the corresponding TaskID.
optional TaskState state = 2;
optional TaskStatus.Reason reason = 3;
// This field will be populated if the task was terminated due to
// a resource limitation.
optional TaskResourceLimitation limitation = 4;
optional string message = 5;
}
// Returns termination information about the standalone or nested container.
message WaitContainer {
// Wait status of the lead process in the container. Note that this
// is the return value of `wait(2)`, so callers must use the `wait(2)`
// family of macros to extract whether the process exited cleanly and
// what the exit code was.
optional int32 exit_status = 1;
// The `state` and `reason` fields may be populated if the Mesos agent
// terminates the container. In the absence of any special knowledge,
// executors should propagate this information via the `status` field
// of an `Update` call for the corresponding TaskID.
optional TaskState state = 2;
optional TaskStatus.Reason reason = 3;
// This field will be populated if the task was terminated due to
// a resource limitation.
optional TaskResourceLimitation limitation = 4;
optional string message = 5;
}
optional Type type = 1 [(gogoproto.nullable) = false];
optional GetHealth get_health = 2;
optional GetFlags get_flags = 3;
optional GetVersion get_version = 4;
optional GetMetrics get_metrics = 5;
optional GetLoggingLevel get_logging_level = 6;
optional ListFiles list_files = 7;
optional ReadFile read_file = 8;
optional GetState get_state = 9;
optional GetContainers get_containers = 10;
optional GetFrameworks get_frameworks = 11;
optional GetExecutors get_executors = 12;
optional GetOperations get_operations = 18;
optional GetTasks get_tasks = 13;
optional GetAgent get_agent = 15;
optional GetResourceProviders get_resource_providers = 17;
optional WaitNestedContainer wait_nested_container = 14;
optional WaitContainer wait_container = 16;
}
/**
* Streaming response to `Call::LAUNCH_NESTED_CONTAINER_SESSION` and
* `Call::ATTACH_CONTAINER_OUTPUT`.
*
* This message is also used to stream request data for
* `Call::ATTACH_CONTAINER_INPUT`.
*/
message ProcessIO {
enum Type {
UNKNOWN = 0;
DATA = 1;
CONTROL = 2;
option (gogoproto.goproto_enum_prefix) = true;
}
message Data {
enum Type {
UNKNOWN = 0;
STDIN = 1;
STDOUT = 2;
STDERR = 3;
option (gogoproto.goproto_enum_prefix) = true;
}
optional Type type = 1 [(gogoproto.nullable) = false];
optional bytes data = 2;
}
message Control {
enum Type {
UNKNOWN = 0;
TTY_INFO = 1;
HEARTBEAT = 2;
option (gogoproto.goproto_enum_prefix) = true;
}
message Heartbeat {
optional DurationInfo interval = 1;
}
optional Type type = 1 [(gogoproto.nullable) = false];
optional TTYInfo tty_info = 2 [(gogoproto.customname) = "TTYInfo"];
optional Heartbeat heartbeat = 3;
}
optional Type type = 1 [(gogoproto.nullable) = false];
optional Data data = 2;
optional Control control = 3;
}

View File

@@ -0,0 +1,32 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"calls.go",
"calls_generated.go",
"gen.go",
],
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/agent/calls",
importpath = "github.com/mesos/mesos-go/api/v1/lib/agent/calls",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/mesos/mesos-go/api/v1/lib:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/agent:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,258 @@
package calls
import (
"time"
"github.com/mesos/mesos-go/api/v1/lib"
"github.com/mesos/mesos-go/api/v1/lib/agent"
)
func GetHealth() *agent.Call { return &agent.Call{Type: agent.Call_GET_HEALTH} }
func GetFlags() *agent.Call { return &agent.Call{Type: agent.Call_GET_FLAGS} }
func GetVersion() *agent.Call { return &agent.Call{Type: agent.Call_GET_VERSION} }
func GetMetrics(d *time.Duration) (call *agent.Call) {
call = &agent.Call{
Type: agent.Call_GET_METRICS,
GetMetrics: &agent.Call_GetMetrics{},
}
if d != nil {
call.GetMetrics.Timeout = &mesos.DurationInfo{
Nanoseconds: d.Nanoseconds(),
}
}
return
}
func GetLoggingLevel() *agent.Call { return &agent.Call{Type: agent.Call_GET_LOGGING_LEVEL} }
func SetLoggingLevel(level uint32, d time.Duration) *agent.Call {
return &agent.Call{
Type: agent.Call_SET_LOGGING_LEVEL,
SetLoggingLevel: &agent.Call_SetLoggingLevel{
Duration: mesos.DurationInfo{Nanoseconds: d.Nanoseconds()},
Level: level,
},
}
}
func ListFiles(path string) *agent.Call {
return &agent.Call{
Type: agent.Call_LIST_FILES,
ListFiles: &agent.Call_ListFiles{
Path: path,
},
}
}
func ReadFile(path string, offset uint64) *agent.Call {
return &agent.Call{
Type: agent.Call_READ_FILE,
ReadFile: &agent.Call_ReadFile{
Path: path,
Offset: offset,
},
}
}
func ReadFileWithLength(path string, offset, length uint64) (call *agent.Call) {
call = ReadFile(path, offset)
call.ReadFile.Length = &length
return
}
func GetState() *agent.Call { return &agent.Call{Type: agent.Call_GET_STATE} }
func GetContainers() *agent.Call { return &agent.Call{Type: agent.Call_GET_CONTAINERS} }
func GetFrameworks() *agent.Call { return &agent.Call{Type: agent.Call_GET_FRAMEWORKS} }
func GetExecutors() *agent.Call { return &agent.Call{Type: agent.Call_GET_EXECUTORS} }
func GetOperations() *agent.Call { return &agent.Call{Type: agent.Call_GET_OPERATIONS} }
func GetTasks() *agent.Call { return &agent.Call{Type: agent.Call_GET_TASKS} }
func GetAgent() *agent.Call { return &agent.Call{Type: agent.Call_GET_AGENT} }
func GetResourceProviders() *agent.Call { return &agent.Call{Type: agent.Call_GET_RESOURCE_PROVIDERS} }
func LaunchNestedContainer(cid mesos.ContainerID, cmd *mesos.CommandInfo, ci *mesos.ContainerInfo) *agent.Call {
return &agent.Call{
Type: agent.Call_LAUNCH_NESTED_CONTAINER,
LaunchNestedContainer: &agent.Call_LaunchNestedContainer{
ContainerID: cid,
Command: cmd,
Container: ci,
},
}
}
func LaunchContainer(cid mesos.ContainerID, cmd *mesos.CommandInfo, ci *mesos.ContainerInfo, r []mesos.Resource) *agent.Call {
return &agent.Call{
Type: agent.Call_LAUNCH_CONTAINER,
LaunchContainer: &agent.Call_LaunchContainer{
ContainerID: cid,
Command: cmd,
Container: ci,
Resources: r,
},
}
}
func WaitNestedContainer(cid mesos.ContainerID) *agent.Call {
return &agent.Call{
Type: agent.Call_WAIT_NESTED_CONTAINER,
WaitNestedContainer: &agent.Call_WaitNestedContainer{
ContainerID: cid,
},
}
}
func WaitContainer(cid mesos.ContainerID) *agent.Call {
return &agent.Call{
Type: agent.Call_WAIT_CONTAINER,
WaitContainer: &agent.Call_WaitContainer{
ContainerID: cid,
},
}
}
func KillNestedContainer(cid mesos.ContainerID) *agent.Call {
return &agent.Call{
Type: agent.Call_KILL_NESTED_CONTAINER,
KillNestedContainer: &agent.Call_KillNestedContainer{
ContainerID: cid,
},
}
}
func KillContainer(cid mesos.ContainerID) *agent.Call {
return &agent.Call{
Type: agent.Call_KILL_CONTAINER,
KillContainer: &agent.Call_KillContainer{
ContainerID: cid,
},
}
}
func RemoveNestedContainer(cid mesos.ContainerID) *agent.Call {
return &agent.Call{
Type: agent.Call_REMOVE_NESTED_CONTAINER,
RemoveNestedContainer: &agent.Call_RemoveNestedContainer{
ContainerID: cid,
},
}
}
func RemoveContainer(cid mesos.ContainerID) *agent.Call {
return &agent.Call{
Type: agent.Call_REMOVE_CONTAINER,
RemoveContainer: &agent.Call_RemoveContainer{
ContainerID: cid,
},
}
}
func LaunchNestedContainerSession(cid mesos.ContainerID, cmd *mesos.CommandInfo, ci *mesos.ContainerInfo) *agent.Call {
return &agent.Call{
Type: agent.Call_LAUNCH_NESTED_CONTAINER_SESSION,
LaunchNestedContainerSession: &agent.Call_LaunchNestedContainerSession{
ContainerID: cid,
Command: cmd,
Container: ci,
},
}
}
func AttachContainerOutput(cid mesos.ContainerID) *agent.Call {
return &agent.Call{
Type: agent.Call_ATTACH_CONTAINER_OUTPUT,
AttachContainerOutput: &agent.Call_AttachContainerOutput{
ContainerID: cid,
},
}
}
// AttachContainerInput returns a Call that is used to initiate attachment to a container's stdin.
// Callers should first send this Call followed by one or more AttachContainerInputXxx calls.
func AttachContainerInput(cid mesos.ContainerID) *agent.Call {
return &agent.Call{
Type: agent.Call_ATTACH_CONTAINER_INPUT,
AttachContainerInput: &agent.Call_AttachContainerInput{
Type: agent.Call_AttachContainerInput_CONTAINER_ID,
ContainerID: &cid,
},
}
}
func AttachContainerInputData(data []byte) *agent.Call {
return &agent.Call{
Type: agent.Call_ATTACH_CONTAINER_INPUT,
AttachContainerInput: &agent.Call_AttachContainerInput{
Type: agent.Call_AttachContainerInput_PROCESS_IO,
ProcessIO: &agent.ProcessIO{
Type: agent.ProcessIO_DATA,
Data: &agent.ProcessIO_Data{
Type: agent.ProcessIO_Data_STDIN,
Data: data,
},
},
},
}
}
func AttachContainerInputTTY(t *mesos.TTYInfo) *agent.Call {
return &agent.Call{
Type: agent.Call_ATTACH_CONTAINER_INPUT,
AttachContainerInput: &agent.Call_AttachContainerInput{
Type: agent.Call_AttachContainerInput_PROCESS_IO,
ProcessIO: &agent.ProcessIO{
Type: agent.ProcessIO_CONTROL,
Control: &agent.ProcessIO_Control{
Type: agent.ProcessIO_Control_TTY_INFO,
TTYInfo: t,
},
},
},
}
}
func AddResourceProviderConfig(rpi mesos.ResourceProviderInfo) *agent.Call {
return &agent.Call{
Type: agent.Call_ADD_RESOURCE_PROVIDER_CONFIG,
AddResourceProviderConfig: &agent.Call_AddResourceProviderConfig{
Info: rpi,
},
}
}
func UpdateResourceProviderConfig(rpi mesos.ResourceProviderInfo) *agent.Call {
return &agent.Call{
Type: agent.Call_UPDATE_RESOURCE_PROVIDER_CONFIG,
UpdateResourceProviderConfig: &agent.Call_UpdateResourceProviderConfig{
Info: rpi,
},
}
}
func RemoveResourceProviderConfig(typ, name string) *agent.Call {
return &agent.Call{
Type: agent.Call_REMOVE_RESOURCE_PROVIDER_CONFIG,
RemoveResourceProviderConfig: &agent.Call_RemoveResourceProviderConfig{
Type: typ,
Name: name,
},
}
}
func PruneImages(excluded []mesos.Image) *agent.Call {
return &agent.Call{
Type: agent.Call_PRUNE_IMAGES,
PruneImages: &agent.Call_PruneImages{
ExcludedImages: excluded,
},
}
}

View File

@@ -0,0 +1,129 @@
package calls
// go generate -import github.com/mesos/mesos-go/api/v1/lib/agent -type C:agent.Call
// GENERATED CODE FOLLOWS; DO NOT EDIT.
import (
"context"
"github.com/mesos/mesos-go/api/v1/lib"
"github.com/mesos/mesos-go/api/v1/lib/encoding"
"github.com/mesos/mesos-go/api/v1/lib/agent"
)
type (
// Request generates a Call that's sent to a Mesos agent. Subsequent invocations are expected to
// yield equivalent calls. Intended for use w/ non-streaming requests to an agent.
Request interface {
Call() *agent.Call
}
// RequestFunc is the functional adaptation of Request.
RequestFunc func() *agent.Call
// RequestStreaming generates a Call that's send to a Mesos agent. Subsequent invocations MAY generate
// different Call objects. No more Call objects are expected once a nil is returned to signal the end of
// of the request stream.
RequestStreaming interface {
Request
IsStreaming()
}
// RequestStreamingFunc is the functional adaptation of RequestStreaming.
RequestStreamingFunc func() *agent.Call
// Send issues a Request to a Mesos agent and properly manages Call-specific mechanics.
Sender interface {
Send(context.Context, Request) (mesos.Response, error)
}
// SenderFunc is the functional adaptation of the Sender interface
SenderFunc func(context.Context, Request) (mesos.Response, error)
)
func (f RequestFunc) Call() *agent.Call { return f() }
func (f RequestFunc) Marshaler() encoding.Marshaler {
// avoid returning (*agent.Call)(nil) for interface type
if call := f(); call != nil {
return call
}
return nil
}
func (f RequestStreamingFunc) Push(c ...*agent.Call) RequestStreamingFunc { return Push(f, c...) }
func (f RequestStreamingFunc) Marshaler() encoding.Marshaler {
// avoid returning (*agent.Call)(nil) for interface type
if call := f(); call != nil {
return call
}
return nil
}
func (f RequestStreamingFunc) IsStreaming() {}
func (f RequestStreamingFunc) Call() *agent.Call { return f() }
// Push prepends one or more calls onto a request stream. If no calls are given then the original stream is returned.
func Push(r RequestStreaming, c ...*agent.Call) RequestStreamingFunc {
return func() *agent.Call {
if len(c) == 0 {
return r.Call()
}
head := c[0]
c = c[1:]
return head
}
}
// Empty generates a stream that always returns nil.
func Empty() RequestStreamingFunc { return func() *agent.Call { return nil } }
var (
_ = Request(RequestFunc(nil))
_ = RequestStreaming(RequestStreamingFunc(nil))
_ = Sender(SenderFunc(nil))
)
// NonStreaming returns a RequestFunc that always generates the same Call.
func NonStreaming(c *agent.Call) RequestFunc { return func() *agent.Call { return c } }
// FromChan returns a streaming request that fetches calls from the given channel until it closes.
// If a nil chan is specified then the returned func will always generate nil.
func FromChan(ch <-chan *agent.Call) RequestStreamingFunc {
if ch == nil {
// avoid blocking forever if we're handed a nil chan
return func() *agent.Call { return nil }
}
return func() *agent.Call {
if m, ok := <-ch; ok {
return m
}
return nil
}
}
// Send implements the Sender interface for SenderFunc
func (f SenderFunc) Send(ctx context.Context, r Request) (mesos.Response, error) {
return f(ctx, r)
}
// IgnoreResponse generates a sender that closes any non-nil response received by Mesos.
func IgnoreResponse(s Sender) SenderFunc {
return func(ctx context.Context, r Request) (mesos.Response, error) {
resp, err := s.Send(ctx, r)
if resp != nil {
resp.Close()
}
return nil, err
}
}
// SendNoData is a convenience func that executes the given Call using the provided Sender
// and always drops the response data.
func SendNoData(ctx context.Context, sender Sender, r Request) (err error) {
_, err = IgnoreResponse(sender).Send(ctx, r)
return
}

View File

@@ -0,0 +1,3 @@
package calls
//go:generate go run ../../extras/gen/sender.go ../../extras/gen/gen.go -import github.com/mesos/mesos-go/api/v1/lib/agent -type C:agent.Call

71
vendor/github.com/mesos/mesos-go/api/v1/lib/client.go generated vendored Normal file
View File

@@ -0,0 +1,71 @@
package mesos
// DEPRECATED in favor of github.com/mesos/mesos-go/api/v1/lib/client
import (
"io"
"github.com/mesos/mesos-go/api/v1/lib/encoding"
)
// A Client represents a Mesos API client which can send Calls and return
// a streaming Decoder from which callers can read Events from, an io.Closer to
// close the event stream on graceful termination and an error in case of failure.
type Client interface {
Do(encoding.Marshaler) (Response, error)
}
// ClientFunc is a functional adapter of the Client interface
type ClientFunc func(encoding.Marshaler) (Response, error)
// Do implements Client
func (cf ClientFunc) Do(m encoding.Marshaler) (Response, error) { return cf(m) }
// Response captures the output of a Mesos API operation. Callers are responsible for invoking
// Close when they're finished processing the response otherwise there may be connection leaks.
type Response interface {
io.Closer
encoding.Decoder
}
// ResponseDecorator optionally modifies the behavior of a Response
type ResponseDecorator interface {
Decorate(Response) Response
}
// ResponseDecoratorFunc is the functional adapter for ResponseDecorator
type ResponseDecoratorFunc func(Response) Response
func (f ResponseDecoratorFunc) Decorate(r Response) Response { return f(r) }
// CloseFunc is the functional adapter for io.Closer
type CloseFunc func() error
// Close implements io.Closer
func (f CloseFunc) Close() error { return f() }
// ResponseWrapper delegates to optional overrides for invocations of Response methods.
type ResponseWrapper struct {
Response Response
Closer io.Closer
Decoder encoding.Decoder
}
func (wrapper *ResponseWrapper) Close() error {
if wrapper.Closer != nil {
return wrapper.Closer.Close()
}
if wrapper.Response != nil {
return wrapper.Response.Close()
}
return nil
}
func (wrapper *ResponseWrapper) Decode(u encoding.Unmarshaler) error {
if wrapper.Decoder != nil {
return wrapper.Decoder.Decode(u)
}
return wrapper.Response.Decode(u)
}
var _ = Response(&ResponseWrapper{})

View File

@@ -0,0 +1,24 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["client.go"],
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/client",
importpath = "github.com/mesos/mesos-go/api/v1/lib/client",
visibility = ["//visibility:public"],
deps = ["//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,54 @@
package client
import (
"github.com/mesos/mesos-go/api/v1/lib/encoding"
)
type (
// ResponseClass indicates the kind of response that a caller is expecting from Mesos.
ResponseClass int
// Request is a non-streaming request from the client to the server.
// Marshaler always returns the same object; the object is sent once to the server and then
// a response is expected.
Request interface {
Marshaler() encoding.Marshaler
}
// RequestStreaming is a streaming request from the client to the server.
// Marshaler returns a new object for upon each invocation, nil when there are no more objects to send.
// Client implementations are expected to differentiate between Request and RequestStreaming either by
// type-switching or by attempting interface conversion.
RequestStreaming interface {
Request
IsStreaming()
}
RequestFunc func() encoding.Marshaler
RequestStreamingFunc func() encoding.Marshaler
)
var (
_ = Request(RequestFunc(nil))
_ = RequestStreaming(RequestStreamingFunc(nil))
)
func (f RequestFunc) Marshaler() encoding.Marshaler { return f() }
func (f RequestStreamingFunc) Marshaler() encoding.Marshaler { return f() }
func (f RequestStreamingFunc) IsStreaming() {}
// RequestSingleton generates a non-streaming Request that always returns the same marshaler
func RequestSingleton(m encoding.Marshaler) Request {
return RequestFunc(func() encoding.Marshaler { return m })
}
const (
ResponseClassSingleton ResponseClass = iota
ResponseClassStreaming
ResponseClassNoData
// ResponseClassAuto should be used with versions of Mesos prior to 1.2.x.
// Otherwise, this type is deprecated and callers should use ResponseClassSingleton
// or ResponseClassStreaming instead.
ResponseClassAuto
)

View File

@@ -0,0 +1,23 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["logger.go"],
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/debug",
importpath = "github.com/mesos/mesos-go/api/v1/lib/debug",
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,17 @@
package debug
import "log"
type Logger bool
func (d Logger) Log(v ...interface{}) {
if d {
log.Print(v...)
}
}
func (d Logger) Logf(s string, v ...interface{}) {
if d {
log.Printf(s, v...)
}
}

3
vendor/github.com/mesos/mesos-go/api/v1/lib/doc.go generated vendored Normal file
View File

@@ -0,0 +1,3 @@
// Package mesos presents common v1 HTTP API message types in addition to extension APIs that
// aim to simplify use of the machine-generated code.
package mesos

View File

@@ -0,0 +1,33 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["types.go"],
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/encoding",
importpath = "github.com/mesos/mesos-go/api/v1/lib/encoding",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/codecs:all-srcs",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing:all-srcs",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/json:all-srcs",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/proto:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,28 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["codecs.go"],
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/codecs",
importpath = "github.com/mesos/mesos-go/api/v1/lib/encoding/codecs",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/json:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/proto:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,33 @@
package codecs
import (
"github.com/mesos/mesos-go/api/v1/lib/encoding"
"github.com/mesos/mesos-go/api/v1/lib/encoding/json"
"github.com/mesos/mesos-go/api/v1/lib/encoding/proto"
)
const (
// MediaTypeProtobuf is the Protobuf serialization format media type.
MediaTypeProtobuf = encoding.MediaType("application/x-protobuf")
// MediaTypeJSON is the JSON serialiation format media type.
MediaTypeJSON = encoding.MediaType("application/json")
NameProtobuf = "protobuf"
NameJSON = "json"
)
// ByMediaType are pre-configured default Codecs, ready to use OOTB
var ByMediaType = map[encoding.MediaType]encoding.Codec{
MediaTypeProtobuf: encoding.Codec{
Name: NameProtobuf,
Type: MediaTypeProtobuf,
NewEncoder: proto.NewEncoder,
NewDecoder: proto.NewDecoder,
},
MediaTypeJSON: encoding.Codec{
Name: NameJSON,
Type: MediaTypeJSON,
NewEncoder: json.NewEncoder,
NewDecoder: json.NewDecoder,
},
}

View File

@@ -0,0 +1,26 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"decoder.go",
"framing.go",
],
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing",
importpath = "github.com/mesos/mesos-go/api/v1/lib/encoding/framing",
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,34 @@
package framing
type (
// UnmarshalFunc translates bytes to objects
UnmarshalFunc func([]byte, interface{}) error
// Decoder reads and decodes Protobuf messages from an io.Reader.
Decoder interface {
// Decode reads the next encoded message from its input and stores it
// in the value pointed to by m. If m isn't a proto.Message, Decode will panic.
Decode(interface{}) error
}
// DecoderFunc is the functional adaptation of Decoder
DecoderFunc func(interface{}) error
)
func (f DecoderFunc) Decode(m interface{}) error { return f(m) }
var _ = Decoder(DecoderFunc(nil))
// NewDecoder returns a new Decoder that reads from the given frame Reader.
func NewDecoder(r Reader, uf UnmarshalFunc) DecoderFunc {
return func(m interface{}) error {
// Note: the buf returned by ReadFrame will change over time, it can't be sub-sliced
// and then those sub-slices retained. Examination of generated proto code seems to indicate
// that byte buffers are copied vs. referenced by sub-slice (gogo protoc).
frame, err := r.ReadFrame()
if err != nil {
return err
}
return uf(frame, m)
}
}

View File

@@ -0,0 +1,70 @@
package framing
import (
"io"
"io/ioutil"
)
type Error string
func (err Error) Error() string { return string(err) }
const (
ErrorUnderrun = Error("frame underrun, unexpected EOF")
ErrorBadSize = Error("bad frame size")
ErrorOversizedFrame = Error("oversized frame, max size exceeded")
)
type (
// Reader generates data frames from some source, returning io.EOF when the end of the input stream is
// detected.
Reader interface {
ReadFrame() (frame []byte, err error)
}
// ReaderFunc is the functional adaptation of Reader.
ReaderFunc func() ([]byte, error)
// Writer sends whole frames to some endpoint; returns io.ErrShortWrite if the frame is only partially written.
Writer interface {
WriteFrame(frame []byte) error
}
// WriterFunc is the functional adaptation of Writer.
WriterFunc func([]byte) error
)
func (f ReaderFunc) ReadFrame() ([]byte, error) { return f() }
func (f WriterFunc) WriteFrame(b []byte) error { return f(b) }
var _ = Reader(ReaderFunc(nil))
var _ = Writer(WriterFunc(nil))
// EOFReaderFunc always returns nil, io.EOF; it implements the ReaderFunc API.
func EOFReaderFunc() ([]byte, error) { return nil, io.EOF }
var _ = ReaderFunc(EOFReaderFunc) // sanity check
// ReadAll returns a reader func that returns the complete contents of `r` in a single frame.
// A zero length frame is treated as an "end of stream" condition, returning io.EOF.
func ReadAll(r io.Reader) ReaderFunc {
return func() (b []byte, err error) {
b, err = ioutil.ReadAll(r)
if len(b) == 0 && err == nil {
err = io.EOF
}
return
}
}
// WriterFor adapts an io.Writer to the Writer interface. All buffers are written to `w` without decoration or
// modification.
func WriterFor(w io.Writer) WriterFunc {
return func(b []byte) error {
n, err := w.Write(b)
if err == nil && n != len(b) {
return io.ErrShortWrite
}
return err
}
}

View File

@@ -0,0 +1,27 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["json.go"],
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/json",
importpath = "github.com/mesos/mesos-go/api/v1/lib/encoding/json",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,28 @@
package json
import (
"encoding/json"
"github.com/mesos/mesos-go/api/v1/lib/encoding"
"github.com/mesos/mesos-go/api/v1/lib/encoding/framing"
)
// NewEncoder returns a new Encoder of Calls to JSON messages written to
// the given io.Writer.
func NewEncoder(s encoding.Sink) encoding.Encoder {
w := s()
return encoding.EncoderFunc(func(m encoding.Marshaler) error {
b, err := json.Marshal(m)
if err != nil {
return err
}
return w.WriteFrame(b)
})
}
// NewDecoder returns a new Decoder of JSON messages read from the given source.
func NewDecoder(s encoding.Source) encoding.Decoder {
r := s()
dec := framing.NewDecoder(r, json.Unmarshal)
return encoding.DecoderFunc(func(u encoding.Unmarshaler) error { return dec.Decode(u) })
}

View File

@@ -0,0 +1,31 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"encoding.go",
],
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/proto",
importpath = "github.com/mesos/mesos-go/api/v1/lib/encoding/proto",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,4 @@
// Package proto implements protobuf utilities such as functional options to
// construct complex structs and encoders and decoders composable with
// io.ReadWriters.
package proto

View File

@@ -0,0 +1,30 @@
package proto
import (
"github.com/gogo/protobuf/proto"
"github.com/mesos/mesos-go/api/v1/lib/encoding"
"github.com/mesos/mesos-go/api/v1/lib/encoding/framing"
)
// NewEncoder returns a new Encoder of Calls to Protobuf messages written to
// the given io.Writer.
func NewEncoder(s encoding.Sink) encoding.Encoder {
w := s()
return encoding.EncoderFunc(func(m encoding.Marshaler) error {
b, err := proto.Marshal(m.(proto.Message))
if err != nil {
return err
}
return w.WriteFrame(b)
})
}
// NewDecoder returns a new Decoder of Protobuf messages read from the given Source.
func NewDecoder(s encoding.Source) encoding.Decoder {
r := s()
var (
uf = func(b []byte, m interface{}) error { return proto.Unmarshal(b, m.(proto.Message)) }
dec = framing.NewDecoder(r, uf)
)
return encoding.DecoderFunc(func(u encoding.Unmarshaler) error { return dec.Decode(u) })
}

View File

@@ -0,0 +1,111 @@
package encoding
import (
"encoding/json"
"io"
pb "github.com/gogo/protobuf/proto"
"github.com/mesos/mesos-go/api/v1/lib/encoding/framing"
)
type MediaType string
// ContentType returns the HTTP Content-Type associated with the MediaType
func (m MediaType) ContentType() string { return string(m) }
type (
Source func() framing.Reader
Sink func() framing.Writer
// A Codec composes encoding and decoding of a serialization format.
Codec struct {
Name string
Type MediaType
NewEncoder func(Sink) Encoder
NewDecoder func(Source) Decoder
}
SourceFactory interface {
NewSource(r io.Reader) Source
}
SourceFactoryFunc func(r io.Reader) Source
SinkFactory interface {
NewSink(w io.Writer) Sink
}
SinkFactoryFunc func(w io.Writer) Sink
)
func (f SourceFactoryFunc) NewSource(r io.Reader) Source { return f(r) }
func (f SinkFactoryFunc) NewSink(w io.Writer) Sink { return f(w) }
var (
_ = SourceFactory(SourceFactoryFunc(nil))
_ = SinkFactory(SinkFactoryFunc(nil))
)
// SourceReader returns a Source that buffers all input from the given io.Reader
// and returns the contents in a single frame.
func SourceReader(r io.Reader) Source {
ch := make(chan framing.ReaderFunc, 1)
ch <- framing.ReadAll(r)
return func() framing.Reader {
select {
case f := <-ch:
return f
default:
return framing.ReaderFunc(framing.EOFReaderFunc)
}
}
}
// SinkWriter returns a Sink that sends a frame to an io.Writer with no decoration.
func SinkWriter(w io.Writer) Sink { return func() framing.Writer { return framing.WriterFor(w) } }
// String implements the fmt.Stringer interface.
func (c *Codec) String() string {
if c == nil {
return ""
}
return c.Name
}
type (
// Marshaler composes the supported marshaling formats.
Marshaler interface {
pb.Marshaler
json.Marshaler
}
// Unmarshaler composes the supporter unmarshaling formats.
Unmarshaler interface {
pb.Unmarshaler
json.Unmarshaler
}
// An Encoder encodes a given Marshaler or returns an error in case of failure.
Encoder interface {
Encode(Marshaler) error
}
// EncoderFunc is the functional adapter for Encoder
EncoderFunc func(Marshaler) error
// A Decoder decodes a given Unmarshaler or returns an error in case of failure.
Decoder interface {
Decode(Unmarshaler) error
}
// DecoderFunc is the functional adapter for Decoder
DecoderFunc func(Unmarshaler) error
)
// Decode implements the Decoder interface
func (f DecoderFunc) Decode(u Unmarshaler) error { return f(u) }
// Encode implements the Encoder interface
func (f EncoderFunc) Encode(m Marshaler) error { return f(m) }
var (
_ = Encoder(EncoderFunc(nil))
_ = Decoder(DecoderFunc(nil))
)

26
vendor/github.com/mesos/mesos-go/api/v1/lib/filters.go generated vendored Normal file
View File

@@ -0,0 +1,26 @@
package mesos
import "time"
type FilterOpt func(*Filters)
func (f *Filters) With(opts ...FilterOpt) *Filters {
for _, o := range opts {
o(f)
}
return f
}
func RefuseSeconds(d time.Duration) FilterOpt {
return func(f *Filters) {
s := d.Seconds()
f.RefuseSeconds = &s
}
}
func OptionalFilters(fo ...FilterOpt) *Filters {
if len(fo) == 0 {
return nil
}
return (&Filters{}).With(fo...)
}

View File

@@ -0,0 +1,35 @@
package mesos
// fixed point scalar math from mesos:src/common/values.cpp
// --
// We manipulate scalar values by converting them from floating point to a
// fixed point representation, doing a calculation, and then converting
// the result back to floating point. We deliberately only preserve three
// decimal digits of precision in the fixed point representation. This
// ensures that client applications see predictable numerical behavior, at
// the expense of sacrificing some precision.
import "math"
func convertToFloat64(f int64) float64 {
// NOTE: We do the conversion from fixed point via integer division
// and then modulus, rather than a single floating point division.
// This ensures that we only apply floating point division to inputs
// in the range [0,999], which is easier to check for correctness.
var (
quotient = float64(f / 1000)
remainder = float64(f%1000) / 1000.0
)
return quotient + remainder
}
func convertToFixed64(f float64) int64 {
return round64(f * 1000)
}
func round64(f float64) int64 {
if math.Abs(f) < 0.5 {
return 0
}
return int64(f + math.Copysign(0.5, f))
}

View File

@@ -0,0 +1,40 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"auth_basic.go",
"http.go",
"opts.go",
],
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli",
importpath = "github.com/mesos/mesos-go/api/v1/lib/httpcli",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/mesos/mesos-go/api/v1/lib:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/client:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/debug:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/codecs:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/apierrors:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/recordio:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/apierrors:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,23 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["apierrors.go"],
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/httpcli/apierrors",
importpath = "github.com/mesos/mesos-go/api/v1/lib/httpcli/apierrors",
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,161 @@
package apierrors
import (
"io"
"io/ioutil"
"net/http"
)
// Code is a Mesos HTTP v1 API response status code
type Code int
const (
// MsgNotLeader is returned by Do calls that are sent to a non leading Mesos master.
MsgNotLeader = "call sent to a non-leading master"
// MsgAuth is returned by Do calls that are not successfully authenticated.
MsgAuth = "call not authenticated"
// MsgUnsubscribed is returned by Do calls that are sent before a subscription is established.
MsgUnsubscribed = "no subscription established"
// MsgVersion is returned by Do calls that are sent to an incompatible API version.
MsgVersion = "incompatible API version"
// MsgMalformed is returned by Do calls that are malformed.
MsgMalformed = "malformed request"
// MsgMediaType is returned by Do calls that are sent with an unsupported media type.
MsgMediaType = "unsupported media type"
// MsgRateLimit is returned by Do calls that are rate limited. This is a temporary condition
// that should clear.
MsgRateLimit = "rate limited"
// MsgUnavailable is returned by Do calls that are sent to a master or agent that's in recovery, or
// does not yet realize that it's the leader. This is a temporary condition that should clear.
MsgUnavailable = "mesos server unavailable"
// MsgNotFound could happen if the master or agent libprocess has not yet set up http routes.
MsgNotFound = "mesos http endpoint not found"
CodeNotLeader = Code(http.StatusTemporaryRedirect)
CodeNotAuthenticated = Code(http.StatusUnauthorized)
CodeUnsubscribed = Code(http.StatusForbidden)
CodeIncompatibleVersion = Code(http.StatusConflict)
CodeMalformedRequest = Code(http.StatusBadRequest)
CodeUnsupportedMediaType = Code(http.StatusNotAcceptable)
CodeRateLimitExceeded = Code(http.StatusTooManyRequests)
CodeMesosUnavailable = Code(http.StatusServiceUnavailable)
CodeNotFound = Code(http.StatusNotFound)
MaxSizeDetails = 4 * 1024 // MaxSizeDetails limits the length of the details message read from a response body
)
var (
// ErrorTable maps HTTP response codes to their respective Mesos v1 API error messages.
ErrorTable = map[Code]string{
CodeNotLeader: MsgNotLeader,
CodeMalformedRequest: MsgMalformed,
CodeIncompatibleVersion: MsgVersion,
CodeUnsubscribed: MsgUnsubscribed,
CodeNotAuthenticated: MsgAuth,
CodeUnsupportedMediaType: MsgMediaType,
CodeNotFound: MsgNotFound,
CodeMesosUnavailable: MsgUnavailable,
CodeRateLimitExceeded: MsgRateLimit,
}
)
// Error captures HTTP v1 API error codes and messages generated by Mesos.
type Error struct {
code Code // code is the HTTP response status code generated by Mesos
message string // message briefly summarizes the nature of the error, possibly includes details from Mesos
}
// IsError returns true for all HTTP status codes that are not considered informational or successful.
func (code Code) IsError() bool {
return code >= 300
}
// FromResponse returns an `*Error` for a response containing a status code that indicates an error condition.
// The response body (if any) is captured in the Error.Details field.
// Returns nil for nil responses and responses with non-error status codes.
// See IsErrorCode.
func FromResponse(res *http.Response) error {
if res == nil {
return nil
}
code := Code(res.StatusCode)
if !code.IsError() {
// non-error HTTP response codes don't generate errors
return nil
}
var details string
if res.Body != nil {
defer res.Body.Close()
buf, _ := ioutil.ReadAll(io.LimitReader(res.Body, MaxSizeDetails))
details = string(buf)
}
return code.Error(details)
}
// Error generates an error from the given status code and detail string.
func (code Code) Error(details string) error {
if !code.IsError() {
return nil
}
err := &Error{
code: code,
message: ErrorTable[code],
}
if details != "" {
err.message = err.message + ": " + details
}
return err
}
// Error implements error interface
func (e *Error) Error() string { return e.message }
// Temporary returns true if the error is a temporary condition that should eventually clear.
func (e *Error) Temporary() bool {
switch e.code {
// TODO(jdef): NotFound **could** be a temporary error because there's a race at mesos startup in which the
// HTTP server responds before the internal listeners have been initialized. But it could also be reported
// because the client is accessing an invalid endpoint; as of right now, a client cannot distinguish between
// these cases.
// https://issues.apache.org/jira/browse/MESOS-7697
case CodeRateLimitExceeded, CodeMesosUnavailable:
return true
default:
return false
}
}
// CodesIndicatingSubscriptionLoss is a set of apierror.Code entries which each indicate that
// the event subscription stream has been severed between the scheduler and mesos. It's respresented
// as a public map variable so that clients can program additional error codes (if such are discovered)
// without hacking the code of the mesos-go library directly.
var CodesIndicatingSubscriptionLoss = func(codes ...Code) map[Code]struct{} {
result := make(map[Code]struct{}, len(codes))
for _, code := range codes {
result[code] = struct{}{}
}
return result
}(
// expand this list as we discover other errors that guarantee we've lost our event subscription.
CodeUnsubscribed,
)
// SubscriptionLoss returns true if the error indicates that the event subscription stream has been severed
// between mesos and a mesos client.
func (e *Error) SubscriptionLoss() (result bool) {
_, result = CodesIndicatingSubscriptionLoss[e.code]
return
}
// Matches returns true if the given error is an API error with a matching error code
func (code Code) Matches(err error) bool {
if err == nil {
return !code.IsError()
}
apiErr, ok := err.(*Error)
return ok && apiErr.code == code
}

View File

@@ -0,0 +1,33 @@
package httpcli
import (
"net/http"
)
// roundTripperFunc is the functional adaptation of http.RoundTripper
type roundTripperFunc func(*http.Request) (*http.Response, error)
// RoundTrip implements RoundTripper for roundTripperFunc
func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { return f(req) }
// BasicAuth generates a functional config option that sets HTTP Basic authentication for a Client
func BasicAuth(username, passwd string) ConfigOpt {
// TODO(jdef) this could be more efficient. according to the stdlib we're not supposed to
// mutate the original Request, so we copy here (including headers). another approach would
// be to generate a functional RequestOpt that adds the right header.
return WrapRoundTripper(func(rt http.RoundTripper) http.RoundTripper {
return roundTripperFunc(func(req *http.Request) (*http.Response, error) {
var h http.Header
if req.Header != nil {
h = make(http.Header, len(req.Header))
for k, v := range req.Header {
h[k] = append(make([]string, 0, len(v)), v...)
}
}
clonedReq := *req
clonedReq.Header = h
clonedReq.SetBasicAuth(username, passwd)
return rt.RoundTrip(&clonedReq)
})
})
}

View File

@@ -0,0 +1,614 @@
package httpcli
import (
"bytes"
"context"
"crypto/tls"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"sync"
"time"
"github.com/mesos/mesos-go/api/v1/lib"
"github.com/mesos/mesos-go/api/v1/lib/client"
logger "github.com/mesos/mesos-go/api/v1/lib/debug"
"github.com/mesos/mesos-go/api/v1/lib/encoding"
"github.com/mesos/mesos-go/api/v1/lib/encoding/codecs"
"github.com/mesos/mesos-go/api/v1/lib/encoding/framing"
"github.com/mesos/mesos-go/api/v1/lib/httpcli/apierrors"
"github.com/mesos/mesos-go/api/v1/lib/recordio"
)
func noRedirect(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }
// ProtocolError is returned when we receive a response from Mesos that is outside of the HTTP API specification.
// Receipt of the following will yield protocol errors:
// - any unexpected non-error HTTP response codes (e.g. 199)
// - any unexpected Content-Type
type ProtocolError string
// Error implements error interface
func (pe ProtocolError) Error() string { return string(pe) }
const (
debug = logger.Logger(false)
mediaTypeRecordIO = encoding.MediaType("application/recordio")
)
// DoFunc sends an HTTP request and returns an HTTP response.
//
// An error is returned if caused by client policy (such as
// http.Client.CheckRedirect), or if there was an HTTP protocol error. A
// non-2xx response doesn't cause an error.
//
// When err is nil, resp always contains a non-nil resp.Body.
//
// Callers should close resp.Body when done reading from it. If resp.Body is
// not closed, an underlying RoundTripper (typically Transport) may not be able
// to re-use a persistent TCP connection to the server for a subsequent
// "keep-alive" request.
//
// The request Body, if non-nil, will be closed by an underlying Transport,
// even on errors.
type DoFunc func(*http.Request) (*http.Response, error)
// Response captures the output of a Mesos HTTP API operation. Callers are responsible for invoking
// Close when they're finished processing the response otherwise there may be connection leaks.
type Response struct {
io.Closer
encoding.Decoder
Header http.Header
}
// ErrorMapperFunc generates an error for the given response.
type ErrorMapperFunc func(*http.Response) error
// ResponseHandler is invoked to process an HTTP response. Callers SHALL invoke Close for
// a non-nil Response, even when errors are returned.
type ResponseHandler func(*http.Response, client.ResponseClass, error) (mesos.Response, error)
// A Client is a Mesos HTTP APIs client.
type Client struct {
url string
do DoFunc
header http.Header
codec encoding.Codec
errorMapper ErrorMapperFunc
requestOpts []RequestOpt
buildRequestFunc func(client.Request, client.ResponseClass, ...RequestOpt) (*http.Request, error)
handleResponse ResponseHandler
}
var (
DefaultCodec = codecs.ByMediaType[codecs.MediaTypeProtobuf]
DefaultHeaders = http.Header{}
// DefaultConfigOpt represents the default client config options.
DefaultConfigOpt = []ConfigOpt{
Transport(func(t *http.Transport) {
// all calls should be ack'd by the server within this interval.
t.ResponseHeaderTimeout = 15 * time.Second
t.MaxIdleConnsPerHost = 2 // don't depend on go's default
}),
}
DefaultErrorMapper = ErrorMapperFunc(apierrors.FromResponse)
)
// New returns a new Client with the given Opts applied.
// Callers are expected to configure the URL, Do, and Codec options prior to
// invoking Do.
func New(opts ...Opt) *Client {
c := &Client{
codec: DefaultCodec,
do: With(DefaultConfigOpt...),
header: cloneHeaders(DefaultHeaders),
errorMapper: DefaultErrorMapper,
}
c.buildRequestFunc = c.buildRequest
c.handleResponse = c.HandleResponse
c.With(opts...)
return c
}
func cloneHeaders(hs http.Header) http.Header {
result := make(http.Header)
for k, v := range hs {
cloned := make([]string, len(v))
copy(cloned, v)
result[k] = cloned
}
return result
}
// Endpoint returns the current Mesos API endpoint URL that the caller is set to invoke
func (c *Client) Endpoint() string {
return c.url
}
// RequestOpt defines a functional option for an http.Request.
type RequestOpt func(*http.Request)
// RequestOpts is a convenience type
type RequestOpts []RequestOpt
// Apply this set of request options to the given HTTP request.
func (opts RequestOpts) Apply(req *http.Request) {
// apply per-request options
for _, o := range opts {
if o != nil {
o(req)
}
}
}
// With applies the given Opts to a Client and returns itself.
func (c *Client) With(opts ...Opt) Opt {
return Opts(opts).Merged().Apply(c)
}
// WithTemporary configures the Client with the temporary option and returns the results of
// invoking f(). Changes made to the Client by the temporary option are reverted before this
// func returns.
func (c *Client) WithTemporary(opt Opt, f func() error) error {
if opt != nil {
undo := c.With(opt)
defer c.With(undo)
}
return f()
}
// Mesos returns a mesos.Client variant backed by this implementation.
// Deprecated.
func (c *Client) Mesos(opts ...RequestOpt) mesos.Client {
return mesos.ClientFunc(func(m encoding.Marshaler) (mesos.Response, error) {
return c.Do(m, opts...)
})
}
func prepareForResponse(rc client.ResponseClass, codec encoding.Codec) (RequestOpts, error) {
// We need to tell Mesos both the content-type and message-content-type that we're expecting, otherwise
// the server may give us validation problems, or else send back a vague content-type (w/o a
// message-content-type). In order to communicate these things we need to understand the desired response
// type from the perspective of the caller --> client.ResponseClass.
var accept RequestOpts
switch rc {
case client.ResponseClassSingleton, client.ResponseClassAuto, client.ResponseClassNoData:
accept = append(accept, Header("Accept", codec.Type.ContentType()))
case client.ResponseClassStreaming:
accept = append(accept, Header("Accept", mediaTypeRecordIO.ContentType()))
accept = append(accept, Header("Message-Accept", codec.Type.ContentType()))
default:
return nil, ProtocolError(fmt.Sprintf("illegal response class requested: %v", rc))
}
return accept, nil
}
// buildRequest is a factory func that generates and returns an http.Request for the
// given marshaler and request options.
func (c *Client) buildRequest(cr client.Request, rc client.ResponseClass, opt ...RequestOpt) (*http.Request, error) {
if crs, ok := cr.(client.RequestStreaming); ok {
return c.buildRequestStream(crs.Marshaler, rc, opt...)
}
accept, err := prepareForResponse(rc, c.codec)
if err != nil {
return nil, err
}
//TODO(jdef): use a pool to allocate these (and reduce garbage)?
// .. or else, use a pipe (like streaming does) to avoid the intermediate buffer?
var body bytes.Buffer
if err := c.codec.NewEncoder(encoding.SinkWriter(&body)).Encode(cr.Marshaler()); err != nil {
return nil, err
}
req, err := http.NewRequest("POST", c.url, &body)
if err != nil {
return nil, err
}
helper := HTTPRequestHelper{req}
return helper.
withOptions(c.requestOpts, opt).
withHeaders(c.header).
withHeader("Content-Type", c.codec.Type.ContentType()).
withHeader("Accept", c.codec.Type.ContentType()).
withOptions(accept).
Request, nil
}
func (c *Client) buildRequestStream(f func() encoding.Marshaler, rc client.ResponseClass, opt ...RequestOpt) (*http.Request, error) {
accept, err := prepareForResponse(rc, c.codec)
if err != nil {
return nil, err
}
var (
pr, pw = io.Pipe()
enc = c.codec.NewEncoder(func() framing.Writer { return recordio.NewWriter(pw) })
)
req, err := http.NewRequest("POST", c.url, pr)
if err != nil {
pw.Close() // ignore error
return nil, err
}
go func() {
var closeOnce sync.Once
defer closeOnce.Do(func() {
pw.Close()
})
for {
m := f()
if m == nil {
// no more messages to send; end of the stream
break
}
err := enc.Encode(m)
if err != nil {
closeOnce.Do(func() {
pw.CloseWithError(err)
})
break
}
}
}()
helper := HTTPRequestHelper{req}
return helper.
withOptions(c.requestOpts, opt).
withHeaders(c.header).
withHeader("Content-Type", mediaTypeRecordIO.ContentType()).
withHeader("Message-Content-Type", c.codec.Type.ContentType()).
withOptions(accept).
Request, nil
}
func validateSuccessfulResponse(codec encoding.Codec, res *http.Response, rc client.ResponseClass) error {
switch res.StatusCode {
case http.StatusOK:
ct := res.Header.Get("Content-Type")
switch rc {
case client.ResponseClassNoData:
if ct != "" {
return ProtocolError(fmt.Sprintf("unexpected content type: %q", ct))
}
case client.ResponseClassSingleton, client.ResponseClassAuto:
if ct != codec.Type.ContentType() {
return ProtocolError(fmt.Sprintf("unexpected content type: %q", ct))
}
case client.ResponseClassStreaming:
if ct != mediaTypeRecordIO.ContentType() {
return ProtocolError(fmt.Sprintf("unexpected content type: %q", ct))
}
ct = res.Header.Get("Message-Content-Type")
if ct != codec.Type.ContentType() {
return ProtocolError(fmt.Sprintf("unexpected message content type: %q", ct))
}
default:
return ProtocolError(fmt.Sprintf("unsupported response-class: %q", rc))
}
case http.StatusAccepted:
// nothing to validate, we're not expecting any response entity in this case.
// TODO(jdef) perhaps check Content-Length == 0 here?
}
return nil
}
func newSourceFactory(rc client.ResponseClass) encoding.SourceFactoryFunc {
switch rc {
case client.ResponseClassNoData:
return nil
case client.ResponseClassSingleton:
return encoding.SourceReader
case client.ResponseClassStreaming, client.ResponseClassAuto:
return recordIOSourceFactory
default:
panic(fmt.Sprintf("unsupported response-class: %q", rc))
}
}
func recordIOSourceFactory(r io.Reader) encoding.Source {
return func() framing.Reader { return recordio.NewReader(r) }
}
// HandleResponse parses an HTTP response from a Mesos service endpoint, transforming the
// raw HTTP response into a mesos.Response.
func (c *Client) HandleResponse(res *http.Response, rc client.ResponseClass, err error) (mesos.Response, error) {
if err != nil {
if res != nil && res.Body != nil {
res.Body.Close()
}
return nil, err
}
result := &Response{
Closer: res.Body,
Header: res.Header,
}
if err = c.errorMapper(res); err != nil {
return result, err
}
err = validateSuccessfulResponse(c.codec, res, rc)
if err != nil {
res.Body.Close()
return nil, err
}
switch res.StatusCode {
case http.StatusOK:
debug.Log("request OK, decoding response")
sf := newSourceFactory(rc)
if sf == nil {
if rc != client.ResponseClassNoData {
panic("nil Source for response that expected data")
}
// we don't expect any data. drain the response body and close it (compliant with golang's expectations
// for http/1.1 keepalive support.
defer res.Body.Close()
_, err = io.Copy(ioutil.Discard, res.Body)
return nil, err
}
result.Decoder = c.codec.NewDecoder(sf.NewSource(res.Body))
case http.StatusAccepted:
debug.Log("request Accepted")
// noop; no decoder for these types of calls
defer res.Body.Close()
_, err = io.Copy(ioutil.Discard, res.Body)
return nil, err
default:
debug.Log("unexpected HTTP status", res.StatusCode)
defer res.Body.Close()
io.Copy(ioutil.Discard, res.Body) // intentionally discard any error here
return nil, ProtocolError(fmt.Sprintf("unexpected mesos HTTP response code: %d", res.StatusCode))
}
return result, nil
}
// Do is deprecated in favor of Send.
func (c *Client) Do(m encoding.Marshaler, opt ...RequestOpt) (res mesos.Response, err error) {
return c.Send(client.RequestSingleton(m), client.ResponseClassAuto, opt...)
}
// Send sends a Call and returns (a) a Response (should be closed when finished) that
// contains a either a streaming or non-streaming Decoder from which callers can read
// objects from, and; (b) an error in case of failure. Callers are expected to *always*
// close a non-nil Response if one is returned. For operations which are successful but
// also for which there are no expected result objects the embedded Decoder will be nil.
// The provided ResponseClass determines whether the client implementation will attempt
// to decode a result as a single obeject or as an object stream. When working with
// versions of Mesos prior to v1.2.x callers MUST use ResponseClassAuto.
func (c *Client) Send(cr client.Request, rc client.ResponseClass, opt ...RequestOpt) (res mesos.Response, err error) {
var (
hreq *http.Request
hres *http.Response
)
hreq, err = c.buildRequestFunc(cr, rc, opt...)
if err == nil {
hres, err = c.do(hreq)
res, err = c.handleResponse(hres, rc, err)
}
return
}
// ErrorMapper returns am Opt that overrides the existing error mapping behavior of the client.
func ErrorMapper(em ErrorMapperFunc) Opt {
return func(c *Client) Opt {
old := c.errorMapper
c.errorMapper = em
return ErrorMapper(old)
}
}
// Endpoint returns an Opt that sets a Client's URL.
func Endpoint(rawurl string) Opt {
return func(c *Client) Opt {
old := c.url
c.url = rawurl
return Endpoint(old)
}
}
// WrapDoer returns an Opt that decorates a Client's DoFunc
func WrapDoer(f func(DoFunc) DoFunc) Opt {
return func(c *Client) Opt {
old := c.do
c.do = f(c.do)
return Do(old)
}
}
// Do returns an Opt that sets a Client's DoFunc
func Do(do DoFunc) Opt {
return func(c *Client) Opt {
old := c.do
c.do = do
return Do(old)
}
}
// Codec returns an Opt that sets a Client's Codec.
func Codec(codec encoding.Codec) Opt {
return func(c *Client) Opt {
old := c.codec
c.codec = codec
return Codec(old)
}
}
// DefaultHeader returns an Opt that adds a header to an Client's headers.
func DefaultHeader(k, v string) Opt {
return func(c *Client) Opt {
old, found := c.header[k]
old = append([]string{}, old...) // clone
c.header.Add(k, v)
return func(c *Client) Opt {
if found {
c.header[k] = old
} else {
c.header.Del(k)
}
return DefaultHeader(k, v)
}
}
}
// HandleResponse returns a functional config option to set the HTTP response handler of the client.
func HandleResponse(f ResponseHandler) Opt {
return func(c *Client) Opt {
old := c.handleResponse
c.handleResponse = f
return HandleResponse(old)
}
}
// RequestOptions returns an Opt that applies the given set of options to every Client request.
func RequestOptions(opts ...RequestOpt) Opt {
if len(opts) == 0 {
return nil
}
return func(c *Client) Opt {
old := append([]RequestOpt{}, c.requestOpts...)
c.requestOpts = opts
return RequestOptions(old...)
}
}
// Header returns an RequestOpt that adds a header value to an HTTP requests's header.
func Header(k, v string) RequestOpt { return func(r *http.Request) { r.Header.Add(k, v) } }
// Close returns a RequestOpt that determines whether to close the underlying connection after sending the request.
func Close(b bool) RequestOpt { return func(r *http.Request) { r.Close = b } }
// Context returns a RequestOpt that sets the request's Context (ctx must be non-nil)
func Context(ctx context.Context) RequestOpt {
return func(r *http.Request) {
r2 := r.WithContext(ctx)
*r = *r2
}
}
type Config struct {
client *http.Client
dialer *net.Dialer
transport *http.Transport
}
type ConfigOpt func(*Config)
// With returns a DoFunc that executes HTTP round-trips.
// The default implementation provides reasonable defaults for timeouts:
// keep-alive, connection, request/response read/write, and TLS handshake.
// Callers can customize configuration by specifying one or more ConfigOpt's.
func With(opt ...ConfigOpt) DoFunc {
var (
dialer = &net.Dialer{
LocalAddr: &net.TCPAddr{IP: net.IPv4zero},
KeepAlive: 30 * time.Second,
Timeout: 5 * time.Second,
}
transport = &http.Transport{
Proxy: http.ProxyFromEnvironment,
Dial: dialer.Dial,
ResponseHeaderTimeout: 5 * time.Second,
TLSClientConfig: &tls.Config{InsecureSkipVerify: false},
TLSHandshakeTimeout: 5 * time.Second,
}
config = &Config{
dialer: dialer,
transport: transport,
client: &http.Client{
Transport: transport,
CheckRedirect: noRedirect, // so we can actually see the 307 redirects
},
}
)
for _, o := range opt {
if o != nil {
o(config)
}
}
return config.client.Do
}
// Timeout returns an ConfigOpt that sets a Config's response header timeout, tls handshake timeout,
// and dialer timeout.
func Timeout(d time.Duration) ConfigOpt {
return func(c *Config) {
c.transport.ResponseHeaderTimeout = d
c.transport.TLSHandshakeTimeout = d
c.dialer.Timeout = d
}
}
// RoundTripper returns a ConfigOpt that sets a Config's round-tripper.
func RoundTripper(rt http.RoundTripper) ConfigOpt {
return func(c *Config) {
c.client.Transport = rt
}
}
// TLSConfig returns a ConfigOpt that sets a Config's TLS configuration.
func TLSConfig(tc *tls.Config) ConfigOpt {
return func(c *Config) {
c.transport.TLSClientConfig = tc
}
}
// Transport returns a ConfigOpt that allows tweaks of the default Config's http.Transport
func Transport(modifyTransport func(*http.Transport)) ConfigOpt {
return func(c *Config) {
if modifyTransport != nil {
modifyTransport(c.transport)
}
}
}
// WrapRoundTripper allows a caller to customize a configuration's HTTP exchanger. Useful
// for authentication protocols that operate over stock HTTP.
func WrapRoundTripper(f func(http.RoundTripper) http.RoundTripper) ConfigOpt {
return func(c *Config) {
if f != nil {
if rt := f(c.client.Transport); rt != nil {
c.client.Transport = rt
}
}
}
}
// HTTPRequestHelper wraps an http.Request and provides utility funcs to simplify code elsewhere
type HTTPRequestHelper struct {
*http.Request
}
func (r *HTTPRequestHelper) withOptions(optsets ...RequestOpts) *HTTPRequestHelper {
for _, opts := range optsets {
opts.Apply(r.Request)
}
return r
}
func (r *HTTPRequestHelper) withHeaders(hh http.Header) *HTTPRequestHelper {
for k, v := range hh {
r.Header[k] = v
debug.Log("request header " + k + ": " + v[0])
}
return r
}
func (r *HTTPRequestHelper) withHeader(key, value string) *HTTPRequestHelper {
r.Header.Set(key, value)
return r
}

View File

@@ -0,0 +1,53 @@
package httpcli
type (
// Opt defines a functional option for the HTTP client type. A functional option
// must return an Opt that acts as an "undo" if applied to the same Client.
Opt func(*Client) Opt
// Opts represents a series of functional options
Opts []Opt
)
// Apply is a nil-safe application of an Opt: if the receiver is nil then this func
// simply returns nil, otherwise it returns the result invoking the receiving Opt
// with the given Client.
func (o Opt) Apply(c *Client) (result Opt) {
if o != nil {
result = o(c)
}
return
}
// Merged generates a single Opt that applies all the functional options, in-order
func (opts Opts) Merged() Opt {
if len(opts) == 0 {
return nil
}
return func(c *Client) Opt {
var (
size = len(opts)
undo = make(Opts, size)
)
size-- // make this a zero-based offset
for i, opt := range opts {
if opt != nil {
undo[size-i] = opt(c)
}
}
return undo.Merged()
}
}
// And combines two functional options into a single Opt
func (o Opt) And(other Opt) Opt {
if o == nil {
if other == nil {
return nil
}
return other
}
if other == nil {
return o
}
return Opts{o, other}.Merged()
}

95
vendor/github.com/mesos/mesos-go/api/v1/lib/labels.go generated vendored Normal file
View File

@@ -0,0 +1,95 @@
package mesos
import (
"bytes"
"io"
)
type labelList []Label // convenience type, for working with unwrapped Label slices
// Equivalent returns true if left and right have the same labels. Order is not important.
func (left *Labels) Equivalent(right *Labels) bool {
return labelList(left.GetLabels()).Equivalent(labelList(right.GetLabels()))
}
// Equivalent returns true if left and right have the same labels. Order is not important.
func (left labelList) Equivalent(right labelList) bool {
if len(left) != len(right) {
return false
} else {
for i := range left {
found := false
for j := range right {
if left[i].Equivalent(right[j]) {
found = true
break
}
}
if !found {
return false
}
}
return true
}
}
// Equivalent returns true if left and right represent the same Label.
func (left Label) Equivalent(right Label) bool {
if left.Key != right.Key {
return false
}
if left.Value == nil {
return right.Value == nil
} else {
return right.Value != nil && *left.Value == *right.Value
}
}
func (left Label) writeTo(w io.Writer) (n int64, err error) {
write := func(s string) {
if err != nil {
return
}
var n2 int
n2, err = io.WriteString(w, s)
n += int64(n2)
}
write(left.Key)
if s := left.GetValue(); s != "" {
write("=")
write(s)
}
return
}
func (left *Labels) writeTo(w io.Writer) (n int64, err error) {
var (
lab = left.GetLabels()
n2 int
n3 int64
)
for i := range lab {
if i > 0 {
n2, err = io.WriteString(w, ",")
n += int64(n2)
if err != nil {
break
}
}
n3, err = lab[i].writeTo(w)
n += n3
if err != nil {
break
}
}
return
}
func (left *Labels) Format() string {
if left == nil {
return ""
}
var b bytes.Buffer
left.writeTo(&b)
return b.String()
}

72498
vendor/github.com/mesos/mesos-go/api/v1/lib/mesos.pb.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

3600
vendor/github.com/mesos/mesos-go/api/v1/lib/mesos.proto generated vendored Normal file

File diff suppressed because it is too large Load Diff

253
vendor/github.com/mesos/mesos-go/api/v1/lib/ranges.go generated vendored Normal file
View File

@@ -0,0 +1,253 @@
package mesos
import (
"sort"
)
// Ranges represents a list of Ranges.
type Ranges []Value_Range
// NewRanges returns squashed Ranges from the given numbers.
func NewRanges(ns ...uint64) Ranges {
xs := append(uint64s{}, ns...)
sort.Sort(xs)
rs := make(Ranges, len(xs))
for i := range xs {
rs[i].Begin, rs[i].End = xs[i], xs[i]
}
return rs.Squash()
}
// NewPortRanges returns Ranges from the "ports" resource in the
// given *Offer. If that resource isn't provided, nil will be returned.
//
// The returned Ranges are sorted and have all overlapping ranges merged from
// left to right. e.g. [[0, 5], [4, 3], [10, 7]] -> [[0, 5], [7, 10]]
func NewPortRanges(o *Offer) Ranges {
if o == nil {
return Ranges{}
}
var (
r Resource
found bool
)
for i := range o.Resources {
if o.Resources[i].GetName() == "ports" {
r = o.Resources[i]
found = true
break
}
}
if !found {
return Ranges{}
}
offered := r.GetRanges().GetRange()
rs := make(Ranges, len(offered))
for i, r := range offered {
if lo, hi := r.GetBegin(), r.GetEnd(); lo <= hi {
rs[i].Begin, rs[i].End = lo, hi
} else {
rs[i].Begin, rs[i].End = hi, lo
}
}
return rs.Sort().Squash()
}
// These three methods implement sort.Interface
func (rs Ranges) Len() int { return len(rs) }
func (rs Ranges) Swap(i, j int) { rs[i], rs[j] = rs[j], rs[i] }
func (rs Ranges) Less(i, j int) bool {
return rs[i].Begin < rs[j].Begin || (rs[i].Begin == rs[j].Begin && rs[i].End < rs[j].End)
}
// Size returns the sum of the Size of all Ranges.
func (rs Ranges) Size() uint64 {
var sz uint64
for i := range rs {
sz += 1 + (rs[i].End - rs[i].Begin)
}
return sz
}
// Sort sorts the receiving Ranges and returns the result; convenience
func (rs Ranges) Sort() Ranges {
sort.Sort(rs)
return rs
}
// Squash merges overlapping and continuous Ranges. It assumes they're pre-sorted.
func (rs Ranges) Squash() Ranges {
if len(rs) < 2 {
return rs
}
squashed := Ranges{rs[0]}
for i := 1; i < len(rs); i++ {
switch max := squashed[len(squashed)-1].End; {
case 1+max < rs[i].Begin: // no overlap nor continuity: push
squashed = append(squashed, rs[i])
case max <= rs[i].End: // overlap or continuity: squash
squashed[len(squashed)-1].End = rs[i].End
}
}
return squashed
}
// Search performs a binary search for n returning the index of the Range it was
// found at or -1 if not found.
func (rs Ranges) Search(n uint64) int {
for lo, hi := 0, len(rs)-1; lo <= hi; {
switch m := lo + (hi-lo)/2; {
case n < rs[m].Begin:
hi = m - 1
case n > rs[m].End:
lo = m + 1
default:
return m
}
}
return -1
}
// Partition partitions Ranges around n. It returns the partitioned Ranges
// and a boolean indicating if n was found.
func (rs Ranges) Partition(n uint64) (Ranges, bool) {
i := rs.Search(n)
if i < 0 {
return rs, false
}
pn := make(Ranges, 0, len(rs)+1)
switch pn = append(pn, rs[:i]...); {
case rs[i].Begin == rs[i].End: // delete
case rs[i].Begin == n: // increment lower bound
pn = append(pn, Value_Range{rs[i].Begin + 1, rs[i].End})
case rs[i].End == n: // decrement upper bound
pn = append(pn, Value_Range{rs[i].Begin, rs[i].End - 1})
default: // split
pn = append(pn, Value_Range{rs[i].Begin, n - 1}, Value_Range{n + 1, rs[i].End})
}
return append(pn, rs[i+1:]...), true
}
// Remove removes a range from already coalesced ranges.
// The algorithms constructs a new vector of ranges which is then
// Squash'ed into a Ranges instance.
func (rs Ranges) Remove(removal Value_Range) Ranges {
ranges := make([]Value_Range, 0, len(rs))
for _, r := range rs {
// skip if the entire range is subsumed by removal
if r.Begin >= removal.Begin && r.End <= removal.End {
continue
}
// divide if the range subsumes the removal
if r.Begin < removal.Begin && r.End > removal.End {
ranges = append(ranges,
Value_Range{r.Begin, removal.Begin - 1},
Value_Range{removal.End + 1, r.End},
)
continue
}
// add the full range if there's no intersection
if r.End < removal.Begin || r.Begin > removal.End {
ranges = append(ranges, r)
continue
}
// trim if the range does intersect
if r.End > removal.End {
ranges = append(ranges, Value_Range{removal.End + 1, r.End})
} else {
if r.Begin >= removal.Begin {
// should never happen
panic("r.Begin >= removal.Begin")
}
ranges = append(ranges, Value_Range{r.Begin, removal.Begin - 1})
}
}
return Ranges(ranges).Squash()
}
// Compare assumes that both Ranges are already in sort-order.
// Returns 0 if rs and right are equivalent, -1 if rs is a subset of right, or else 1
func (rs Ranges) Compare(right Ranges) int {
x, y, result := rs.equiv(right)
if result {
return 0
}
for _, a := range x {
// make sure that this range is a subset of a range in y
matched := false
for _, b := range y {
if a.Begin >= b.Begin && a.End <= b.End {
matched = true
break
}
}
if !matched {
return 1
}
}
return -1
}
// Equivalent assumes that both Ranges are already in sort-order.
func (rs Ranges) Equivalent(right Ranges) (result bool) {
_, _, result = rs.equiv(right)
return
}
// Equivalent assumes that both Ranges are already in sort-order.
func (rs Ranges) equiv(right Ranges) (_, _ Ranges, _ bool) {
// we need to squash rs and right but don't want to change the originals
switch len(rs) {
case 0:
case 1:
rs = Ranges{rs[0]}
default:
rs = Ranges(append([]Value_Range{rs[0], rs[1]}, rs[2:]...)).Sort().Squash()
}
switch len(right) {
case 0:
case 1:
right = Ranges{right[0]}
default:
right = Ranges(append([]Value_Range{right[0], right[1]}, right[2:]...)).Sort().Squash()
}
return rs, right, (&Value_Ranges{Range: rs}).Equal(&Value_Ranges{Range: right})
}
func (rs Ranges) Clone() Ranges {
if len(rs) == 0 {
return nil
}
x := make(Ranges, len(rs))
copy(x, rs)
return x
}
// Min returns the minimum number in Ranges. It will panic on empty Ranges.
func (rs Ranges) Min() uint64 { return rs[0].Begin }
// Max returns the maximum number in Ranges. It will panic on empty Ranges.
func (rs Ranges) Max() uint64 { return rs[len(rs)-1].End }
// resource returns a *Resource with the given name and Ranges.
func (rs Ranges) resource(name string) Resource {
vr := make([]Value_Range, len(rs))
copy(vr, rs)
return Resource{
Name: name,
Type: RANGES.Enum(),
Ranges: &Value_Ranges{Range: vr},
}
}
// uint64s is an utility used to sort a slice of uint64s
type uint64s []uint64
// These three methods implement sort.Interface
func (ns uint64s) Len() int { return len(ns) }
func (ns uint64s) Less(i, j int) bool { return ns[i] < ns[j] }
func (ns uint64s) Swap(i, j int) { ns[i], ns[j] = ns[j], ns[i] }

View File

@@ -0,0 +1,32 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"reader.go",
"strconv.go",
"writer.go",
],
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/recordio",
importpath = "github.com/mesos/mesos-go/api/v1/lib/recordio",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/mesos/mesos-go/api/v1/lib/debug:go_default_library",
"//vendor/github.com/mesos/mesos-go/api/v1/lib/encoding/framing:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,5 @@
// Package recordio implements the Mesos variant of RecordIO framing, whereby
// each record is prefixed by a line that indicates the length of the record in
// decimal ASCII. The bytes of the record immediately follow the length-line.
// Zero-length records are allowed.
package recordio

View File

@@ -0,0 +1,145 @@
package recordio
import (
"bufio"
"bytes"
"io"
logger "github.com/mesos/mesos-go/api/v1/lib/debug"
"github.com/mesos/mesos-go/api/v1/lib/encoding/framing"
)
const debug = logger.Logger(false)
type (
Opt func(*reader)
reader struct {
*bufio.Scanner
pend int
splitf func(data []byte, atEOF bool) (int, []byte, error)
maxf int // max frame size
}
)
// NewReader returns a reader that parses frames from a recordio stream.
func NewReader(read io.Reader, opt ...Opt) framing.Reader {
debug.Log("new frame reader")
r := &reader{Scanner: bufio.NewScanner(read)}
r.Split(func(data []byte, atEOF bool) (int, []byte, error) {
// Scanner panics if we invoke Split after scanning has started,
// use this proxy func as a work-around.
return r.splitf(data, atEOF)
})
buf := make([]byte, 16*1024)
r.Buffer(buf, 1<<22) // 1<<22 == max protobuf size
r.splitf = r.splitSize
// apply options
for _, f := range opt {
if f != nil {
f(r)
}
}
return r
}
// MaxMessageSize returns a functional option that configures the internal Scanner's buffer and max token (message)
// length, in bytes.
func MaxMessageSize(max int) Opt {
return func(r *reader) {
buf := make([]byte, max>>1)
r.Buffer(buf, max)
r.maxf = max
}
}
func (r *reader) splitSize(data []byte, atEOF bool) (int, []byte, error) {
const maxTokenLength = 20 // textual length of largest uint64 number
if atEOF {
x := len(data)
switch {
case x == 0:
debug.Log("EOF and empty frame, returning io.EOF")
return 0, nil, io.EOF
case x < 2: // min frame size
debug.Log("remaining data less than min total frame length")
return 0, nil, framing.ErrorUnderrun
}
// otherwise, we may have a valid frame...
}
debug.Log("len(data)=", len(data))
adv := 0
for {
i := 0
for ; i < maxTokenLength && i < len(data) && data[i] != '\n'; i++ {
}
debug.Log("i=", i)
if i == len(data) {
debug.Log("need more input")
return 0, nil, nil // need more input
}
if i == maxTokenLength && data[i] != '\n' {
debug.Log("frame size: max token length exceeded")
return 0, nil, framing.ErrorBadSize
}
n, err := ParseUintBytes(bytes.TrimSpace(data[:i]), 10, 64)
if err != nil {
debug.Log("failed to parse frame size field:", err)
return 0, nil, framing.ErrorBadSize
}
if r.maxf != 0 && int(n) > r.maxf {
debug.Log("frame size max length exceeded:", n)
return 0, nil, framing.ErrorOversizedFrame
}
if n == 0 {
// special case... don't invoke splitData, just parse the next size header
adv += i + 1
data = data[i+1:]
continue
}
r.pend = int(n)
r.splitf = r.splitFrame
debug.Logf("split next frame: %d, %d", n, adv+i+1)
return adv + i + 1, data[:0], nil // returning a nil token screws up the Scanner, so return empty
}
}
func (r *reader) splitFrame(data []byte, atEOF bool) (advance int, token []byte, err error) {
x := len(data)
debug.Log("splitFrame:x=", x, ",eof=", atEOF)
if atEOF {
if x < r.pend {
return 0, nil, framing.ErrorUnderrun
}
}
if r.pend == 0 {
panic("asked to read frame data, but no data left in frame")
}
if x < int(r.pend) {
// need more data
return 0, nil, nil
}
r.splitf = r.splitSize
adv := int(r.pend)
r.pend = 0
return adv, data[:adv], nil
}
// ReadFrame implements framing.Reader
func (r *reader) ReadFrame() (tok []byte, err error) {
for r.Scan() {
b := r.Bytes()
if len(b) == 0 {
continue
}
tok = b
debug.Log("len(tok)", len(tok))
break
}
// either scan failed, or it succeeded and we have a token...
err = r.Err()
if err == nil && len(tok) == 0 {
err = io.EOF
}
return
}

View File

@@ -0,0 +1,117 @@
/*
Copyright 2013 The Camlistore Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package recordio
import (
"errors"
"strconv"
)
// ParseUintBytes is like strconv.ParseUint, but using a []byte.
func ParseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) {
var cutoff, maxVal uint64
if bitSize == 0 {
bitSize = int(strconv.IntSize)
}
s0 := s
switch {
case len(s) < 1:
err = strconv.ErrSyntax
goto Error
case 2 <= base && base <= 36:
// valid base; nothing to do
case base == 0:
// Look for octal, hex prefix.
switch {
case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
base = 16
s = s[2:]
if len(s) < 1 {
err = strconv.ErrSyntax
goto Error
}
case s[0] == '0':
base = 8
default:
base = 10
}
default:
err = errors.New("invalid base " + strconv.Itoa(base))
goto Error
}
n = 0
cutoff = cutoff64(base)
maxVal = 1<<uint(bitSize) - 1
for i := 0; i < len(s); i++ {
var v byte
d := s[i]
switch {
case '0' <= d && d <= '9':
v = d - '0'
case 'a' <= d && d <= 'z':
v = d - 'a' + 10
case 'A' <= d && d <= 'Z':
v = d - 'A' + 10
default:
n = 0
err = strconv.ErrSyntax
goto Error
}
if int(v) >= base {
n = 0
err = strconv.ErrSyntax
goto Error
}
if n >= cutoff {
// n*base overflows
n = 1<<64 - 1
err = strconv.ErrRange
goto Error
}
n *= uint64(base)
n1 := n + uint64(v)
if n1 < n || n1 > maxVal {
// n+v overflows
n = 1<<64 - 1
err = strconv.ErrRange
goto Error
}
n = n1
}
return n, nil
Error:
return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err}
}
// Return the first number n such that n*base >= 1<<64.
func cutoff64(base int) uint64 {
if base < 2 {
return 0
}
return (1<<64-1)/uint64(base) + 1
}

View File

@@ -0,0 +1,34 @@
package recordio
import (
"io"
"strconv"
)
var lf = []byte{'\n'}
type Writer struct {
out io.Writer
}
func NewWriter(out io.Writer) *Writer {
return &Writer{out}
}
func (w *Writer) writeBuffer(b []byte, err error) error {
if err != nil {
return err
}
n, err := w.out.Write(b)
if err == nil && n != len(b) {
return io.ErrShortWrite
}
return err
}
func (w *Writer) WriteFrame(b []byte) (err error) {
err = w.writeBuffer(([]byte)(strconv.Itoa(len(b))), err)
err = w.writeBuffer(lf, err)
err = w.writeBuffer(b, err)
return
}

1145
vendor/github.com/mesos/mesos-go/api/v1/lib/resources.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["role.go"],
importmap = "k8s.io/kubernetes/vendor/github.com/mesos/mesos-go/api/v1/lib/roles",
importpath = "github.com/mesos/mesos-go/api/v1/lib/roles",
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,82 @@
package roles
import (
"fmt"
"strings"
"unicode"
)
// Role is a deprecated type.
type Role string
const defaultRole = Role("*")
func (r Role) IsDefault() bool {
return r == defaultRole
}
func (r Role) Assign() func(interface{}) {
return func(v interface{}) {
type roler interface {
WithRole(string)
}
if ri, ok := v.(roler); ok {
ri.WithRole(string(r))
}
}
}
func (r Role) Proto() *string {
s := string(r)
return &s
}
// IsStrictSubroleOf returns true if left is a strict subrole of right.
func IsStrictSubroleOf(left, right string) bool {
return len(left) > len(right) && left[len(right)] == '/' && strings.HasPrefix(left, right)
}
var illegalComponents = map[string]struct{}{
".": struct{}{},
"..": struct{}{},
"*": struct{}{},
}
func Parse(s string) (string, error) {
if s == string(defaultRole) {
return s, nil
}
if strings.HasPrefix(s, "/") {
return "", fmt.Errorf("role %q cannot start with a slash", s)
}
if strings.HasSuffix(s, "/") {
return "", fmt.Errorf("role %q cannot end with a slash", s)
}
// validate each component in the role path
for _, part := range strings.Split(s, "/") {
if part == "" {
return "", fmt.Errorf("role %q cannot contain two adjacent slashes", s)
}
if bad, found := illegalComponents[part]; found {
return "", fmt.Errorf("role %q cannot contain %q as a component", s, bad)
}
if strings.HasPrefix(part, "-") {
return "", fmt.Errorf("role component %q is invalid because it begins with a dash", part)
}
if strings.IndexFunc(part, func(r rune) bool { return unicode.IsSpace(r) || unicode.IsControl(r) }) > -1 {
return "", fmt.Errorf("role component %q is invalid because it contains backspace or whitespace", part)
}
}
return s, nil
}
func Validate(roles ...string) error {
for i := range roles {
_, err := Parse(roles[i])
if err != nil {
return err
}
}
return nil
}

142
vendor/github.com/mesos/mesos-go/api/v1/lib/values.go generated vendored Normal file
View File

@@ -0,0 +1,142 @@
package mesos
func (left *Value_Scalar) Compare(right *Value_Scalar) int {
var (
a = convertToFixed64(left.GetValue())
b = convertToFixed64(right.GetValue())
)
if a < b {
return -1
}
if a > b {
return 1
}
return 0
}
func (left *Value_Ranges) Compare(right *Value_Ranges) int {
return Ranges(left.GetRange()).Compare(right.GetRange())
}
func (left *Value_Set) Compare(right *Value_Set) int {
i, j := left.GetItem(), right.GetItem()
if len(i) <= len(j) {
b := make(map[string]struct{}, len(j))
for _, x := range j {
b[x] = struct{}{}
}
// make sure that each item on the left exists on the right,
// otherwise left is not a subset of right.
a := make(map[string]struct{}, len(i))
for _, x := range i {
if _, ok := b[x]; !ok {
return 1
}
a[x] = struct{}{}
}
// if every item on the right also exists on the left, then
// the sets are equal, otherwise left < right
for x := range b {
if _, ok := a[x]; !ok {
return -1
}
}
return 0
}
return 1
}
func (left *Value_Set) Add(right *Value_Set) *Value_Set {
lefty := left.GetItem()
righty := right.GetItem()
c := len(lefty) + len(righty)
if c == 0 {
return nil
}
m := make(map[string]struct{}, c)
for _, v := range lefty {
m[v] = struct{}{}
}
for _, v := range righty {
m[v] = struct{}{}
}
x := make([]string, 0, len(m))
for v := range m {
x = append(x, v)
}
return &Value_Set{Item: x}
}
func (left *Value_Set) Subtract(right *Value_Set) *Value_Set {
// for each item in right, remove it from left
lefty := left.GetItem()
righty := right.GetItem()
if c := len(lefty); c == 0 {
return nil
} else if len(righty) == 0 {
x := make([]string, c)
copy(x, lefty)
return &Value_Set{Item: x}
}
a := make(map[string]struct{}, len(lefty))
for _, x := range lefty {
a[x] = struct{}{}
}
for _, x := range righty {
delete(a, x)
}
if len(a) == 0 {
return nil
}
i := 0
for k := range a {
lefty[i] = k
i++
}
return &Value_Set{Item: lefty[:len(a)]}
}
func (left *Value_Ranges) Add(right *Value_Ranges) *Value_Ranges {
a, b := Ranges(left.GetRange()), Ranges(right.GetRange())
c := len(a) + len(b)
if c == 0 {
return nil
}
x := make(Ranges, c)
if len(a) > 0 {
copy(x, a)
}
if len(b) > 0 {
copy(x[len(a):], b)
}
return &Value_Ranges{
Range: x.Sort().Squash(),
}
}
func (left *Value_Ranges) Subtract(right *Value_Ranges) *Value_Ranges {
a, b := Ranges(left.GetRange()), Ranges(right.GetRange())
if len(a) > 1 {
x := make(Ranges, len(a))
copy(x, a)
a = x.Sort().Squash()
}
for _, r := range b {
a = a.Remove(r)
}
if len(a) == 0 {
return nil
}
return &Value_Ranges{Range: a}
}
func (left *Value_Scalar) Add(right *Value_Scalar) *Value_Scalar {
sum := convertToFixed64(left.GetValue()) + convertToFixed64(right.GetValue())
return &Value_Scalar{Value: convertToFloat64(sum)}
}
func (left *Value_Scalar) Subtract(right *Value_Scalar) *Value_Scalar {
diff := convertToFixed64(left.GetValue()) - convertToFixed64(right.GetValue())
return &Value_Scalar{Value: convertToFloat64(diff)}
}