diff --git a/api/prototool.yaml b/api/prototool.yaml index cff0c9a0f9e..609c328ce09 100644 --- a/api/prototool.yaml +++ b/api/prototool.yaml @@ -8,7 +8,7 @@ lint: ignores: - id: FILE_OPTIONS_GO_PACKAGE_NOT_LONG_FORM files: - - vendor/google/rpc/status.proto + - vendor/google/ rules: # The specific linters to add. diff --git a/api/resource/definitions/block/block.proto b/api/resource/definitions/block/block.proto index 70daf9bd74e..090e89dd0d7 100755 --- a/api/resource/definitions/block/block.proto +++ b/api/resource/definitions/block/block.proto @@ -4,6 +4,9 @@ package talos.resource.definitions.block; option go_package = "github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/block"; +import "google/api/expr/v1alpha1/checked.proto"; +import "resource/definitions/enums/enums.proto"; + // DeviceSpec is the spec for devices status. message DeviceSpec { string type = 1; @@ -34,6 +37,23 @@ message DiscoveredVolumeSpec { string type = 14; string device_path = 15; string parent = 16; + string dev_path = 17; + string parent_dev_path = 18; +} + +// DiscoveryRefreshRequestSpec is the spec for DiscoveryRefreshRequest. +message DiscoveryRefreshRequestSpec { + int64 request = 1; +} + +// DiscoveryRefreshStatusSpec is the spec for DiscoveryRefreshStatus status. +message DiscoveryRefreshStatusSpec { + int64 request = 1; +} + +// DiskSelector selects a disk for the volume. +message DiskSelector { + google.api.expr.v1alpha1.CheckedExpr match = 1; } // DiskSpec is the spec for Disks status. @@ -51,6 +71,34 @@ message DiskSpec { string transport = 11; bool rotational = 12; bool cdrom = 13; + string dev_path = 14; +} + +// FilesystemSpec is the spec for volume filesystem. +message FilesystemSpec { + talos.resource.definitions.enums.BlockFilesystemType type = 1; +} + +// LocatorSpec is the spec for volume locator. +message LocatorSpec { + google.api.expr.v1alpha1.CheckedExpr match = 1; +} + +// PartitionSpec is the spec for volume partitioning. +message PartitionSpec { + uint64 min_size = 1; + uint64 max_size = 2; + bool grow = 3; + string label = 4; + string type_uuid = 5; +} + +// ProvisioningSpec is the spec for volume provisioning. +message ProvisioningSpec { + DiskSelector disk_selector = 1; + PartitionSpec partition_spec = 2; + int64 wave = 3; + FilesystemSpec filesystem_spec = 4; } // SystemDiskSpec is the spec for SystemDisks status. @@ -58,3 +106,24 @@ message SystemDiskSpec { string disk_id = 1; } +// VolumeConfigSpec is the spec for VolumeConfig resource. +message VolumeConfigSpec { + string parent_id = 1; + talos.resource.definitions.enums.BlockVolumeType type = 2; + ProvisioningSpec provisioning = 3; + LocatorSpec locator = 4; +} + +// VolumeStatusSpec is the spec for VolumeStatus resource. +message VolumeStatusSpec { + talos.resource.definitions.enums.BlockVolumePhase phase = 1; + string location = 2; + string error_message = 3; + string uuid = 4; + string partition_uuid = 5; + talos.resource.definitions.enums.BlockVolumePhase pre_fail_phase = 6; + string parent_location = 7; + int64 partition_index = 8; + uint64 size = 9; +} + diff --git a/api/resource/definitions/enums/enums.proto b/api/resource/definitions/enums/enums.proto index 5456dbb92aa..fc34ad90d8f 100755 --- a/api/resource/definitions/enums/enums.proto +++ b/api/resource/definitions/enums/enums.proto @@ -353,6 +353,29 @@ enum NethelpersVLANProtocol { VLAN_PROTOCOL8021_AD = 34984; } +// BlockFilesystemType describes filesystem type. +enum BlockFilesystemType { + FILESYSTEM_TYPE_NONE = 0; + FILESYSTEM_TYPE_XFS = 1; +} + +// BlockVolumePhase describes volume phase. +enum BlockVolumePhase { + VOLUME_PHASE_WAITING = 0; + VOLUME_PHASE_READY = 1; + VOLUME_PHASE_FAILED = 2; + VOLUME_PHASE_MISSING = 3; + VOLUME_PHASE_LOCATED = 4; + VOLUME_PHASE_PROVISIONED = 5; +} + +// BlockVolumeType describes volume type. +enum BlockVolumeType { + VOLUME_TYPE_PARTITION = 0; + VOLUME_TYPE_DISK = 1; + VOLUME_TYPE_TMPFS = 2; +} + // KubespanPeerState is KubeSpan peer current state. enum KubespanPeerState { PEER_STATE_UNKNOWN = 0; diff --git a/api/vendor/google/api/expr/v1alpha1/checked.proto b/api/vendor/google/api/expr/v1alpha1/checked.proto new file mode 100644 index 00000000000..b2ba161782b --- /dev/null +++ b/api/vendor/google/api/expr/v1alpha1/checked.proto @@ -0,0 +1,295 @@ +// Copyright 2024 Google LLC +// +// 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. + +syntax = "proto3"; + +package google.api.expr.v1alpha1; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/expr/v1alpha1;expr"; +option java_multiple_files = true; +option java_outer_classname = "DeclProto"; +option java_package = "com.google.api.expr.v1alpha1"; + +import "google/api/expr/v1alpha1/syntax.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/struct.proto"; + +// Protos for representing CEL declarations and typed checked expressions. + +// A CEL expression which has been successfully type checked. +message CheckedExpr { + // A map from expression ids to resolved references. + // + // The following entries are in this table: + // + // - An Ident or Select expression is represented here if it resolves to a + // declaration. For instance, if `a.b.c` is represented by + // `select(select(id(a), b), c)`, and `a.b` resolves to a declaration, + // while `c` is a field selection, then the reference is attached to the + // nested select expression (but not to the id or or the outer select). + // In turn, if `a` resolves to a declaration and `b.c` are field selections, + // the reference is attached to the ident expression. + // - Every Call expression has an entry here, identifying the function being + // called. + // - Every CreateStruct expression for a message has an entry, identifying + // the message. + map reference_map = 2; + // A map from expression ids to types. + // + // Every expression node which has a type different than DYN has a mapping + // here. If an expression has type DYN, it is omitted from this map to save + // space. + map type_map = 3; + // The source info derived from input that generated the parsed `expr` and + // any optimizations made during the type-checking pass. + SourceInfo source_info = 5; + // The expr version indicates the major / minor version number of the `expr` + // representation. + // + // The most common reason for a version change will be to indicate to the CEL + // runtimes that transformations have been performed on the expr during static + // analysis. In some cases, this will save the runtime the work of applying + // the same or similar transformations prior to evaluation. + string expr_version = 6; + // The checked expression. Semantically equivalent to the parsed `expr`, but + // may have structural differences. + Expr expr = 4; +} + +// Represents a CEL type. +message Type { + // List type with typed elements, e.g. `list`. + message ListType { + // The element type. + Type elem_type = 1; + } + // Map type with parameterized key and value types, e.g. `map`. + message MapType { + // The type of the key. + Type key_type = 1; + // The type of the value. + Type value_type = 2; + } + // Function type with result and arg types. + message FunctionType { + // Result type of the function. + Type result_type = 1; + // Argument types of the function. + repeated Type arg_types = 2; + } + // Application defined abstract type. + message AbstractType { + // The fully qualified name of this abstract type. + string name = 1; + // Parameter types for this abstract type. + repeated Type parameter_types = 2; + } + // CEL primitive types. + enum PrimitiveType { + // Unspecified type. + PRIMITIVE_TYPE_UNSPECIFIED = 0; + // Boolean type. + BOOL = 1; + // Int64 type. + // + // Proto-based integer values are widened to int64. + INT64 = 2; + // Uint64 type. + // + // Proto-based unsigned integer values are widened to uint64. + UINT64 = 3; + // Double type. + // + // Proto-based float values are widened to double values. + DOUBLE = 4; + // String type. + STRING = 5; + // Bytes type. + BYTES = 6; + } + // Well-known protobuf types treated with first-class support in CEL. + enum WellKnownType { + // Unspecified type. + WELL_KNOWN_TYPE_UNSPECIFIED = 0; + // Well-known protobuf.Any type. + // + // Any types are a polymorphic message type. During type-checking they are + // treated like `DYN` types, but at runtime they are resolved to a specific + // message type specified at evaluation time. + ANY = 1; + // Well-known protobuf.Timestamp type, internally referenced as `timestamp`. + TIMESTAMP = 2; + // Well-known protobuf.Duration type, internally referenced as `duration`. + DURATION = 3; + } + // The kind of type. + oneof type_kind { + // Dynamic type. + google.protobuf.Empty dyn = 1; + // Null value. + google.protobuf.NullValue null = 2; + // Primitive types: `true`, `1u`, `-2.0`, `'string'`, `b'bytes'`. + PrimitiveType primitive = 3; + // Wrapper of a primitive type, e.g. `google.protobuf.Int64Value`. + PrimitiveType wrapper = 4; + // Well-known protobuf type such as `google.protobuf.Timestamp`. + WellKnownType well_known = 5; + // Parameterized list with elements of `list_type`, e.g. `list`. + ListType list_type = 6; + // Parameterized map with typed keys and values. + MapType map_type = 7; + // Function type. + FunctionType function = 8; + // Protocol buffer message type. + // + // The `message_type` string specifies the qualified message type name. For + // example, `google.plus.Profile`. + string message_type = 9; + // Type param type. + // + // The `type_param` string specifies the type parameter name, e.g. `list` + // would be a `list_type` whose element type was a `type_param` type + // named `E`. + string type_param = 10; + // Type type. + // + // The `type` value specifies the target type. e.g. int is type with a + // target type of `Primitive.INT`. + Type type = 11; + // Error type. + // + // During type-checking if an expression is an error, its type is propagated + // as the `ERROR` type. This permits the type-checker to discover other + // errors present in the expression. + google.protobuf.Empty error = 12; + // Abstract, application defined type. + AbstractType abstract_type = 14; + } +} + +// Represents a declaration of a named value or function. +// +// A declaration is part of the contract between the expression, the agent +// evaluating that expression, and the caller requesting evaluation. +message Decl { + // Identifier declaration which specifies its type and optional `Expr` value. + // + // An identifier without a value is a declaration that must be provided at + // evaluation time. An identifier with a value should resolve to a constant, + // but may be used in conjunction with other identifiers bound at evaluation + // time. + message IdentDecl { + // Required. The type of the identifier. + Type type = 1; + // The constant value of the identifier. If not specified, the identifier + // must be supplied at evaluation time. + Constant value = 2; + // Documentation string for the identifier. + string doc = 3; + } + // Function declaration specifies one or more overloads which indicate the + // function's parameter types and return type. + // + // Functions have no observable side-effects (there may be side-effects like + // logging which are not observable from CEL). + message FunctionDecl { + // An overload indicates a function's parameter types and return type, and + // may optionally include a function body described in terms of + // [Expr][google.api.expr.v1alpha1.Expr] values. + // + // Functions overloads are declared in either a function or method + // call-style. For methods, the `params[0]` is the expected type of the + // target receiver. + // + // Overloads must have non-overlapping argument types after erasure of all + // parameterized type variables (similar as type erasure in Java). + message Overload { + // Required. Globally unique overload name of the function which reflects + // the function name and argument types. + // + // This will be used by a [Reference][google.api.expr.v1alpha1.Reference] + // to indicate the `overload_id` that was resolved for the function + // `name`. + string overload_id = 1; + // List of function parameter [Type][google.api.expr.v1alpha1.Type] + // values. + // + // Param types are disjoint after generic type parameters have been + // replaced with the type `DYN`. Since the `DYN` type is compatible with + // any other type, this means that if `A` is a type parameter, the + // function types `int` and `int` are not disjoint. Likewise, + // `map` is not disjoint from `map`. + // + // When the `result_type` of a function is a generic type param, the + // type param name also appears as the `type` of on at least one params. + repeated Type params = 2; + // The type param names associated with the function declaration. + // + // For example, `function ex(K key, map map) : V` would yield + // the type params of `K, V`. + repeated string type_params = 3; + // Required. The result type of the function. For example, the operator + // `string.isEmpty()` would have `result_type` of `kind: BOOL`. + Type result_type = 4; + // Whether the function is to be used in a method call-style `x.f(...)` + // or a function call-style `f(x, ...)`. + // + // For methods, the first parameter declaration, `params[0]` is the + // expected type of the target receiver. + bool is_instance_function = 5; + // Documentation string for the overload. + string doc = 6; + } + // Required. List of function overloads, must contain at least one overload. + repeated Overload overloads = 1; + } + // The fully qualified name of the declaration. + // + // Declarations are organized in containers and this represents the full path + // to the declaration in its container, as in `google.api.expr.Decl`. + // + // Declarations used as + // [FunctionDecl.Overload][google.api.expr.v1alpha1.Decl.FunctionDecl.Overload] + // parameters may or may not have a name depending on whether the overload is + // function declaration or a function definition containing a result + // [Expr][google.api.expr.v1alpha1.Expr]. + string name = 1; + // Required. The declaration kind. + oneof decl_kind { + // Identifier declaration. + IdentDecl ident = 2; + // Function declaration. + FunctionDecl function = 3; + } +} + +// Describes a resolved reference to a declaration. +message Reference { + // The fully qualified name of the declaration. + string name = 1; + // For references to functions, this is a list of `Overload.overload_id` + // values which match according to typing rules. + // + // If the list has more than one element, overload resolution among the + // presented candidates must happen at runtime because of dynamic types. The + // type checker attempts to narrow down this list as much as possible. + // + // Empty if this is not a reference to a + // [Decl.FunctionDecl][google.api.expr.v1alpha1.Decl.FunctionDecl]. + repeated string overload_id = 3; + // For references to constants, this may contain the value of the + // constant if known at compile time. + Constant value = 4; +} diff --git a/api/vendor/google/api/expr/v1alpha1/eval.proto b/api/vendor/google/api/expr/v1alpha1/eval.proto new file mode 100644 index 00000000000..6ad7a3da5a3 --- /dev/null +++ b/api/vendor/google/api/expr/v1alpha1/eval.proto @@ -0,0 +1,113 @@ +// Copyright 2024 Google LLC +// +// 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. + +syntax = "proto3"; + +package google.api.expr.v1alpha1; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/expr/v1alpha1;expr"; +option java_multiple_files = true; +option java_outer_classname = "EvalProto"; +option java_package = "com.google.api.expr.v1alpha1"; + +import "google/api/expr/v1alpha1/value.proto"; +import "google/rpc/status.proto"; + +// The state of an evaluation. +// +// Can represent an inital, partial, or completed state of evaluation. +message EvalState { + // A single evalution result. + message Result { + // The id of the expression this result if for. + int64 expr = 1; + // The index in `values` of the resulting value. + int64 value = 2; + } + // The unique values referenced in this message. + repeated ExprValue values = 1; + // An ordered list of results. + // + // Tracks the flow of evaluation through the expression. + // May be sparse. + repeated Result results = 3; +} + +// The value of an evaluated expression. +message ExprValue { + // An expression can resolve to a value, error or unknown. + oneof kind { + // A concrete value. + Value value = 1; + // The set of errors in the critical path of evalution. + // + // Only errors in the critical path are included. For example, + // `( || true) && ` will only result in ``, + // while ` || ` will result in both `` and + // ``. + // + // Errors cause by the presence of other errors are not included in the + // set. For example `.foo`, `foo()`, and ` + 1` will + // only result in ``. + // + // Multiple errors *might* be included when evaluation could result + // in different errors. For example ` + ` and + // `foo(, )` may result in ``, `` or both. + // The exact subset of errors included for this case is unspecified and + // depends on the implementation details of the evaluator. + ErrorSet error = 2; + // The set of unknowns in the critical path of evaluation. + // + // Unknown behaves identically to Error with regards to propagation. + // Specifically, only unknowns in the critical path are included, unknowns + // caused by the presence of other unknowns are not included, and multiple + // unknowns *might* be included included when evaluation could result in + // different unknowns. For example: + // + // ( || true) && -> + // || -> + // .foo -> + // foo() -> + // + -> or + // + // Unknown takes precidence over Error in cases where a `Value` can short + // circuit the result: + // + // || -> + // && -> + // + // Errors take precidence in all other cases: + // + // + -> + // foo(, ) -> + UnknownSet unknown = 3; + } +} + +// A set of errors. +// +// The errors included depend on the context. See `ExprValue.error`. +message ErrorSet { + // The errors in the set. + repeated google.rpc.Status errors = 1; +} + +// A set of expressions for which the value is unknown. +// +// The unknowns included depend on the context. See `ExprValue.unknown`. +message UnknownSet { + // The ids of the expressions with unknown values. + repeated int64 exprs = 1; +} diff --git a/api/vendor/google/api/expr/v1alpha1/explain.proto b/api/vendor/google/api/expr/v1alpha1/explain.proto new file mode 100644 index 00000000000..e533f8be820 --- /dev/null +++ b/api/vendor/google/api/expr/v1alpha1/explain.proto @@ -0,0 +1,49 @@ +// Copyright 2024 Google LLC +// +// 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. + +syntax = "proto3"; + +package google.api.expr.v1alpha1; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/expr/v1alpha1;expr"; +option java_multiple_files = true; +option java_outer_classname = "ExplainProto"; +option java_package = "com.google.api.expr.v1alpha1"; + +import "google/api/expr/v1alpha1/value.proto"; + +// Values of intermediate expressions produced when evaluating expression. +// Deprecated, use `EvalState` instead. +message Explain { + option deprecated = true; + // ID and value index of one step. + message ExprStep { + // ID of corresponding Expr node. + int64 id = 1; + // Index of the value in the values list. + int32 value_index = 2; + } + // All of the observed values. + // + // The field value_index is an index in the values list. + // Separating values from steps is needed to remove redundant values. + repeated Value values = 1; + // List of steps. + // + // Repeated evaluations of the same expression generate new ExprStep + // instances. The order of such ExprStep instances matches the order of + // elements returned by Comprehension.iter_range. + repeated ExprStep expr_steps = 2; +} diff --git a/api/vendor/google/api/expr/v1alpha1/syntax.proto b/api/vendor/google/api/expr/v1alpha1/syntax.proto new file mode 100644 index 00000000000..7cdc188f465 --- /dev/null +++ b/api/vendor/google/api/expr/v1alpha1/syntax.proto @@ -0,0 +1,344 @@ +// Copyright 2024 Google LLC +// +// 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. + +syntax = "proto3"; + +package google.api.expr.v1alpha1; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/expr/v1alpha1;expr"; +option java_multiple_files = true; +option java_outer_classname = "SyntaxProto"; +option java_package = "com.google.api.expr.v1alpha1"; + +import "google/protobuf/duration.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/timestamp.proto"; + +// A representation of the abstract syntax of the Common Expression Language. + +// An expression together with source information as returned by the parser. +message ParsedExpr { + // The parsed expression. + Expr expr = 2; + // The source info derived from input that generated the parsed `expr`. + SourceInfo source_info = 3; +} + +// An abstract representation of a common expression. +// +// Expressions are abstractly represented as a collection of identifiers, +// select statements, function calls, literals, and comprehensions. All +// operators with the exception of the '.' operator are modelled as function +// calls. This makes it easy to represent new operators into the existing AST. +// +// All references within expressions must resolve to a +// [Decl][google.api.expr.v1alpha1.Decl] provided at type-check for an +// expression to be valid. A reference may either be a bare identifier `name` or +// a qualified identifier `google.api.name`. References may either refer to a +// value or a function declaration. +// +// For example, the expression `google.api.name.startsWith('expr')` references +// the declaration `google.api.name` within a +// [Expr.Select][google.api.expr.v1alpha1.Expr.Select] expression, and the +// function declaration `startsWith`. +message Expr { + // An identifier expression. e.g. `request`. + message Ident { + // Required. Holds a single, unqualified identifier, possibly preceded by a + // '.'. + // + // Qualified names are represented by the + // [Expr.Select][google.api.expr.v1alpha1.Expr.Select] expression. + string name = 1; + } + // A field selection expression. e.g. `request.auth`. + message Select { + // Required. The target of the selection expression. + // + // For example, in the select expression `request.auth`, the `request` + // portion of the expression is the `operand`. + Expr operand = 1; + // Required. The name of the field to select. + // + // For example, in the select expression `request.auth`, the `auth` portion + // of the expression would be the `field`. + string field = 2; + // Whether the select is to be interpreted as a field presence test. + // + // This results from the macro `has(request.auth)`. + bool test_only = 3; + } + // A call expression, including calls to predefined functions and operators. + // + // For example, `value == 10`, `size(map_value)`. + message Call { + // The target of an method call-style expression. For example, `x` in + // `x.f()`. + Expr target = 1; + // Required. The name of the function or method being called. + string function = 2; + // The arguments. + repeated Expr args = 3; + } + // A list creation expression. + // + // Lists may either be homogenous, e.g. `[1, 2, 3]`, or heterogeneous, e.g. + // `dyn([1, 'hello', 2.0])` + message CreateList { + // The elements part of the list. + repeated Expr elements = 1; + // The indices within the elements list which are marked as optional + // elements. + // + // When an optional-typed value is present, the value it contains + // is included in the list. If the optional-typed value is absent, the list + // element is omitted from the CreateList result. + repeated int32 optional_indices = 2; + } + // A map or message creation expression. + // + // Maps are constructed as `{'key_name': 'value'}`. Message construction is + // similar, but prefixed with a type name and composed of field ids: + // `types.MyType{field_id: 'value'}`. + message CreateStruct { + // Represents an entry. + message Entry { + // Required. An id assigned to this node by the parser which is unique + // in a given expression tree. This is used to associate type + // information and other attributes to the node. + int64 id = 1; + // The `Entry` key kinds. + oneof key_kind { + // The field key for a message creator statement. + string field_key = 2; + // The key expression for a map creation statement. + Expr map_key = 3; + } + // Required. The value assigned to the key. + // + // If the optional_entry field is true, the expression must resolve to an + // optional-typed value. If the optional value is present, the key will be + // set; however, if the optional value is absent, the key will be unset. + Expr value = 4; + // Whether the key-value pair is optional. + bool optional_entry = 5; + } + // The type name of the message to be created, empty when creating map + // literals. + string message_name = 1; + // The entries in the creation expression. + repeated Entry entries = 2; + } + // A comprehension expression applied to a list or map. + // + // Comprehensions are not part of the core syntax, but enabled with macros. + // A macro matches a specific call signature within a parsed AST and replaces + // the call with an alternate AST block. Macro expansion happens at parse + // time. + // + // The following macros are supported within CEL: + // + // Aggregate type macros may be applied to all elements in a list or all keys + // in a map: + // + // * `all`, `exists`, `exists_one` - test a predicate expression against + // the inputs and return `true` if the predicate is satisfied for all, + // any, or only one value `list.all(x, x < 10)`. + // * `filter` - test a predicate expression against the inputs and return + // the subset of elements which satisfy the predicate: + // `payments.filter(p, p > 1000)`. + // * `map` - apply an expression to all elements in the input and return the + // output aggregate type: `[1, 2, 3].map(i, i * i)`. + // + // The `has(m.x)` macro tests whether the property `x` is present in struct + // `m`. The semantics of this macro depend on the type of `m`. For proto2 + // messages `has(m.x)` is defined as 'defined, but not set`. For proto3, the + // macro tests whether the property is set to its default. For map and struct + // types, the macro tests whether the property `x` is defined on `m`. + message Comprehension { + // The name of the iteration variable. + string iter_var = 1; + // The range over which var iterates. + Expr iter_range = 2; + // The name of the variable used for accumulation of the result. + string accu_var = 3; + // The initial value of the accumulator. + Expr accu_init = 4; + // An expression which can contain iter_var and accu_var. + // + // Returns false when the result has been computed and may be used as + // a hint to short-circuit the remainder of the comprehension. + Expr loop_condition = 5; + // An expression which can contain iter_var and accu_var. + // + // Computes the next value of accu_var. + Expr loop_step = 6; + // An expression which can contain accu_var. + // + // Computes the result. + Expr result = 7; + } + // Required. An id assigned to this node by the parser which is unique in a + // given expression tree. This is used to associate type information and other + // attributes to a node in the parse tree. + int64 id = 2; + // Required. Variants of expressions. + oneof expr_kind { + // A literal expression. + Constant const_expr = 3; + // An identifier expression. + Ident ident_expr = 4; + // A field selection expression, e.g. `request.auth`. + Select select_expr = 5; + // A call expression, including calls to predefined functions and operators. + Call call_expr = 6; + // A list creation expression. + CreateList list_expr = 7; + // A map or message creation expression. + CreateStruct struct_expr = 8; + // A comprehension expression. + Comprehension comprehension_expr = 9; + } +} + +// Represents a primitive literal. +// +// Named 'Constant' here for backwards compatibility. +// +// This is similar as the primitives supported in the well-known type +// `google.protobuf.Value`, but richer so it can represent CEL's full range of +// primitives. +// +// Lists and structs are not included as constants as these aggregate types may +// contain [Expr][google.api.expr.v1alpha1.Expr] elements which require +// evaluation and are thus not constant. +// +// Examples of literals include: `"hello"`, `b'bytes'`, `1u`, `4.2`, `-2`, +// `true`, `null`. +message Constant { + // Required. The valid constant kinds. + oneof constant_kind { + // null value. + google.protobuf.NullValue null_value = 1; + // boolean value. + bool bool_value = 2; + // int64 value. + int64 int64_value = 3; + // uint64 value. + uint64 uint64_value = 4; + // double value. + double double_value = 5; + // string value. + string string_value = 6; + // bytes value. + bytes bytes_value = 7; + // protobuf.Duration value. + // + // Deprecated: duration is no longer considered a builtin cel type. + google.protobuf.Duration duration_value = 8 [deprecated = true]; + // protobuf.Timestamp value. + // + // Deprecated: timestamp is no longer considered a builtin cel type. + google.protobuf.Timestamp timestamp_value = 9 [deprecated = true]; + } +} + +// Source information collected at parse time. +message SourceInfo { + // An extension that was requested for the source expression. + message Extension { + // Version + message Version { + // Major version changes indicate different required support level from + // the required components. + int64 major = 1; + // Minor version changes must not change the observed behavior from + // existing implementations, but may be provided informationally. + int64 minor = 2; + } + // CEL component specifier. + enum Component { + // Unspecified, default. + COMPONENT_UNSPECIFIED = 0; + // Parser. Converts a CEL string to an AST. + COMPONENT_PARSER = 1; + // Type checker. Checks that references in an AST are defined and types + // agree. + COMPONENT_TYPE_CHECKER = 2; + // Runtime. Evaluates a parsed and optionally checked CEL AST against a + // context. + COMPONENT_RUNTIME = 3; + } + // Identifier for the extension. Example: constant_folding + string id = 1; + // If set, the listed components must understand the extension for the + // expression to evaluate correctly. + // + // This field has set semantics, repeated values should be deduplicated. + repeated Component affected_components = 2; + // Version info. May be skipped if it isn't meaningful for the extension. + // (for example constant_folding might always be v0.0). + Version version = 3; + } + // The syntax version of the source, e.g. `cel1`. + string syntax_version = 1; + // The location name. All position information attached to an expression is + // relative to this location. + // + // The location could be a file, UI element, or similar. For example, + // `acme/app/AnvilPolicy.cel`. + string location = 2; + // Monotonically increasing list of code point offsets where newlines + // `\n` appear. + // + // The line number of a given position is the index `i` where for a given + // `id` the `line_offsets[i] < id_positions[id] < line_offsets[i+1]`. The + // column may be derivd from `id_positions[id] - line_offsets[i]`. + repeated int32 line_offsets = 3; + // A map from the parse node id (e.g. `Expr.id`) to the code point offset + // within the source. + map positions = 4; + // A map from the parse node id where a macro replacement was made to the + // call `Expr` that resulted in a macro expansion. + // + // For example, `has(value.field)` is a function call that is replaced by a + // `test_only` field selection in the AST. Likewise, the call + // `list.exists(e, e > 10)` translates to a comprehension expression. The key + // in the map corresponds to the expression id of the expanded macro, and the + // value is the call `Expr` that was replaced. + map macro_calls = 5; + // A list of tags for extensions that were used while parsing or type checking + // the source expression. For example, optimizations that require special + // runtime support may be specified. + // + // These are used to check feature support between components in separate + // implementations. This can be used to either skip redundant work or + // report an error if the extension is unsupported. + repeated Extension extensions = 6; +} + +// A specific position in source. +message SourcePosition { + // The soucre location name (e.g. file name). + string location = 1; + // The UTF-8 code unit offset. + int32 offset = 2; + // The 1-based index of the starting line in the source text + // where the issue occurs, or 0 if unknown. + int32 line = 3; + // The 0-based index of the starting position within the line of source text + // where the issue occurs. Only meaningful if line is nonzero. + int32 column = 4; +} diff --git a/api/vendor/google/api/expr/v1alpha1/value.proto b/api/vendor/google/api/expr/v1alpha1/value.proto new file mode 100644 index 00000000000..a34d6819d3e --- /dev/null +++ b/api/vendor/google/api/expr/v1alpha1/value.proto @@ -0,0 +1,101 @@ +// Copyright 2024 Google LLC +// +// 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. + +syntax = "proto3"; + +package google.api.expr.v1alpha1; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/expr/v1alpha1;expr"; +option java_multiple_files = true; +option java_outer_classname = "ValueProto"; +option java_package = "com.google.api.expr.v1alpha1"; + +import "google/protobuf/any.proto"; +import "google/protobuf/struct.proto"; + +// Contains representations for CEL runtime values. + +// Represents a CEL value. +// +// This is similar to `google.protobuf.Value`, but can represent CEL's full +// range of values. +message Value { + // Required. The valid kinds of values. + oneof kind { + // Null value. + google.protobuf.NullValue null_value = 1; + // Boolean value. + bool bool_value = 2; + // Signed integer value. + int64 int64_value = 3; + // Unsigned integer value. + uint64 uint64_value = 4; + // Floating point value. + double double_value = 5; + // UTF-8 string value. + string string_value = 6; + // Byte string value. + bytes bytes_value = 7; + // An enum value. + EnumValue enum_value = 9; + // The proto message backing an object value. + google.protobuf.Any object_value = 10; + // Map value. + MapValue map_value = 11; + // List value. + ListValue list_value = 12; + // Type value. + string type_value = 15; + } +} + +// An enum value. +message EnumValue { + // The fully qualified name of the enum type. + string type = 1; + // The value of the enum. + int32 value = 2; +} + +// A list. +// +// Wrapped in a message so 'not set' and empty can be differentiated, which is +// required for use in a 'oneof'. +message ListValue { + // The ordered values in the list. + repeated Value values = 1; +} + +// A map. +// +// Wrapped in a message so 'not set' and empty can be differentiated, which is +// required for use in a 'oneof'. +message MapValue { + // An entry in the map. + message Entry { + // The key. + // + // Must be unique with in the map. + // Currently only boolean, int, uint, and string values can be keys. + Value key = 1; + // The value. + Value value = 2; + } + // The set of map entries. + // + // CEL has fewer restrictions on keys, so a protobuf map represenation + // cannot be used. + repeated Entry entries = 1; +} diff --git a/cmd/installer/pkg/install/errata.go b/cmd/installer/pkg/install/errata.go index ab0da0c43ef..efe7c5e3b64 100644 --- a/cmd/installer/pkg/install/errata.go +++ b/cmd/installer/pkg/install/errata.go @@ -73,33 +73,28 @@ func errataArm64ZBoot() { // errataNetIfnames appends the `net.ifnames=0` kernel parameter to the kernel command line if upgrading // from an old enough version of Talos. -func (i *Installer) errataNetIfnames() error { +func (i *Installer) errataNetIfnames(talosVersion *compatibility.TalosVersion) { if i.cmdline.Get(constants.KernelParamNetIfnames).First() != nil { // net.ifnames is already set, nothing to do - return nil + return } - oldTalos, err := upgradeFromPreIfnamesTalos() - if err != nil { - return err - } + oldTalos := upgradeFromPreIfnamesTalos(talosVersion) if oldTalos { log.Printf("appending net.ifnames=0 to the kernel command line") i.cmdline.Append(constants.KernelParamNetIfnames, "0") } - - return nil } -func upgradeFromPreIfnamesTalos() (bool, error) { +func readHostTalosVersion() (*compatibility.TalosVersion, error) { ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() if _, err := os.Stat(constants.MachineSocketPath); err != nil { - // old Talos version, include fallback - return true, nil + // can't read Talos version + return nil, nil } c, err := client.New(ctx, @@ -107,7 +102,7 @@ func upgradeFromPreIfnamesTalos() (bool, error) { client.WithGRPCDialOptions(grpc.WithTransportCredentials(insecure.NewCredentials())), ) if err != nil { - return false, fmt.Errorf("error connecting to the machine service: %w", err) + return nil, fmt.Errorf("error connecting to the machine service: %w", err) } defer c.Close() //nolint:errcheck @@ -117,15 +112,24 @@ func upgradeFromPreIfnamesTalos() (bool, error) { resp, err := c.Version(ctx) if err != nil { - return false, fmt.Errorf("error getting Talos version: %w", err) + return nil, fmt.Errorf("error getting Talos version: %w", err) } hostVersion := unpack(resp.Messages) talosVersion, err := compatibility.ParseTalosVersion(hostVersion.Version) if err != nil { - return false, fmt.Errorf("error parsing Talos version: %w", err) + return nil, fmt.Errorf("error parsing Talos version: %w", err) + } + + return talosVersion, nil +} + +func upgradeFromPreIfnamesTalos(talosVersion *compatibility.TalosVersion) bool { + if talosVersion == nil { + // old Talos version, include fallback + return true } - return talosVersion.DisablePredictableNetworkInterfaces(), nil + return talosVersion.DisablePredictableNetworkInterfaces() } diff --git a/cmd/installer/pkg/install/install.go b/cmd/installer/pkg/install/install.go index 7e2a4442fa6..0a020799310 100644 --- a/cmd/installer/pkg/install/install.go +++ b/cmd/installer/pkg/install/install.go @@ -12,12 +12,14 @@ import ( "log" "os" "path/filepath" - "syscall" - "time" - "github.com/siderolabs/go-blockdevice/blockdevice" + "github.com/google/uuid" + "github.com/siderolabs/go-blockdevice/v2/blkid" + "github.com/siderolabs/go-blockdevice/v2/block" + "github.com/siderolabs/go-blockdevice/v2/partitioning" + "github.com/siderolabs/go-blockdevice/v2/partitioning/gpt" + "github.com/siderolabs/go-pointer" "github.com/siderolabs/go-procfs/procfs" - "github.com/siderolabs/go-retry/retry" "gopkg.in/yaml.v3" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" @@ -25,9 +27,11 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader" bootloaderoptions "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options" "github.com/siderolabs/talos/internal/pkg/meta" - "github.com/siderolabs/talos/internal/pkg/mount" + "github.com/siderolabs/talos/internal/pkg/partition" "github.com/siderolabs/talos/pkg/imager/overlay/executor" + "github.com/siderolabs/talos/pkg/machinery/compatibility" "github.com/siderolabs/talos/pkg/machinery/constants" + "github.com/siderolabs/talos/pkg/machinery/imager/quirks" "github.com/siderolabs/talos/pkg/machinery/kernel" "github.com/siderolabs/talos/pkg/machinery/overlay" "github.com/siderolabs/talos/pkg/machinery/version" @@ -174,10 +178,8 @@ func Install(ctx context.Context, p runtime.Platform, mode Mode, opts *Options) // Installer represents the installer logic. It serves as the entrypoint to all // installation methods. type Installer struct { - cmdline *procfs.Cmdline - options *Options - manifest *Manifest - bootloader bootloader.Bootloader + cmdline *procfs.Cmdline + options *Options } // NewInstaller initializes and returns an Installer. @@ -195,30 +197,15 @@ func NewInstaller(ctx context.Context, cmdline *procfs.Cmdline, mode Mode, opts i.options.Printf = log.Printf } - if !i.options.Zero { - i.bootloader, err = bootloader.Probe(ctx, i.options.Disk) - if err != nil && !os.IsNotExist(err) { - return nil, fmt.Errorf("failed to probe bootloader: %w", err) - } + if mode == ModeUpgrade && i.options.Force { + i.options.Printf("system disk wipe on upgrade is not supported anymore, option ignored") } - i.options.BootAssets.FillDefaults(opts.Arch) - - bootLoaderPresent := i.bootloader != nil - if !bootLoaderPresent { - if mode.IsImage() { - // on image creation, use the bootloader based on options - i.bootloader = bootloader.New(opts.ImageSecureboot, opts.Version) - } else { - // on install/upgrade perform automatic detection - i.bootloader = bootloader.NewAuto() - } + if i.options.Zero && mode != ModeInstall { + i.options.Printf("zeroing of the disk is only supported for the initial installation, option ignored") } - i.manifest, err = NewManifest(mode, i.bootloader.UEFIBoot(), bootLoaderPresent, i.options) - if err != nil { - return nil, fmt.Errorf("failed to create installation manifest: %w", err) - } + i.options.BootAssets.FillDefaults(opts.Arch) return i, nil } @@ -228,93 +215,115 @@ func NewInstaller(ctx context.Context, cmdline *procfs.Cmdline, mode Mode, opts // //nolint:gocyclo,cyclop func (i *Installer) Install(ctx context.Context, mode Mode) (err error) { - errataArm64ZBoot() + // pre-flight checks, erratas + hostTalosVersion, err := readHostTalosVersion() + if err != nil { + return err + } if mode == ModeUpgrade { - if err = i.errataNetIfnames(); err != nil { - return err - } + errataArm64ZBoot() + + i.errataNetIfnames(hostTalosVersion) } if err = i.runPreflightChecks(mode); err != nil { return err } + // prepare extensions if legacy machine.install.extensions is present if err = i.installExtensions(); err != nil { return err } - if err = i.manifest.Execute(); err != nil { - return err + // open and lock the blockdevice for the installation disk for the whole duration of the installer + bd, err := block.NewFromPath(i.options.Disk, block.OpenForWrite()) + if err != nil { + return fmt.Errorf("failed to open blockdevice %s: %w", i.options.Disk, err) } - // Mount the partitions. - mountpoints := mount.NewMountPoints() + defer bd.Close() //nolint:errcheck - var bootLabels []string - - if i.bootloader.UEFIBoot() { - bootLabels = []string{constants.EFIPartitionLabel} - } else { - bootLabels = []string{constants.BootPartitionLabel, constants.EFIPartitionLabel} + if err = bd.Lock(true); err != nil { + return fmt.Errorf("failed to lock blockdevice %s: %w", i.options.Disk, err) } - for _, label := range bootLabels { - if err = func() error { - var device string - // searching targets for the device to be used - OuterLoop: - for dev, targets := range i.manifest.Targets { - for _, target := range targets { - if target.Label == label { - device = dev - - break OuterLoop - } - } - } - - if device == "" { - return fmt.Errorf("failed to detect %s target device", label) - } + defer bd.Unlock() //nolint:errcheck - var bd *blockdevice.BlockDevice + var bootlder bootloader.Bootloader - bd, err = retryBlockdeviceOpen(device) - if err != nil { - return fmt.Errorf("error opening blockdevice %s: %w", device, err) - } + // if running in install/image mode, just create new GPT partition table + // if running in upgrade mode, verify that install disk has correct GPT partition table and expected partitions - defer bd.Close() //nolint:errcheck + // probe the disk anyways + info, err := blkid.Probe(bd.File(), blkid.WithSkipLocking(true)) + if err != nil { + return fmt.Errorf("failed to probe blockdevice %s: %w", i.options.Disk, err) + } - var mountpoint *mount.Point + gptdev, err := gpt.DeviceFromBlockDevice(bd) + if err != nil { + return fmt.Errorf("error getting GPT device: %w", err) + } - mountpoint, err = mount.SystemMountPointForLabel(ctx, bd, label, mount.WithPrefix(i.options.MountPrefix)) - if err != nil { - return fmt.Errorf("error finding system mount points for %s: %w", device, err) + switch mode { + case ModeImage: + // on image creation, we don't care about disk contents + bootlder = bootloader.New(i.options.ImageSecureboot, i.options.Version) + case ModeInstall: + if !i.options.Zero { + // verify that the disk is either empty or has an empty GPT partition table, otherwise fail the install + switch { + case info.Name == "": + // empty, ok + case info.Name == "gpt" && len(info.Parts) == 0: + // GPT, no partitions, ok + default: + return fmt.Errorf("disk %s is not empty, skipping install, detected %q", i.options.Disk, info.Name) } + } else { + // zero the disk + if err = bd.FastWipe(); err != nil { + return fmt.Errorf("failed to zero blockdevice %s: %w", i.options.Disk, err) + } + } - mountpoints.Set(label, mountpoint) - - return nil - }(); err != nil { - return fmt.Errorf("error mounting for label %q: %w", label, err) + // on install, automatically detect the bootloader + bootlder = bootloader.NewAuto() + case ModeUpgrade: + // on upgrade, we don't touch the disk partitions, but we need to verify that the disk has the expected GPT partition table + if info.Name != "gpt" { + return fmt.Errorf("disk %s has an unexpected format %q", i.options.Disk, info.Name) } } - if err = mount.Mount(mountpoints); err != nil { - return fmt.Errorf("failed to mount standard mountpoints: %w", err) + if mode == ModeImage || mode == ModeInstall { + // create partitions and re-probe the device + if err = i.createPartitions(gptdev, mode, hostTalosVersion, bootlder); err != nil { + return fmt.Errorf("failed to create partitions: %w", err) + } + + info, err = blkid.Probe(bd.File(), blkid.WithSkipLocking(true)) + if err != nil { + return fmt.Errorf("failed to probe blockdevice %s: %w", i.options.Disk, err) + } } - defer func() { - e := mount.Unmount(mountpoints) - if e != nil { - log.Printf("failed to unmount: %v", e) + if mode == ModeUpgrade { + // on upgrade, probe the bootloader + bootlder, err = bootloader.Probe(i.options.Disk, bootloaderoptions.ProbeOptions{ + // the disk is already locked + BlockProbeOptions: []blkid.ProbeOption{ + blkid.WithSkipLocking(true), + }, + }) + if err != nil { + return fmt.Errorf("failed to probe bootloader on upgrade: %w", err) } - }() + } // Install the bootloader. - if err = i.bootloader.Install(bootloaderoptions.InstallOptions{ + bootInstallResult, err := bootlder.Install(bootloaderoptions.InstallOptions{ BootDisk: i.options.Disk, Arch: i.options.Arch, Cmdline: i.cmdline.String(), @@ -323,43 +332,48 @@ func (i *Installer) Install(ctx context.Context, mode Mode) (err error) { MountPrefix: i.options.MountPrefix, BootAssets: i.options.BootAssets, Printf: i.options.Printf, - }); err != nil { - return fmt.Errorf("failed to install bootloader: %w", err) - } - if i.options.Board != constants.BoardNone { - var b runtime.Board + ExtraInstallStep: func() error { + if i.options.Board != constants.BoardNone { + var b runtime.Board - b, err = board.NewBoard(i.options.Board) - if err != nil { - return err - } + b, err = board.NewBoard(i.options.Board) + if err != nil { + return err + } - i.options.Printf("installing U-Boot for %q", b.Name()) - - if err = b.Install(runtime.BoardInstallOptions{ - InstallDisk: i.options.Disk, - MountPrefix: i.options.MountPrefix, - UBootPath: i.options.BootAssets.UBootPath, - DTBPath: i.options.BootAssets.DTBPath, - RPiFirmwarePath: i.options.BootAssets.RPiFirmwarePath, - Printf: i.options.Printf, - }); err != nil { - return fmt.Errorf("failed to install for board %s: %w", b.Name(), err) - } - } + i.options.Printf("installing U-Boot for %q", b.Name()) + + if err = b.Install(runtime.BoardInstallOptions{ + InstallDisk: i.options.Disk, + MountPrefix: i.options.MountPrefix, + UBootPath: i.options.BootAssets.UBootPath, + DTBPath: i.options.BootAssets.DTBPath, + RPiFirmwarePath: i.options.BootAssets.RPiFirmwarePath, + Printf: i.options.Printf, + }); err != nil { + return fmt.Errorf("failed to install for board %s: %w", b.Name(), err) + } + } - if i.options.OverlayInstaller != nil { - i.options.Printf("running overlay installer %q", i.options.OverlayName) - - if err = i.options.OverlayInstaller.Install(overlay.InstallOptions[overlay.ExtraOptions]{ - InstallDisk: i.options.Disk, - MountPrefix: i.options.MountPrefix, - ArtifactsPath: filepath.Join(i.options.OverlayExtractedDir, constants.ImagerOverlayArtifactsPath), - ExtraOptions: i.options.ExtraOptions, - }); err != nil { - return fmt.Errorf("failed to run overlay installer: %w", err) - } + if i.options.OverlayInstaller != nil { + i.options.Printf("running overlay installer %q", i.options.OverlayName) + + if err = i.options.OverlayInstaller.Install(overlay.InstallOptions[overlay.ExtraOptions]{ + InstallDisk: i.options.Disk, + MountPrefix: i.options.MountPrefix, + ArtifactsPath: filepath.Join(i.options.OverlayExtractedDir, constants.ImagerOverlayArtifactsPath), + ExtraOptions: i.options.ExtraOptions, + }); err != nil { + return fmt.Errorf("failed to run overlay installer: %w", err) + } + } + + return nil + }, + }) + if err != nil { + return fmt.Errorf("failed to install bootloader: %w", err) } if mode == ModeUpgrade || len(i.options.MetaValues.values) > 0 { @@ -368,16 +382,10 @@ func (i *Installer) Install(ctx context.Context, mode Mode) (err error) { metaPartitionName string ) - for _, targets := range i.manifest.Targets { - for _, target := range targets { - if target.Label == constants.MetaPartitionLabel { - metaPartitionName = target.PartitionName + for _, partition := range info.Parts { + if pointer.SafeDeref(partition.PartitionLabel) == constants.MetaPartitionLabel { + metaPartitionName = partitioning.DevName(i.options.Disk, partition.PartitionIndex) - break - } - } - - if metaPartitionName != "" { break } } @@ -393,8 +401,8 @@ func (i *Installer) Install(ctx context.Context, mode Mode) (err error) { var ok bool if mode == ModeUpgrade { - if ok, err = metaState.SetTag(context.Background(), meta.Upgrade, i.bootloader.PreviousLabel()); !ok || err != nil { - return fmt.Errorf("failed to set upgrade tag: %q", i.bootloader.PreviousLabel()) + if ok, err = metaState.SetTag(context.Background(), meta.Upgrade, bootInstallResult.PreviousLabel); !ok || err != nil { + return fmt.Errorf("failed to set upgrade tag: %q", bootInstallResult.PreviousLabel) } } @@ -412,6 +420,105 @@ func (i *Installer) Install(ctx context.Context, mode Mode) (err error) { return nil } +//nolint:gocyclo,cyclop +func (i *Installer) createPartitions(gptdev gpt.Device, mode Mode, hostTalosVersion *compatibility.TalosVersion, bootlder bootloader.Bootloader) error { + var partitionOptions *runtime.PartitionOptions + + if i.options.Board != constants.BoardNone && !quirks.New(i.options.Version).SupportsOverlay() { + var b runtime.Board + + b, err := board.NewBoard(i.options.Board) + if err != nil { + return err + } + + partitionOptions = b.PartitionOptions() + } + + if i.options.OverlayInstaller != nil { + overlayOpts, getOptsErr := i.options.OverlayInstaller.GetOptions(i.options.ExtraOptions) + if getOptsErr != nil { + return fmt.Errorf("failed to get overlay installer options: %w", getOptsErr) + } + + if overlayOpts.PartitionOptions.Offset != 0 { + partitionOptions = &runtime.PartitionOptions{ + PartitionsOffset: overlayOpts.PartitionOptions.Offset, + } + } + } + + var gptOptions []gpt.Option + + if partitionOptions != nil && partitionOptions.PartitionsOffset != 0 { + gptOptions = append(gptOptions, gpt.WithSkipLBAs(uint(partitionOptions.PartitionsOffset))) + } + + if i.options.LegacyBIOSSupport { + gptOptions = append(gptOptions, gpt.WithMarkPMBRBootable()) + } + + pt, err := gpt.New(gptdev, gptOptions...) + if err != nil { + return fmt.Errorf("failed to initialize GPT: %w", err) + } + + // boot partitions + partitions := bootlder.RequiredPartitions() + + // META partition + partitions = append(partitions, + partition.NewPartitionOptions(constants.MetaPartitionLabel, false), + ) + + legacyImage := mode == ModeImage && !quirks.New(i.options.Version).SkipDataPartitions() + + // compatibility when installing on Talos < 1.8 + if legacyImage || (hostTalosVersion != nil && hostTalosVersion.PrecreateStatePartition()) { + partitions = append(partitions, + partition.NewPartitionOptions(constants.StatePartitionLabel, false), + ) + } + + if legacyImage { + partitions = append(partitions, + partition.NewPartitionOptions(constants.EphemeralPartitionLabel, false), + ) + } + + for _, p := range partitions { + size := p.Size + + if size == 0 { + size = pt.LargestContiguousAllocatable() + } + + partitionTyp := uuid.MustParse(p.PartitionType) + + _, _, err = pt.AllocatePartition(size, p.PartitionLabel, partitionTyp) + if err != nil { + return fmt.Errorf("failed to allocate partition %s: %w", p.PartitionLabel, err) + } + + i.options.Printf("created %s (%s) size %d blocks", p.PartitionLabel, p.PartitionType, size) + } + + if err = pt.Write(); err != nil { + return fmt.Errorf("failed to write GPT: %w", err) + } + + // now format all partitions + for idx, p := range partitions { + devName := partitioning.DevName(i.options.Disk, uint(idx+1)) + + if err = partition.Format(devName, &p.FormatOptions, i.options.Printf); err != nil { + return fmt.Errorf("failed to format partition %s: %w", devName, err) + } + } + + return nil +} + func (i *Installer) runPreflightChecks(mode Mode) error { if mode != ModeUpgrade { // pre-flight checks only apply to upgrades @@ -431,30 +538,6 @@ func (i *Installer) runPreflightChecks(mode Mode) error { return checks.Run(ctx) } -func retryBlockdeviceOpen(device string) (*blockdevice.BlockDevice, error) { - var bd *blockdevice.BlockDevice - - err := retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(func() error { - var openErr error - - bd, openErr = blockdevice.Open(device, blockdevice.WithExclusiveLock(true)) - if openErr == nil { - return nil - } - - switch { - case os.IsNotExist(openErr): - return retry.ExpectedError(openErr) - case errors.Is(openErr, syscall.ENODEV), errors.Is(openErr, syscall.ENXIO): - return retry.ExpectedError(openErr) - default: - return nil - } - }) - - return bd, err -} - func overlayPresent() bool { _, err := os.Stat(constants.ImagerOverlayInstallerDefaultPath) diff --git a/cmd/installer/pkg/install/manifest.go b/cmd/installer/pkg/install/manifest.go deleted file mode 100644 index 2cf68d38f62..00000000000 --- a/cmd/installer/pkg/install/manifest.go +++ /dev/null @@ -1,545 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package install - -import ( - "bufio" - "context" - "errors" - "fmt" - "os" - "path/filepath" - "strings" - "time" - - "github.com/siderolabs/go-blockdevice/blockdevice" - "github.com/siderolabs/go-blockdevice/blockdevice/partition/gpt" - "github.com/siderolabs/go-retry/retry" - - "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" - "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/board" - "github.com/siderolabs/talos/internal/pkg/mount" - "github.com/siderolabs/talos/internal/pkg/partition" - "github.com/siderolabs/talos/pkg/machinery/constants" - "github.com/siderolabs/talos/pkg/machinery/imager/quirks" -) - -// Manifest represents the instructions for preparing all block devices -// for an installation. -type Manifest struct { - PartitionOptions *runtime.PartitionOptions - Devices map[string]Device - Targets map[string][]*Target - LegacyBIOSSupport bool - - Printf func(string, ...any) -} - -// Device represents device options. -type Device struct { - Device string - - ResetPartitionTable bool - Zero bool - - SkipOverlayMountsCheck bool -} - -// NewManifest initializes and returns a Manifest. -// -//nolint:gocyclo,cyclop -func NewManifest(mode Mode, uefiOnlyBoot bool, bootLoaderPresent bool, opts *Options) (manifest *Manifest, err error) { - manifest = &Manifest{ - Devices: map[string]Device{}, - Targets: map[string][]*Target{}, - LegacyBIOSSupport: opts.LegacyBIOSSupport, - - Printf: opts.Printf, - } - - if opts.Board != constants.BoardNone && !quirks.New(opts.Version).SupportsOverlay() { - if uefiOnlyBoot { - return nil, errors.New("board option can't be used with uefi-only-boot") - } - - var b runtime.Board - - b, err = board.NewBoard(opts.Board) - if err != nil { - return nil, err - } - - manifest.PartitionOptions = b.PartitionOptions() - } - - if opts.OverlayInstaller != nil { - overlayOpts, getOptsErr := opts.OverlayInstaller.GetOptions(opts.ExtraOptions) - if getOptsErr != nil { - return nil, fmt.Errorf("failed to get overlay installer options: %w", getOptsErr) - } - - if overlayOpts.PartitionOptions.Offset != 0 { - manifest.PartitionOptions = &runtime.PartitionOptions{ - PartitionsOffset: overlayOpts.PartitionOptions.Offset, - } - } - } - - // TODO: legacy, to support old Talos initramfs, assume force if boot partition not found - if !bootLoaderPresent { - opts.Force = true - } - - if !opts.Force && opts.Zero { - return nil, errors.New("zero option can't be used without force") - } - - if !opts.Force && !bootLoaderPresent { - return nil, errors.New("install with preserve is not supported if existing boot partition was not found") - } - - // Verify that the target device(s) can satisfy the requested options. - - if mode == ModeInstall { - if err = VerifyEphemeralPartition(opts); err != nil { - return nil, fmt.Errorf("failed to prepare ephemeral partition: %w", err) - } - } - - skipOverlayMountsCheck, err := shouldSkipOverlayMountsCheck(mode) - if err != nil { - return nil, err - } - - manifest.Devices[opts.Disk] = Device{ - Device: opts.Disk, - - ResetPartitionTable: opts.Force, - Zero: opts.Zero, - - SkipOverlayMountsCheck: skipOverlayMountsCheck, - } - - // Initialize any slices we need. Note that a boot partition is not - // required. - - if manifest.Targets[opts.Disk] == nil { - manifest.Targets[opts.Disk] = []*Target{} - } - - var targets []*Target - - // create GRUB BIOS+UEFI partitions, or only one big EFI partition if not using GRUB - if !uefiOnlyBoot { - targets = append(targets, - EFITarget(opts.Disk, nil), - BIOSTarget(opts.Disk, nil), - BootTarget(opts.Disk, &Target{ - PreserveContents: bootLoaderPresent, - }), - ) - } else { - targets = append(targets, - EFITargetUKI(opts.Disk, &Target{ - PreserveContents: bootLoaderPresent, - }), - ) - } - - targets = append(targets, - MetaTarget(opts.Disk, &Target{ - PreserveContents: bootLoaderPresent, - }), - StateTarget(opts.Disk, &Target{ - PreserveContents: bootLoaderPresent, - FormatOptions: &partition.FormatOptions{ - FileSystemType: partition.FilesystemTypeNone, - }, - }), - EphemeralTarget(opts.Disk, NoFilesystem), - ) - - if !opts.Force { - for _, target := range targets { - target.Force = false - target.Skip = true - } - } - - for _, target := range targets { - if target == nil { - continue - } - - manifest.Targets[target.Device] = append(manifest.Targets[target.Device], target) - } - - return manifest, nil -} - -// Execute partitions and formats all disks in a manifest. -func (m *Manifest) Execute() (err error) { - for dev, targets := range m.Targets { - if err = m.executeOnDevice(m.Devices[dev], targets); err != nil { - return err - } - } - - return nil -} - -// checkMounts verifies that no active mounts in any mount namespace exist for the device. -// -//nolint:gocyclo -func (m *Manifest) checkMounts(device Device) error { - matches, err := filepath.Glob("/proc/*/mountinfo") - if err != nil { - return err - } - - for _, path := range matches { - if err = func() error { - var f *os.File - - f, err = os.Open(path) - if err != nil { - // ignore error in case process got removed - return nil - } - - defer f.Close() //nolint:errcheck - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - fields := strings.Fields(scanner.Text()) - - if len(fields) < 2 { - continue - } - - if !device.SkipOverlayMountsCheck && fields[len(fields)-2] == "overlay" { - //nolint:dupword - // parsing options (last column) in the overlay mount line which looks like: - // 163 70 0:52 /apid / ro,relatime - overlay overlay rw,lowerdir=/opt,upperdir=/var/system/overlays/opt-diff,workdir=/var/system/overlays/opt-workdir - - options := strings.Split(fields[len(fields)-1], ",") - - for _, option := range options { - parts := strings.SplitN(option, "=", 2) - if len(parts) == 2 { - if strings.HasPrefix(parts[1], "/var/") { - return fmt.Errorf("found overlay mount in %q: %s", path, scanner.Text()) - } - } - } - } - - if strings.HasPrefix(fields[len(fields)-2], device.Device) { - return fmt.Errorf("found active mount in %q for %q: %s", path, device.Device, scanner.Text()) - } - } - - return f.Close() - }(); err != nil { - return err - } - } - - return nil -} - -//nolint:gocyclo,cyclop -func (m *Manifest) executeOnDevice(device Device, targets []*Target) (err error) { - if err = m.checkMounts(device); err != nil { - return err - } - - if err = m.preserveContents(device, targets); err != nil { - return err - } - - if device.Zero { - if err = partition.Format(device.Device, &partition.FormatOptions{ - FileSystemType: partition.FilesystemTypeNone, - }, m.Printf); err != nil { - return err - } - } - - var bd *blockdevice.BlockDevice - - if bd, err = blockdevice.Open(device.Device, blockdevice.WithExclusiveLock(true)); err != nil { - return err - } - - //nolint:errcheck - defer bd.Close() - - var pt *gpt.GPT - - created := false - - pt, err = bd.PartitionTable() - if err != nil { - if !errors.Is(err, blockdevice.ErrMissingPartitionTable) { - return err - } - - m.Printf("creating new partition table on %s", device.Device) - - gptOpts := []gpt.Option{ - gpt.WithMarkMBRBootable(m.LegacyBIOSSupport), - } - - if m.PartitionOptions != nil { - gptOpts = append(gptOpts, gpt.WithPartitionEntriesStartLBA(m.PartitionOptions.PartitionsOffset)) - } - - pt, err = gpt.New(bd.Device(), gptOpts...) - if err != nil { - return err - } - - m.Printf("logical/physical block size: %d/%d", pt.Header().LBA.LogicalBlockSize, pt.Header().LBA.PhysicalBlockSize) - m.Printf("minimum/optimal I/O size: %d/%d", pt.Header().LBA.MinimalIOSize, pt.Header().LBA.OptimalIOSize) - - if err = pt.Write(); err != nil { - return err - } - - if err = bd.Close(); err != nil { - return err - } - - if bd, err = blockdevice.Open(device.Device, blockdevice.WithExclusiveLock(true)); err != nil { - return err - } - - defer bd.Close() //nolint:errcheck - - created = true - } - - if !created { - if device.ResetPartitionTable { - m.Printf("resetting partition table on %s", device.Device) - - // TODO: how should it work with zero option above? - if err = bd.Reset(); err != nil { - return err - } - } else { - // clean up partitions which are going to be recreated - keepPartitions := map[string]struct{}{} - - for _, target := range targets { - if target.Skip { - keepPartitions[target.Label] = struct{}{} - } - } - - // make sure all partitions to be skipped already exist - missingPartitions := map[string]struct{}{} - - for label := range keepPartitions { - missingPartitions[label] = struct{}{} - } - - for _, part := range pt.Partitions().Items() { - delete(missingPartitions, part.Name) - } - - if len(missingPartitions) > 0 { - return fmt.Errorf("some partitions to be skipped are missing: %v", missingPartitions) - } - - // delete all partitions which are not skipped - for _, part := range pt.Partitions().Items() { - if _, ok := keepPartitions[part.Name]; !ok { - m.Printf("deleting partition %s", part.Name) - - if err = pt.Delete(part); err != nil { - return err - } - } - } - - if err = pt.Write(); err != nil { - return err - } - } - } - - pt, err = bd.PartitionTable() - if err != nil { - return err - } - - for i, target := range targets { - if err = target.partition(pt, i, m.Printf); err != nil { - return fmt.Errorf("failed to partition device: %w", err) - } - } - - if err = pt.Write(); err != nil { - return err - } - - for _, target := range targets { - err = retry.Constant(time.Minute, retry.WithUnits(100*time.Millisecond)).Retry(func() error { - e := target.Format(m.Printf) - if e != nil { - if strings.Contains(e.Error(), "No such file or directory") { - // workaround problem with partition device not being visible immediately after partitioning - return retry.ExpectedError(e) - } - - return e - } - - return nil - }) - if err != nil { - return fmt.Errorf("failed to format device: %w", err) - } - } - - return m.restoreContents(targets) -} - -//nolint:gocyclo -func (m *Manifest) preserveContents(device Device, targets []*Target) (err error) { - anyPreserveContents := false - - for _, target := range targets { - if target.Skip { - continue - } - - if target.PreserveContents { - anyPreserveContents = true - - break - } - } - - if !anyPreserveContents { - // no target to preserve contents, exit early - return nil - } - - var bd *blockdevice.BlockDevice - - if bd, err = blockdevice.Open(device.Device); err != nil { - // failed to open the block device, probably it's damaged? - m.Printf("warning: skipping preserve contents on %q as block device failed: %s", device.Device, err) - - return nil - } - - //nolint:errcheck - defer bd.Close() - - pt, err := bd.PartitionTable() - if err != nil { - m.Printf("warning: skipping preserve contents on %q as partition table failed: %s", device.Device, err) - - return nil - } - - for _, target := range targets { - if target.Skip { - continue - } - - if !target.PreserveContents { - continue - } - - var ( - sourcePart *gpt.Partition - fileSystemType partition.FileSystemType - fnmatchFilters []string - ) - - sources := append([]PreserveSource{ - { - Label: target.Label, - FileSystemType: target.FileSystemType, - }, - }, target.ExtraPreserveSources...) - - for _, source := range sources { - // find matching existing partition table entry - for _, part := range pt.Partitions().Items() { - if part.Name == source.Label { - sourcePart = part - fileSystemType = source.FileSystemType - fnmatchFilters = source.FnmatchFilters - - break - } - } - } - - if sourcePart == nil { - m.Printf("warning: failed to preserve contents of %q on %q, as source partition wasn't found", target.Label, device.Device) - - continue - } - - if err = target.SaveContents(device, sourcePart, fileSystemType, fnmatchFilters); err != nil { - m.Printf("warning: failed to preserve contents of %q on %q: %s", target.Label, device.Device, err) - } - } - - return nil -} - -func (m *Manifest) restoreContents(targets []*Target) error { - for _, target := range targets { - if err := target.RestoreContents(); err != nil { - return fmt.Errorf("error restoring contents for %q: %w", target.Label, err) - } - } - - return nil -} - -// SystemMountpoints returns list of system mountpoints for the manifest. -func (m *Manifest) SystemMountpoints(ctx context.Context, opts ...mount.Option) (*mount.Points, error) { - mountpoints := mount.NewMountPoints() - - for dev := range m.Targets { - mp, err := mount.SystemMountPointsForDevice(ctx, dev, opts...) - if err != nil { - return nil, err - } - - iter := mp.Iter() - for iter.Next() { - mountpoints.Set(iter.Key(), iter.Value()) - } - } - - return mountpoints, nil -} - -func shouldSkipOverlayMountsCheck(mode Mode) (bool, error) { - var skipOverlayMountsCheck bool - - _, err := os.Stat("/.dockerenv") - - switch { - case err == nil: - skipOverlayMountsCheck = true - case os.IsNotExist(err): - skipOverlayMountsCheck = mode.IsImage() - default: - return false, fmt.Errorf("cannot determine if /.dockerenv exists: %w", err) - } - - return skipOverlayMountsCheck, nil -} diff --git a/cmd/installer/pkg/install/manifest_test.go b/cmd/installer/pkg/install/manifest_test.go deleted file mode 100644 index 4a2d53fd1e6..00000000000 --- a/cmd/installer/pkg/install/manifest_test.go +++ /dev/null @@ -1,328 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package install_test - -import ( - "context" - "fmt" - "io" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/siderolabs/go-blockdevice/blockdevice" - "github.com/siderolabs/go-blockdevice/blockdevice/loopback" - "github.com/stretchr/testify/suite" - - "github.com/siderolabs/talos/cmd/installer/pkg/install" - "github.com/siderolabs/talos/internal/pkg/mount" - "github.com/siderolabs/talos/internal/pkg/partition" - "github.com/siderolabs/talos/pkg/machinery/constants" -) - -// Some tests in this package cannot be run under buildkit, as buildkit doesn't propagate partition devices -// like /dev/loopXpY into the sandbox. To run the tests on your local computer, do the following: -// -// go test -exec sudo -v --count 1 ./cmd/installer/pkg/install/ - -type manifestSuite struct { - suite.Suite - - disk *os.File - loopbackDevice *os.File -} - -const ( - diskSize = 4 * 1024 * 1024 * 1024 // 4 GiB - lbaSize = 512 - gptReserved = 67 -) - -func TestManifestSuite(t *testing.T) { - suite.Run(t, new(manifestSuite)) -} - -func (suite *manifestSuite) SetupTest() { - suite.skipIfNotRoot() - - var err error - - suite.disk, err = os.CreateTemp("", "talos") - suite.Require().NoError(err) - - suite.Require().NoError(suite.disk.Truncate(diskSize)) - - suite.loopbackDevice, err = loopback.NextLoopDevice() - suite.Require().NoError(err) - - suite.T().Logf("Using %s", suite.loopbackDevice.Name()) - - suite.Require().NoError(loopback.Loop(suite.loopbackDevice, suite.disk)) - - suite.Require().NoError(loopback.LoopSetReadWrite(suite.loopbackDevice)) - - // set the env vars xfsprogs expects to use Talos STATE partition which is 100Megs - // whereas xfs expects a default minimum size of 300Megs if these are not set. - // Ref: https://git.kernel.org/pub/scm/fs/xfs/xfsprogs-dev.git/tree/mkfs/xfs_mkfs.c?h=v6.3.0#n2582 - suite.T().Setenv("TEST_DIR", "true") - suite.T().Setenv("TEST_DEV", "true") - suite.T().Setenv("QA_CHECK_FS", "true") -} - -func (suite *manifestSuite) TearDownTest() { - if suite.loopbackDevice != nil { - suite.Assert().NoError(loopback.Unloop(suite.loopbackDevice)) - } - - if suite.disk != nil { - suite.Assert().NoError(os.Remove(suite.disk.Name())) - suite.Assert().NoError(suite.disk.Close()) - } -} - -func (suite *manifestSuite) skipUnderBuildkit() { - hostname, _ := os.Hostname() //nolint:errcheck - - if hostname == "buildkitsandbox" { - suite.T().Skip("test not supported under buildkit as partition devices are not propagated from /dev") - } -} - -func (suite *manifestSuite) skipIfNotRoot() { - if os.Getuid() != 0 { - suite.T().Skip("can't run the test as non-root") - } -} - -func (suite *manifestSuite) verifyBlockdevice(manifest *install.Manifest, current, next string, verifyConfigPersistence, verifyEphemeralPersistence bool) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - bd, err := blockdevice.Open(suite.loopbackDevice.Name()) - suite.Require().NoError(err) - - defer bd.Close() //nolint:errcheck - - table, err := bd.PartitionTable() - suite.Require().NoError(err) - - // verify partition table - - suite.Assert().Len(table.Partitions().Items(), 6) - - part := table.Partitions().Items()[0] - suite.Assert().Equal(partition.EFISystemPartition, strings.ToUpper(part.Type.String())) - suite.Assert().Equal(constants.EFIPartitionLabel, part.Name) - suite.Assert().EqualValues(0, part.Attributes) - suite.Assert().EqualValues(partition.EFISize/lbaSize, part.Length()) - - part = table.Partitions().Items()[1] - suite.Assert().Equal(partition.BIOSBootPartition, strings.ToUpper(part.Type.String())) - suite.Assert().Equal(constants.BIOSGrubPartitionLabel, part.Name) - suite.Assert().EqualValues(4, part.Attributes) - suite.Assert().EqualValues(partition.BIOSGrubSize/lbaSize, part.Length()) - - part = table.Partitions().Items()[2] - suite.Assert().Equal(partition.LinuxFilesystemData, strings.ToUpper(part.Type.String())) - suite.Assert().Equal(constants.BootPartitionLabel, part.Name) - suite.Assert().EqualValues(0, part.Attributes) - suite.Assert().EqualValues(partition.BootSize/lbaSize, part.Length()) - - part = table.Partitions().Items()[3] - suite.Assert().Equal(partition.LinuxFilesystemData, strings.ToUpper(part.Type.String())) - suite.Assert().Equal(constants.MetaPartitionLabel, part.Name) - suite.Assert().EqualValues(0, part.Attributes) - suite.Assert().EqualValues(partition.MetaSize/lbaSize, part.Length()) - - part = table.Partitions().Items()[4] - suite.Assert().Equal(partition.LinuxFilesystemData, strings.ToUpper(part.Type.String())) - suite.Assert().Equal(constants.StatePartitionLabel, part.Name) - suite.Assert().EqualValues(0, part.Attributes) - - suite.Assert().EqualValues(partition.StateSize/lbaSize, part.Length()) - - part = table.Partitions().Items()[5] - suite.Assert().Equal(partition.LinuxFilesystemData, strings.ToUpper(part.Type.String())) - suite.Assert().Equal(constants.EphemeralPartitionLabel, part.Name) - suite.Assert().EqualValues(0, part.Attributes) - suite.Assert().Greater(part.Length(), uint64(1024*1024*1024/lbaSize)) - - suite.Assert().NoError(bd.Close()) - - // query mount points directly for the device - - mountpoints, err := mount.SystemMountPointsForDevice(ctx, suite.loopbackDevice.Name()) - suite.Require().NoError(err) - - suite.Assert().Equal(4, mountpoints.Len()) - - // verify filesystems by mounting and unmounting - - tempDir := suite.T().TempDir() - - mountpoints, err = manifest.SystemMountpoints(ctx) - suite.Require().NoError(err) - - suite.Assert().Equal(4, mountpoints.Len()) - - suite.Require().NoError(mount.PrefixMountTargets(mountpoints, tempDir)) - - err = mount.Mount(mountpoints) - suite.Require().NoError(err) - - defer func() { - suite.Assert().NoError(mount.Unmount(mountpoints)) - }() - - metaPath := fmt.Sprintf("%sp%d", suite.loopbackDevice.Name(), table.Partitions().Items()[3].Number) - - if verifyConfigPersistence { - suite.Assert().FileExists(filepath.Join(tempDir, "system", "state", "config.yaml")) - } - - if verifyEphemeralPersistence { - suite.Assert().FileExists(filepath.Join(tempDir, "var", "content")) - } - - if current != "" { - // verify that current was preserved - suite.Assert().DirExists(filepath.Join(tempDir, "boot", current)) - - suite.Assert().FileExists(filepath.Join(tempDir, "boot", current, "kernel")) - - buf := make([]byte, len(current)) - - f, err := os.Open(metaPath) - suite.Require().NoError(err) - - _, err = io.ReadFull(f, buf) - suite.Require().NoError(err) - - suite.Assert().Equal(current, string(buf)) - - suite.Assert().NoError(f.Close()) - } - - if next != "" { - suite.Assert().NoError(os.MkdirAll(filepath.Join(tempDir, "boot", next), 0o700)) - suite.Assert().NoError(os.WriteFile(filepath.Join(tempDir, "boot", next, "kernel"), []byte("LINUX!"), 0o660)) - suite.Assert().NoError(os.WriteFile(filepath.Join(tempDir, "system", "state", "config.yaml"), []byte("#!yaml"), 0o660)) - - buf := []byte(next) - - f, err := os.OpenFile(metaPath, os.O_WRONLY, 0) - suite.Require().NoError(err) - - _, err = f.Write(buf) - suite.Require().NoError(err) - - suite.Assert().NoError(f.Close()) - } - - suite.Assert().NoError(os.WriteFile(filepath.Join(tempDir, "var", "content"), []byte("data"), 0o600)) -} - -func (suite *manifestSuite) TestExecuteManifestClean() { - suite.skipUnderBuildkit() - - manifest, err := install.NewManifest(install.ModeInstall, false, false, &install.Options{ - Disk: suite.loopbackDevice.Name(), - Force: true, - Board: constants.BoardNone, - Printf: suite.T().Logf, - }) - suite.Require().NoError(err) - - // in the tests overlay mounts should be ignored - dev := manifest.Devices[suite.loopbackDevice.Name()] - dev.SkipOverlayMountsCheck = true - manifest.Devices[suite.loopbackDevice.Name()] = dev - - suite.Assert().NoError(manifest.Execute()) - - suite.verifyBlockdevice(manifest, "", "A", false, false) -} - -func (suite *manifestSuite) TestExecuteManifestForce() { - suite.skipUnderBuildkit() - - manifest, err := install.NewManifest(install.ModeInstall, false, false, &install.Options{ - Disk: suite.loopbackDevice.Name(), - Force: true, - Board: constants.BoardNone, - Printf: suite.T().Logf, - }) - suite.Require().NoError(err) - - // in the tests overlay mounts should be ignored - dev := manifest.Devices[suite.loopbackDevice.Name()] - dev.SkipOverlayMountsCheck = true - manifest.Devices[suite.loopbackDevice.Name()] = dev - - suite.Assert().NoError(manifest.Execute()) - - suite.verifyBlockdevice(manifest, "", "A", false, false) - - // reinstall - - manifest, err = install.NewManifest(install.ModeUpgrade, false, true, &install.Options{ - Disk: suite.loopbackDevice.Name(), - Force: true, - Zero: true, - Board: constants.BoardNone, - Printf: suite.T().Logf, - }) - suite.Require().NoError(err) - - // in the tests overlay mounts should be ignored - dev = manifest.Devices[suite.loopbackDevice.Name()] - dev.SkipOverlayMountsCheck = true - manifest.Devices[suite.loopbackDevice.Name()] = dev - - suite.Assert().NoError(manifest.Execute()) - - suite.verifyBlockdevice(manifest, "A", "B", true, false) -} - -func (suite *manifestSuite) TestExecuteManifestPreserve() { - suite.skipUnderBuildkit() - - manifest, err := install.NewManifest(install.ModeInstall, false, false, &install.Options{ - Disk: suite.loopbackDevice.Name(), - Force: true, - Board: constants.BoardNone, - Printf: suite.T().Logf, - }) - suite.Require().NoError(err) - - // in the tests overlay mounts should be ignored - dev := manifest.Devices[suite.loopbackDevice.Name()] - dev.SkipOverlayMountsCheck = true - manifest.Devices[suite.loopbackDevice.Name()] = dev - - suite.Assert().NoError(manifest.Execute()) - - suite.verifyBlockdevice(manifest, "", "A", false, false) - - // reinstall - - manifest, err = install.NewManifest(install.ModeUpgrade, false, true, &install.Options{ - Disk: suite.loopbackDevice.Name(), - Force: false, - Board: constants.BoardNone, - Printf: suite.T().Logf, - }) - suite.Require().NoError(err) - - // in the tests overlay mounts should be ignored - dev = manifest.Devices[suite.loopbackDevice.Name()] - dev.SkipOverlayMountsCheck = true - manifest.Devices[suite.loopbackDevice.Name()] = dev - - suite.Assert().NoError(manifest.Execute()) - - suite.verifyBlockdevice(manifest, "A", "B", true, true) -} diff --git a/cmd/installer/pkg/install/target.go b/cmd/installer/pkg/install/target.go deleted file mode 100644 index 63aefeea238..00000000000 --- a/cmd/installer/pkg/install/target.go +++ /dev/null @@ -1,371 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package install - -import ( - "bytes" - "compress/gzip" - "context" - "fmt" - "io" - "log" - "os" - "path/filepath" - - "github.com/siderolabs/go-blockdevice/blockdevice/partition/gpt" - "github.com/siderolabs/go-blockdevice/blockdevice/util" - "golang.org/x/sys/unix" - - "github.com/siderolabs/talos/internal/pkg/mount" - "github.com/siderolabs/talos/internal/pkg/partition" - "github.com/siderolabs/talos/pkg/archiver" - "github.com/siderolabs/talos/pkg/machinery/constants" -) - -// Target represents an installation partition. -// -//nolint:maligned -type Target struct { - *partition.FormatOptions - *partition.Options - Device string - - LegacyBIOSBootable bool - - // Preserve contents of the partition with the same label (if it exists). - PreserveContents bool - - // Extra preserved locations (for upgrading from older versions of Talos). - // - // Used only if PreserveContents is true. - ExtraPreserveSources []PreserveSource - - // Skip makes manifest skip any actions with the partition (creating, formatting). - // - // Skipped partitions should exist on the disk by the time manifest execution starts. - Skip bool - - // set during execution - PartitionName string - Contents *bytes.Buffer -} - -// PreserveSource instructs Talos where to look for source files to preserve. -type PreserveSource struct { - Label string - FnmatchFilters []string - FileSystemType partition.FileSystemType -} - -// NoFilesystem preset to override default filesystem type to none. -var NoFilesystem = &Target{ - FormatOptions: &partition.FormatOptions{ - FileSystemType: partition.FilesystemTypeNone, - }, -} - -// ParseTarget parses the target from the label and creates a required target. -func ParseTarget(label, deviceName string) (*Target, error) { - switch label { - case constants.EFIPartitionLabel: - return EFITarget(deviceName, nil), nil - case constants.BIOSGrubPartitionLabel: - return BIOSTarget(deviceName, nil), nil - case constants.BootPartitionLabel: - return BootTarget(deviceName, nil), nil - case constants.MetaPartitionLabel: - return MetaTarget(deviceName, nil), nil - case constants.StatePartitionLabel: - return StateTarget(deviceName, NoFilesystem), nil - case constants.EphemeralPartitionLabel: - return EphemeralTarget(deviceName, NoFilesystem), nil - default: - return nil, fmt.Errorf("label %q is not supported", label) - } -} - -// EFITarget builds the default EFI target. -func EFITarget(device string, extra *Target) *Target { - target := &Target{ - FormatOptions: partition.NewFormatOptions(constants.EFIPartitionLabel), - Options: partition.NewPartitionOptions(constants.EFIPartitionLabel, false), - Device: device, - } - - return target.enhance(extra) -} - -// EFITargetUKI builds the default EFI UKI target. -func EFITargetUKI(device string, extra *Target) *Target { - target := &Target{ - FormatOptions: partition.NewFormatOptions(constants.EFIPartitionLabel), - Options: partition.NewPartitionOptions(constants.EFIPartitionLabel, true), - Device: device, - } - - return target.enhance(extra) -} - -// BIOSTarget builds the default BIOS target. -func BIOSTarget(device string, extra *Target) *Target { - target := &Target{ - FormatOptions: partition.NewFormatOptions(constants.BIOSGrubPartitionLabel), - Options: partition.NewPartitionOptions(constants.BIOSGrubPartitionLabel, false), - Device: device, - LegacyBIOSBootable: true, - } - - return target.enhance(extra) -} - -// BootTarget builds the default boot target. -func BootTarget(device string, extra *Target) *Target { - target := &Target{ - FormatOptions: partition.NewFormatOptions(constants.BootPartitionLabel), - Options: partition.NewPartitionOptions(constants.BootPartitionLabel, false), - Device: device, - } - - return target.enhance(extra) -} - -// MetaTarget builds the default meta target. -func MetaTarget(device string, extra *Target) *Target { - target := &Target{ - FormatOptions: partition.NewFormatOptions(constants.MetaPartitionLabel), - Options: partition.NewPartitionOptions(constants.MetaPartitionLabel, false), - Device: device, - } - - return target.enhance(extra) -} - -// StateTarget builds the default state target. -func StateTarget(device string, extra *Target) *Target { - target := &Target{ - FormatOptions: partition.NewFormatOptions(constants.StatePartitionLabel), - Options: partition.NewPartitionOptions(constants.StatePartitionLabel, false), - Device: device, - } - - return target.enhance(extra) -} - -// EphemeralTarget builds the default ephemeral target. -func EphemeralTarget(device string, extra *Target) *Target { - target := &Target{ - FormatOptions: partition.NewFormatOptions(constants.EphemeralPartitionLabel), - Options: partition.NewPartitionOptions(constants.EphemeralPartitionLabel, false), - Device: device, - } - - return target.enhance(extra) -} - -func (t *Target) enhance(extra *Target) *Target { - if extra == nil { - return t - } - - t.PreserveContents = extra.PreserveContents - t.ExtraPreserveSources = extra.ExtraPreserveSources - t.Skip = extra.Skip - - if extra.FormatOptions != nil { - t.FormatOptions.FileSystemType = extra.FormatOptions.FileSystemType - } - - return t -} - -func (t *Target) String() string { - return fmt.Sprintf("%s (%q)", t.PartitionName, t.Label) -} - -// Locate existing partition on the disk. -func (t *Target) Locate(pt *gpt.GPT) (*gpt.Partition, error) { - part, err := partition.Locate(pt, t.Label) - if err != nil { - return nil, err - } - - t.PartitionName, err = part.Path() - if err != nil { - return nil, err - } - - return part, nil -} - -// partition creates a new partition on the specified device. -func (t *Target) partition(pt *gpt.GPT, pos int, printf func(string, ...any)) (err error) { - if t.Skip { - part := pt.Partitions().FindByName(t.Label) - if part != nil { - printf("skipped %s (%s) size %d blocks", t.PartitionName, t.Label, part.Length()) - - t.PartitionName, err = part.Path() - if err != nil { - return err - } - } - - return nil - } - - partitionName, err := partition.Partition(pt, pos, t.Device, partition.Options{ - PartitionLabel: t.Label, - PartitionType: t.PartitionType, - Size: t.Size, - LegacyBIOSBootable: t.LegacyBIOSBootable, - }, printf) - if err != nil { - return err - } - - t.PartitionName = partitionName - - return nil -} - -// Format creates a filesystem on the device/partition. -func (t *Target) Format(printf func(string, ...any)) error { - if t.Skip { - return nil - } - - return partition.Format(t.PartitionName, t.FormatOptions, printf) -} - -// GetLabel returns the underlaying partition label. -func (t *Target) GetLabel() string { - return t.Label -} - -func withTemporaryMounted(partPath string, flags uintptr, fileSystemType partition.FileSystemType, label string, f func(mountPath string) error) error { - mountPath := filepath.Join(constants.SystemPath, "mnt") - - mountpoints := mount.NewMountPoints() - - mountpoint := mount.NewMountPoint(partPath, mountPath, fileSystemType, unix.MS_NOATIME|flags, "") - mountpoints.Set(label, mountpoint) - - if err := mount.Mount(mountpoints); err != nil { - return fmt.Errorf("failed to mount %q: %w", partPath, err) - } - - defer func() { - if err := mount.Unmount(mountpoints); err != nil { - log.Printf("failed to unmount: %s", err) - } - }() - - return f(mountPath) -} - -// SaveContents saves contents of partition to the target (in-memory). -func (t *Target) SaveContents(device Device, source *gpt.Partition, fileSystemType partition.FileSystemType, fnmatchFilters []string) error { - partPath, err := util.PartPath(device.Device, int(source.Number)) - if err != nil { - return err - } - - if fileSystemType == partition.FilesystemTypeNone { - err = t.saveRawContents(partPath) - } else { - err = t.saveFilesystemContents(partPath, fileSystemType, fnmatchFilters) - } - - if err != nil { - t.Contents = nil - - return err - } - - log.Printf("preserved contents of %q: %d bytes", t.Label, t.Contents.Len()) - - return nil -} - -func (t *Target) saveRawContents(partPath string) error { - src, err := os.Open(partPath) - if err != nil { - return fmt.Errorf("error opening source partition: %q", err) - } - - defer src.Close() //nolint:errcheck - - t.Contents = bytes.NewBuffer(nil) - - zw := gzip.NewWriter(t.Contents) - defer zw.Close() //nolint:errcheck - - _, err = io.Copy(zw, src) - if err != nil { - return fmt.Errorf("error copying partition %q contents: %w", partPath, err) - } - - return src.Close() -} - -func (t *Target) saveFilesystemContents(partPath string, fileSystemType partition.FileSystemType, fnmatchFilters []string) error { - t.Contents = bytes.NewBuffer(nil) - - return withTemporaryMounted(partPath, unix.MS_RDONLY, fileSystemType, t.Label, func(mountPath string) error { - return archiver.TarGz(context.TODO(), mountPath, t.Contents, archiver.WithFnmatchPatterns(fnmatchFilters...)) - }) -} - -// RestoreContents restores previously saved contents to the disk. -func (t *Target) RestoreContents() error { - if t.Contents == nil { - return nil - } - - var err error - - if t.FileSystemType == partition.FilesystemTypeNone { - err = t.restoreRawContents() - } else { - err = t.restoreFilesystemContents() - } - - t.Contents = nil - - if err != nil { - return err - } - - log.Printf("restored contents of %q", t.Label) - - return nil -} - -func (t *Target) restoreRawContents() error { - dst, err := os.OpenFile(t.PartitionName, os.O_WRONLY, 0) - if err != nil { - return fmt.Errorf("error opening source partition: %q", err) - } - - defer dst.Close() //nolint:errcheck - - zr, err := gzip.NewReader(t.Contents) - if err != nil { - return err - } - - _, err = io.Copy(dst, zr) - if err != nil { - return fmt.Errorf("error restoring partition %q contents: %w", t.PartitionName, err) - } - - return dst.Close() -} - -func (t *Target) restoreFilesystemContents() error { - return withTemporaryMounted(t.PartitionName, 0, t.FileSystemType, t.Label, func(mountPath string) error { - return archiver.UntarGz(context.TODO(), t.Contents, mountPath) - }) -} diff --git a/cmd/installer/pkg/install/target_test.go b/cmd/installer/pkg/install/target_test.go deleted file mode 100644 index 1f4d8650cde..00000000000 --- a/cmd/installer/pkg/install/target_test.go +++ /dev/null @@ -1,54 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -package install_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/siderolabs/talos/cmd/installer/pkg/install" -) - -func TestParseTarget(t *testing.T) { - type args struct { - label string - deviceName string - } - - tests := map[string]struct { - args args - want *install.Target - wantErr bool - }{ - "EPHEMERAL": { - args: args{ - label: "EPHEMERAL", - deviceName: "/dev/sda", - }, - want: install.EphemeralTarget("/dev/sda", install.NoFilesystem), - }, - "UNKNOWN": { - args: args{ - label: "UNKNOWN", - deviceName: "/dev/sda", - }, - wantErr: true, - }, - } - - for name, tt := range tests { - t.Run(name, func(t *testing.T) { - got, err := install.ParseTarget(tt.args.label, tt.args.deviceName) - if (err != nil) != tt.wantErr { - t.Errorf("ParseTarget() error = %v, wantErr %v", err, tt.wantErr) - - return - } - - require.Equal(t, tt.want, got) - }) - } -} diff --git a/go.mod b/go.mod index 6e2ac325c3c..6ea67c837d3 100644 --- a/go.mod +++ b/go.mod @@ -183,6 +183,8 @@ require ( sigs.k8s.io/yaml v1.4.0 ) +require github.com/siderolabs/protoenc v0.2.1 + require ( github.com/0x5a17ed/itkit v0.6.0 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect @@ -198,6 +200,7 @@ require ( github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect github.com/ProtonMail/gopenpgp/v2 v2.7.5 // indirect github.com/adrg/xdg v0.4.0 // indirect + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/apparentlymart/go-cidr v1.1.0 // indirect github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 // indirect github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect @@ -252,6 +255,7 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.2 // indirect + github.com/google/cel-go v0.20.1 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect @@ -312,10 +316,10 @@ require ( github.com/prometheus/common v0.55.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/siderolabs/protoenc v0.2.1 // indirect github.com/siderolabs/tcpproxy v0.1.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/afero v1.10.0 // indirect + github.com/stoewer/go-strcase v1.3.0 // indirect github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect github.com/u-root/uio v0.0.0-20240209044354-b3d14b93376a // indirect github.com/vbatts/tar-split v0.11.3 // indirect diff --git a/go.sum b/go.sum index 0dd1ba404f8..87e394f876a 100644 --- a/go.sum +++ b/go.sum @@ -48,6 +48,8 @@ github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E github.com/alexflint/go-filemutex v1.3.0 h1:LgE+nTUWnQCyRKbpoceKZsPQbs84LivvgwUymZXdOcM= github.com/alexflint/go-filemutex v1.3.0/go.mod h1:U0+VA/i30mGBlLCrFPGtTe9y6wGQfNAWPBTekHQ+c8A= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 h1:7Ip0wMmLHLRJdrloDxZfhMm0xrLXZS8+COSu2bXmEQs= @@ -284,6 +286,8 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6 github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84= +github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -642,6 +646,8 @@ github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/hack/structprotogen/proto/proto.go b/hack/structprotogen/proto/proto.go index 79c7aa8326a..04ff58fff5d 100644 --- a/hack/structprotogen/proto/proto.go +++ b/hack/structprotogen/proto/proto.go @@ -392,6 +392,8 @@ func formatTypeName(fieldTypePkg string, fieldType string, declPkg string) (stri return commoProto, "common.PEMEncodedKey" case typeData{"github.com/siderolabs/crypto/x509", "PEMEncodedCertificate"}: return commoProto, "common.PEMEncodedCertificate" + case typeData{"github.com/siderolabs/talos/pkg/machinery/cel", "Expression"}: + return "google/api/expr/v1alpha1/checked.proto", "google.api.expr.v1alpha1.CheckedExpr" default: return "", "" } diff --git a/internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go b/internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go index 0cd85df15cc..6c7fbda66a6 100644 --- a/internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go +++ b/internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go @@ -34,7 +34,6 @@ import ( "github.com/prometheus/procfs" "github.com/rs/xid" "github.com/siderolabs/gen/xslices" - "github.com/siderolabs/go-blockdevice/blockdevice/partition/gpt" bddisk "github.com/siderolabs/go-blockdevice/blockdevice/util/disk" "github.com/siderolabs/go-kmsg" "github.com/siderolabs/go-pointer" @@ -49,9 +48,7 @@ import ( "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/emptypb" - installer "github.com/siderolabs/talos/cmd/installer/pkg/install" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" - "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader" "github.com/siderolabs/talos/internal/app/machined/pkg/system" "github.com/siderolabs/talos/internal/app/resources" storaged "github.com/siderolabs/talos/internal/app/storaged" @@ -356,6 +353,7 @@ func (s *Server) Rollback(ctx context.Context, in *machine.RollbackRequest) (*ma return nil, err } + /* [TODO] restore me systemDisk := s.Controller.Runtime().State().Machine().Disk() if systemDisk == nil { return nil, status.Errorf(codes.FailedPrecondition, "system disk not found") @@ -371,6 +369,7 @@ func (s *Server) Rollback(ctx context.Context, in *machine.RollbackRequest) (*ma }(); err != nil { return nil, err } + */ go func() { if err := s.Controller.Run(context.Background(), runtime.SequenceReboot, in, runtime.WithTakeover()); err != nil { @@ -552,17 +551,18 @@ func (s *Server) Upgrade(ctx context.Context, in *machine.UpgradeRequest) (*mach type ResetOptions struct { *machine.ResetRequest - systemDiskTargets []*installer.Target + // [TODO]: restore me + //systemDiskTargets []*installer.Target } // GetSystemDiskTargets implements runtime.ResetOptions interface. -func (opt *ResetOptions) GetSystemDiskTargets() []runtime.PartitionTarget { - if opt.systemDiskTargets == nil { - return nil - } +// func (opt *ResetOptions) GetSystemDiskTargets() []runtime.PartitionTarget { +// if opt.systemDiskTargets == nil { +// return nil +// } - return xslices.Map(opt.systemDiskTargets, func(t *installer.Target) runtime.PartitionTarget { return t }) -} +// return xslices.Map(opt.systemDiskTargets, func(t *installer.Target) runtime.PartitionTarget { return t }) +// } // Reset resets the node. // @@ -611,36 +611,37 @@ func (s *Server) Reset(ctx context.Context, in *machine.ResetRequest) (reply *ma } } - if len(in.GetSystemPartitionsToWipe()) > 0 { - if in.Mode == machine.ResetRequest_USER_DISKS { - return nil, errors.New("reset failed: invalid input, wipe mode USER_DISKS doesn't support SystemPartitionsToWipe parameter") - } - - bd := s.Controller.Runtime().State().Machine().Disk().BlockDevice + /* + if len(in.GetSystemPartitionsToWipe()) > 0 { + if in.Mode == machine.ResetRequest_USER_DISKS { + return nil, errors.New("reset failed: invalid input, wipe mode USER_DISKS doesn't support SystemPartitionsToWipe parameter") + } - var pt *gpt.GPT + bd := s.Controller.Runtime().State().Machine().Disk().BlockDevice - pt, err = bd.PartitionTable() - if err != nil { - return nil, fmt.Errorf("error reading partition table: %w", err) - } + var pt *gpt.GPT - for _, spec := range in.GetSystemPartitionsToWipe() { - target, err := installer.ParseTarget(spec.Label, bd.Device().Name()) + pt, err = bd.PartitionTable() if err != nil { - return nil, err + return nil, fmt.Errorf("error reading partition table: %w", err) } - _, err = target.Locate(pt) - if err != nil { - return nil, fmt.Errorf("failed location partition with label %q: %w", spec.Label, err) - } + for _, spec := range in.GetSystemPartitionsToWipe() { + target, err := installer.ParseTarget(spec.Label, bd.Device().Name()) + if err != nil { + return nil, err + } - if spec.Wipe { - opts.systemDiskTargets = append(opts.systemDiskTargets, target) + _, err = target.Locate(pt) + if err != nil { + return nil, fmt.Errorf("failed location partition with label %q: %w", spec.Label, err) + } + + if spec.Wipe { + opts.systemDiskTargets = append(opts.systemDiskTargets, target) + } } - } - } + }*/ resetCtx := context.WithValue(context.Background(), runtime.ActorIDCtxKey{}, actorID) diff --git a/internal/app/machined/pkg/controllers/block/discovery.go b/internal/app/machined/pkg/controllers/block/discovery.go index 9244411ffd2..802e375e9c8 100644 --- a/internal/app/machined/pkg/controllers/block/discovery.go +++ b/internal/app/machined/pkg/controllers/block/discovery.go @@ -9,7 +9,6 @@ import ( "errors" "fmt" "path/filepath" - "strconv" "time" "github.com/cosi-project/runtime/pkg/controller" @@ -17,6 +16,7 @@ import ( "github.com/cosi-project/runtime/pkg/state" "github.com/siderolabs/gen/maps" "github.com/siderolabs/go-blockdevice/v2/blkid" + "github.com/siderolabs/go-blockdevice/v2/partitioning" "go.uber.org/zap" "github.com/siderolabs/talos/pkg/machinery/resources/block" @@ -38,6 +38,11 @@ func (ctrl *DiscoveryController) Inputs() []controller.Input { Type: block.DeviceType, Kind: controller.InputWeak, }, + { + Namespace: block.NamespaceName, + Type: block.DiscoveryRefreshRequestType, + Kind: controller.InputWeak, + }, } } @@ -48,18 +53,25 @@ func (ctrl *DiscoveryController) Outputs() []controller.Output { Type: block.DiscoveredVolumeType, Kind: controller.OutputExclusive, }, + { + Type: block.DiscoveryRefreshStatusType, + Kind: controller.OutputExclusive, + }, } } // Run implements controller.Controller interface. // -//nolint:gocyclo +//nolint:gocyclo,cyclop func (ctrl *DiscoveryController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error { // lastObservedGenerations holds the last observed generation of each device. // // when the generation of a device changes, the device might have changed and might need to be re-probed. lastObservedGenerations := map[string]int{} + // whenever new DiscoveryRefresh requests are received, the devices are re-probed. + var lastObservedDiscoveryRefreshRequest int + // nextRescan holds the pool of devices to be rescanned in the next batch. nextRescan := map[string]int{} @@ -86,7 +98,27 @@ func (ctrl *DiscoveryController) Run(ctx context.Context, r controller.Runtime, nextRescan[id] = lastObservedGenerations[id] } } + + if err := safe.WriterModify(ctx, r, block.NewDiscoveryRefreshStatus(block.NamespaceName, block.RefreshID), func(status *block.DiscoveryRefreshStatus) error { + status.TypedSpec().Request = lastObservedDiscoveryRefreshRequest + + return nil + }); err != nil { + return fmt.Errorf("failed to write discovery refresh status: %w", err) + } case <-r.EventCh(): + refreshRequest, err := safe.ReaderGetByID[*block.DiscoveryRefreshRequest](ctx, r, block.RefreshID) + if err != nil && !state.IsNotFoundError(err) { + return fmt.Errorf("failed to get refresh request: %w", err) + } + + if refreshRequest != nil && refreshRequest.TypedSpec().Request != lastObservedDiscoveryRefreshRequest { + lastObservedDiscoveryRefreshRequest = refreshRequest.TypedSpec().Request + + // force re-probe all devices + clear(lastObservedGenerations) + } + devices, err := safe.ReaderListAll[*block.Device](ctx, r) if err != nil { return fmt.Errorf("failed to list devices: %w", err) @@ -169,9 +201,11 @@ func (ctrl *DiscoveryController) rescan(ctx context.Context, r controller.Runtim logger.Debug("probed device", zap.String("id", id), zap.Any("info", info)) if err = safe.WriterModify(ctx, r, block.NewDiscoveredVolume(block.NamespaceName, id), func(dv *block.DiscoveredVolume) error { + dv.TypedSpec().DevPath = filepath.Join("/dev", id) dv.TypedSpec().Type = device.TypedSpec().Type dv.TypedSpec().DevicePath = device.TypedSpec().DevicePath dv.TypedSpec().Parent = device.TypedSpec().Parent + dv.TypedSpec().ParentDevPath = filepath.Join("/dev", device.TypedSpec().Parent) dv.TypedSpec().Size = info.Size dv.TypedSpec().SectorSize = info.SectorSize @@ -187,12 +221,14 @@ func (ctrl *DiscoveryController) rescan(ctx context.Context, r controller.Runtim touchedIDs[id] = struct{}{} for _, nested := range info.Parts { - partID := partitionID(id, nested.PartitionIndex) + partID := partitioning.DevName(id, nested.PartitionIndex) if err = safe.WriterModify(ctx, r, block.NewDiscoveredVolume(block.NamespaceName, partID), func(dv *block.DiscoveredVolume) error { dv.TypedSpec().Type = "partition" + dv.TypedSpec().DevPath = filepath.Join("/dev", partID) dv.TypedSpec().DevicePath = filepath.Join(device.TypedSpec().DevicePath, partID) dv.TypedSpec().Parent = id + dv.TypedSpec().ParentDevPath = filepath.Join("/dev", id) dv.TypedSpec().Size = nested.ProbedSize @@ -287,13 +323,3 @@ func (ctrl *DiscoveryController) fillDiscoveredVolumeFromInfo(dv *block.Discover dv.TypedSpec().FilesystemBlockSize = info.FilesystemBlockSize dv.TypedSpec().ProbedSize = info.ProbedSize } - -func partitionID(devname string, part uint) string { - result := devname - - if len(result) > 0 && result[len(result)-1] >= '0' && result[len(result)-1] <= '9' { - result += "p" - } - - return result + strconv.FormatUint(uint64(part), 10) -} diff --git a/internal/app/machined/pkg/controllers/block/disks.go b/internal/app/machined/pkg/controllers/block/disks.go index 601e89af25d..16d28be2bcb 100644 --- a/internal/app/machined/pkg/controllers/block/disks.go +++ b/internal/app/machined/pkg/controllers/block/disks.go @@ -156,6 +156,7 @@ func (ctrl *DisksController) analyzeBlockDevice(ctx context.Context, r controlle touchedDisks[device.Metadata().ID()] = struct{}{} return safe.WriterModify(ctx, r, block.NewDisk(block.NamespaceName, device.Metadata().ID()), func(d *block.Disk) error { + d.TypedSpec().DevPath = filepath.Join("/dev", device.Metadata().ID()) d.TypedSpec().Size = size d.TypedSpec().IOSize = ioSize d.TypedSpec().SectorSize = sectorSize diff --git a/internal/app/machined/pkg/controllers/block/internal/volumes/disk.go b/internal/app/machined/pkg/controllers/block/internal/volumes/disk.go new file mode 100644 index 00000000000..70713afee14 --- /dev/null +++ b/internal/app/machined/pkg/controllers/block/internal/volumes/disk.go @@ -0,0 +1,100 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package volumes + +import ( + "github.com/siderolabs/go-blockdevice/v2/blkid" + blockdev "github.com/siderolabs/go-blockdevice/v2/block" + "github.com/siderolabs/go-blockdevice/v2/partitioning/gpt" + "go.uber.org/zap" + + "github.com/siderolabs/talos/pkg/machinery/resources/block" +) + +// CheckDiskResult is the result of checking a disk for provisioning. +type CheckDiskResult struct { + // CanProvision indicates if the disk can be used for provisioning. + CanProvision bool + // HasGPT indicates if the disk has a GPT partition table. + HasGPT bool + // DiskSize is the size of the disk. + DiskSize uint64 +} + +// CheckDiskForProvisioning checks if the disk can be used for provisioning for the given volume configuration. +func CheckDiskForProvisioning(logger *zap.Logger, diskPath string, volumeCfg *block.VolumeConfig) CheckDiskResult { + info, err := blkid.ProbePath(diskPath) + if err != nil { + logger.Error("error probing disk", zap.String("disk", diskPath), zap.Error(err)) + + return CheckDiskResult{} + } + + switch volumeCfg.TypedSpec().Type { //nolint:exhaustive + case block.VolumeTypeDisk: + return CheckDiskResult{ + CanProvision: info.Name == "", + DiskSize: info.Size, + } + case block.VolumeTypePartition: + if info.Name == "" { + // if the disk is not partitioned, it can be used for partitioning, but we need to check the size + overhead := uint64(info.SectorSize) * 67 // GPT + MBR + + return CheckDiskResult{ + CanProvision: info.Size >= volumeCfg.TypedSpec().Provisioning.PartitionSpec.MinSize+overhead, + DiskSize: info.Size, + } + } + + if info.Name != "gpt" { + // not empty, and not gpt => can't be used for partitioning + return CheckDiskResult{} + } + default: + panic("unexpected volume type") + } + + // the rest for partition type volumes with existing GPT partition table + // find the amount of space available + dev, err := blockdev.NewFromPath(diskPath) + if err != nil { + logger.Error("error opening disk", zap.String("disk", diskPath), zap.Error(err)) + + return CheckDiskResult{} + } + + defer dev.Close() //nolint:errcheck + + if err = dev.TryLock(false); err != nil { + logger.Error("error locking disk", zap.String("disk", diskPath), zap.Error(err)) + + return CheckDiskResult{} + } + + defer dev.Unlock() //nolint:errcheck + + gptdev, err := gpt.DeviceFromBlockDevice(dev) + if err != nil { + logger.Error("error getting GPT device", zap.String("disk", diskPath), zap.Error(err)) + + return CheckDiskResult{} + } + + pt, err := gpt.Read(gptdev) + if err != nil { + logger.Error("error reading GPT", zap.String("disk", diskPath), zap.Error(err)) + + return CheckDiskResult{} + } + + available := pt.LargestContiguousAllocatable() + + return CheckDiskResult{ + CanProvision: available >= volumeCfg.TypedSpec().Provisioning.PartitionSpec.MinSize, + HasGPT: true, + DiskSize: info.Size, + } +} diff --git a/internal/app/machined/pkg/controllers/block/internal/volumes/format.go b/internal/app/machined/pkg/controllers/block/internal/volumes/format.go new file mode 100644 index 00000000000..9ab06577418 --- /dev/null +++ b/internal/app/machined/pkg/controllers/block/internal/volumes/format.go @@ -0,0 +1,88 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package volumes + +import ( + "fmt" + "os" + + "github.com/siderolabs/gen/xerrors" + "github.com/siderolabs/go-blockdevice/v2/blkid" + blockdev "github.com/siderolabs/go-blockdevice/v2/block" + "go.uber.org/zap" + "golang.org/x/sys/unix" + + "github.com/siderolabs/talos/pkg/machinery/resources/block" + "github.com/siderolabs/talos/pkg/makefs" +) + +// Format establishes a filesystem on a block device. +func Format(logger *zap.Logger, volumeContext ManagerContext) error { + if volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type == block.FilesystemTypeNone { + // nothing to do + volumeContext.Status.Phase = block.VolumePhaseReady + + return nil + } + + // lock either the parent device or the device itself + devPath := volumeContext.Status.ParentLocation + if devPath == "" { + devPath = volumeContext.Status.Location + } + + f, err := os.OpenFile(devPath, os.O_RDWR|unix.O_CLOEXEC, 0) + if err != nil { + return xerrors.NewTaggedf[Retryable]("error opening disk: %w", err) + } + + defer f.Close() //nolint:errcheck + + dev := blockdev.NewFromFile(f) + + if err = dev.TryLock(true); err != nil { + return xerrors.NewTaggedf[Retryable]("error locking disk: %w", err) + } + + defer dev.Unlock() //nolint:errcheck + + info, err := blkid.ProbePath(volumeContext.Status.Location, blkid.WithSkipLocking(true)) + if err != nil { + return xerrors.NewTaggedf[Retryable]("error probing disk: %w", err) + } + + switch { + case info.Name == "": + // no filesystem, format + case info.Name == volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type.String(): + // filesystem already exists + volumeContext.Status.Phase = block.VolumePhaseReady + + return nil + default: + // mismatch + return fmt.Errorf("filesystem type mismatch: %s != %s", info.Name, volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type) + } + + switch volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type { //nolint:exhaustive + case block.FilesystemTypeXFS: + var makefsOptions []makefs.Option + + // xfs doesn't support by default filesystems < 300 MiB + if volumeContext.Status.Size <= 300*1024*1024 { + makefsOptions = append(makefsOptions, makefs.WithUnsupportedFSOption(true)) + } + + if err = makefs.XFS(volumeContext.Status.Location, makefsOptions...); err != nil { + return fmt.Errorf("error formatting XFS: %w", err) + } + default: + return fmt.Errorf("unsupported filesystem type: %s", volumeContext.Cfg.TypedSpec().Provisioning.FilesystemSpec.Type) + } + + volumeContext.Status.Phase = block.VolumePhaseReady + + return nil +} diff --git a/internal/app/machined/pkg/controllers/block/internal/volumes/grow.go b/internal/app/machined/pkg/controllers/block/internal/volumes/grow.go new file mode 100644 index 00000000000..814192afcc9 --- /dev/null +++ b/internal/app/machined/pkg/controllers/block/internal/volumes/grow.go @@ -0,0 +1,88 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package volumes + +import ( + "fmt" + + "github.com/siderolabs/gen/xerrors" + blockdev "github.com/siderolabs/go-blockdevice/v2/block" + "github.com/siderolabs/go-blockdevice/v2/partitioning/gpt" + "go.uber.org/zap" + + "github.com/siderolabs/talos/pkg/machinery/resources/block" +) + +// Grow grows a volume. +// +//nolint:gocyclo +func Grow(logger *zap.Logger, volumeContext ManagerContext) error { + if !(volumeContext.Cfg.TypedSpec().Type == block.VolumeTypePartition && volumeContext.Cfg.TypedSpec().Provisioning.PartitionSpec.Grow) { + // nothing to do + volumeContext.Status.Phase = block.VolumePhaseProvisioned + + return nil + } + + if volumeContext.Cfg.TypedSpec().Provisioning.PartitionSpec.MaxSize > 0 && volumeContext.Status.Size >= volumeContext.Cfg.TypedSpec().Provisioning.PartitionSpec.MaxSize { + // nowhere to grow + volumeContext.Status.Phase = block.VolumePhaseProvisioned + + return nil + } + + dev, err := blockdev.NewFromPath(volumeContext.Status.ParentLocation, blockdev.OpenForWrite()) + if err != nil { + return xerrors.NewTaggedf[Retryable]("error opening disk: %w", err) + } + + defer dev.Close() //nolint:errcheck + + if err = dev.TryLock(true); err != nil { + return xerrors.NewTaggedf[Retryable]("error locking disk: %w", err) + } + + defer dev.Unlock() //nolint:errcheck + + gptdev, err := gpt.DeviceFromBlockDevice(dev) + if err != nil { + return fmt.Errorf("error getting GPT device: %w", err) + } + + pt, err := gpt.Read(gptdev) + if err != nil { + return fmt.Errorf("error initializing GPT: %w", err) + } + + availableGrowth, err := pt.AvailablePartitionGrowth(volumeContext.Status.PartitionIndex - 1) + if err != nil { + return fmt.Errorf("error getting available partition growth: %w", err) + } + + if availableGrowth <= 1024*1024 { // don't grow by less than 1MiB + volumeContext.Status.Phase = block.VolumePhaseProvisioned + + return nil + } + + if volumeContext.Cfg.TypedSpec().Provisioning.PartitionSpec.MaxSize > 0 && availableGrowth > volumeContext.Cfg.TypedSpec().Provisioning.PartitionSpec.MaxSize-volumeContext.Status.Size { + availableGrowth = volumeContext.Cfg.TypedSpec().Provisioning.PartitionSpec.MaxSize - volumeContext.Status.Size + } + + logger.Debug("growing partition", zap.String("disk", volumeContext.Status.ParentLocation), zap.Int("partition", volumeContext.Status.PartitionIndex), zap.Uint64("size", availableGrowth)) + + if err = pt.GrowPartition(volumeContext.Status.PartitionIndex-1, availableGrowth); err != nil { + return fmt.Errorf("error growing partition: %w", err) + } + + if err = pt.Write(); err != nil { + return fmt.Errorf("error writing GPT: %w", err) + } + + volumeContext.Status.Phase = block.VolumePhaseProvisioned + volumeContext.Status.Size += availableGrowth + + return nil +} diff --git a/internal/app/machined/pkg/controllers/block/internal/volumes/locate.go b/internal/app/machined/pkg/controllers/block/internal/volumes/locate.go new file mode 100644 index 00000000000..51222ee77ac --- /dev/null +++ b/internal/app/machined/pkg/controllers/block/internal/volumes/locate.go @@ -0,0 +1,159 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package volumes + +import ( + "fmt" + + "github.com/siderolabs/gen/value" + "github.com/siderolabs/gen/xerrors" + "github.com/siderolabs/go-blockdevice/v2/partitioning" + "go.uber.org/zap" + + "github.com/siderolabs/talos/pkg/machinery/cel/celenv" + "github.com/siderolabs/talos/pkg/machinery/resources/block" +) + +// LocateAndProvision locates and provisions a volume. +// +// It verifies that the volume is either already created, and ready to be used, +// or provisions it. +// +//nolint:gocyclo,cyclop +func LocateAndProvision(logger *zap.Logger, volumeContext ManagerContext) error { + volumeType := volumeContext.Cfg.TypedSpec().Type + + if volumeType == block.VolumeTypeTmpfs { + // tmpfs volumes are always ready + volumeContext.Status.Phase = block.VolumePhaseReady + + return nil + } + + // below for partition/disk volumes: + if value.IsZero(volumeContext.Cfg.TypedSpec().Locator) { + return fmt.Errorf("volume locator is not set") + } + + // attempt to discover the volume + for _, dv := range volumeContext.DiscoveredVolumes { + matches, err := volumeContext.Cfg.TypedSpec().Locator.Match.EvalBool(celenv.VolumeLocator(), map[string]any{ + "volume": dv, + }) + if err != nil { + return fmt.Errorf("error evaluating volume locator: %w", err) + } + + if matches { + volumeContext.Status.Phase = block.VolumePhaseLocated + volumeContext.Status.Location = dv.DevPath + volumeContext.Status.PartitionIndex = int(dv.PartitionIndex) + volumeContext.Status.ParentLocation = dv.ParentDevPath + + volumeContext.Status.UUID = dv.Uuid + volumeContext.Status.PartitionUUID = dv.PartitionUuid + volumeContext.Status.Size = dv.Size + + return nil + } + } + + if !volumeContext.DevicesReady { + // volume wasn't located, but devices are not ready yet + volumeContext.Status.Phase = block.VolumePhaseWaiting + + return nil + } + + // if we got here, the volume is missing, so it needs to be provisioned + if value.IsZero(volumeContext.Cfg.TypedSpec().Provisioning) { + // the volume can't be provisioned, because the provisioning instructions are missing + volumeContext.Status.Phase = block.VolumePhaseMissing + + return nil + } + + if !volumeContext.PreviousWaveProvisioned { + // previous wave is not provisioned yet + volumeContext.Status.Phase = block.VolumePhaseWaiting + + return nil + } + + // locate the disk(s) for the volume + var matchedDisks []string + + for _, diskCtx := range volumeContext.Disks { + if diskCtx.Disk.Readonly { + // skip readonly disks, they can't be provisioned either way + continue + } + + matches, err := volumeContext.Cfg.TypedSpec().Provisioning.DiskSelector.Match.EvalBool(celenv.DiskLocator(), map[string]any{ + "disk": diskCtx.Disk, + "system_disk": diskCtx.SystemDisk, + }) + if err != nil { + return fmt.Errorf("error evaluating disk locator: %w", err) + } + + if matches { + matchedDisks = append(matchedDisks, diskCtx.Disk.DevPath) + } + } + + if len(matchedDisks) == 0 { + return fmt.Errorf("no disks matched for volume") + } + + logger.Debug("matched disks", zap.Strings("disks", matchedDisks)) + + // analyze each disk, until we find the one which is the best fit + var ( + pickedDisk string + diskCheckResult CheckDiskResult + ) + + for _, matchedDisk := range matchedDisks { + diskCheckResult = CheckDiskForProvisioning(logger, matchedDisk, volumeContext.Cfg) + if diskCheckResult.CanProvision { + pickedDisk = matchedDisk + + break + } + } + + if pickedDisk == "" { + return xerrors.NewTaggedf[Retryable]("no disks matched for volume") + } + + logger.Debug("picked disk", zap.String("disk", pickedDisk)) + + switch volumeType { //nolint:exhaustive + case block.VolumeTypeDisk: + // the disk got matched, so we are done here + volumeContext.Status.Phase = block.VolumePhaseProvisioned + volumeContext.Status.Location = pickedDisk + volumeContext.Status.ParentLocation = "" + volumeContext.Status.Size = diskCheckResult.DiskSize + case block.VolumeTypePartition: + // we need to create a partition on the disk + partitionCreateResult, err := CreatePartition(logger, pickedDisk, volumeContext.Cfg, diskCheckResult.HasGPT) + if err != nil { + return fmt.Errorf("error creating partition: %w", err) + } + + volumeContext.Status.Phase = block.VolumePhaseProvisioned + volumeContext.Status.Location = partitioning.DevName(pickedDisk, uint(partitionCreateResult.PartitionIdx)) + volumeContext.Status.PartitionIndex = partitionCreateResult.PartitionIdx + volumeContext.Status.ParentLocation = pickedDisk + volumeContext.Status.PartitionUUID = partitionCreateResult.Partition.PartGUID.String() + volumeContext.Status.Size = partitionCreateResult.Size + default: + panic("unexpected volume type") + } + + return nil +} diff --git a/internal/app/machined/pkg/controllers/block/internal/volumes/partition.go b/internal/app/machined/pkg/controllers/block/internal/volumes/partition.go new file mode 100644 index 00000000000..1ad8df14253 --- /dev/null +++ b/internal/app/machined/pkg/controllers/block/internal/volumes/partition.go @@ -0,0 +1,102 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package volumes + +import ( + "fmt" + + "github.com/dustin/go-humanize" + "github.com/google/uuid" + "github.com/siderolabs/gen/xerrors" + blockdev "github.com/siderolabs/go-blockdevice/v2/block" + "github.com/siderolabs/go-blockdevice/v2/partitioning/gpt" + "go.uber.org/zap" + + "github.com/siderolabs/talos/pkg/machinery/resources/block" +) + +// CreatePartitionResult is the result of creating a partition. +type CreatePartitionResult struct { + PartitionIdx int + Partition gpt.Partition + Size uint64 +} + +// CreatePartition creates a partition on a disk. +// +//nolint:gocyclo +func CreatePartition(logger *zap.Logger, diskPath string, volumeCfg *block.VolumeConfig, hasPT bool) (CreatePartitionResult, error) { + dev, err := blockdev.NewFromPath(diskPath, blockdev.OpenForWrite()) + if err != nil { + return CreatePartitionResult{}, xerrors.NewTaggedf[Retryable]("error opening disk: %w", err) + } + + defer dev.Close() //nolint:errcheck + + if err = dev.TryLock(true); err != nil { + return CreatePartitionResult{}, xerrors.NewTaggedf[Retryable]("error locking disk: %w", err) + } + + defer dev.Unlock() //nolint:errcheck + + gptdev, err := gpt.DeviceFromBlockDevice(dev) + if err != nil { + return CreatePartitionResult{}, fmt.Errorf("error getting GPT device: %w", err) + } + + var pt *gpt.Table + + if hasPT { + pt, err = gpt.Read(gptdev) + } else { + pt, err = gpt.New(gptdev) + } + + if err != nil { + return CreatePartitionResult{}, fmt.Errorf("error initializing GPT: %w", err) + } + + available := pt.LargestContiguousAllocatable() + + size := volumeCfg.TypedSpec().Provisioning.PartitionSpec.MinSize + maxSize := volumeCfg.TypedSpec().Provisioning.PartitionSpec.MaxSize + + if available < size { + // should never happen + return CreatePartitionResult{}, fmt.Errorf("not enough space on disk") + } + + if maxSize == 0 || maxSize >= available { + size = available + } else { + size = maxSize + } + + typeUUID, err := uuid.Parse(volumeCfg.TypedSpec().Provisioning.PartitionSpec.TypeUUID) + if err != nil { + return CreatePartitionResult{}, fmt.Errorf("error parsing type UUID: %w", err) + } + + partitionIdx, partitionEntry, err := pt.AllocatePartition(size, volumeCfg.TypedSpec().Provisioning.PartitionSpec.Label, typeUUID) + if err != nil { + return CreatePartitionResult{}, fmt.Errorf("error allocating partition: %w", err) + } + + if err = pt.Write(); err != nil { + return CreatePartitionResult{}, fmt.Errorf("error writing GPT: %w", err) + } + + logger.Info("partition created", + zap.String("disk", diskPath), zap.Int("partition", partitionIdx), + zap.String("label", volumeCfg.TypedSpec().Provisioning.PartitionSpec.Label), + zap.String("size", humanize.IBytes(size)), + ) + + return CreatePartitionResult{ + PartitionIdx: partitionIdx, + Partition: partitionEntry, + Size: size, + }, nil +} diff --git a/internal/app/machined/pkg/controllers/block/internal/volumes/proto.go b/internal/app/machined/pkg/controllers/block/internal/volumes/proto.go new file mode 100644 index 00000000000..610d19099c3 --- /dev/null +++ b/internal/app/machined/pkg/controllers/block/internal/volumes/proto.go @@ -0,0 +1,22 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package volumes + +import ( + "github.com/cosi-project/runtime/pkg/resource" + "github.com/siderolabs/protoenc" + + "github.com/siderolabs/talos/pkg/machinery/proto" +) + +// ResourceSpecToProto converts a resource spec to a proto message. +func ResourceSpecToProto(i resource.Resource, o proto.Message) error { + marshaled, err := protoenc.Marshal(i.Spec()) + if err != nil { + return err + } + + return proto.Unmarshal(marshaled, o) +} diff --git a/internal/app/machined/pkg/controllers/block/internal/volumes/volumes.go b/internal/app/machined/pkg/controllers/block/internal/volumes/volumes.go new file mode 100644 index 00000000000..cfdb8161404 --- /dev/null +++ b/internal/app/machined/pkg/controllers/block/internal/volumes/volumes.go @@ -0,0 +1,54 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package volumes provides utilities and extra functions for the volume manager. +package volumes + +import ( + "cmp" + + blockpb "github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/block" + "github.com/siderolabs/talos/pkg/machinery/resources/block" +) + +// CompareVolumeConfigs compares two volume configs in the proposed order of provisioning. +func CompareVolumeConfigs(a, b *block.VolumeConfig) int { + if c := cmp.Compare(a.TypedSpec().Provisioning.Wave, b.TypedSpec().Provisioning.Wave); c != 0 { + return c + } + + return cmpBool(a.TypedSpec().Provisioning.PartitionSpec.Grow, b.TypedSpec().Provisioning.PartitionSpec.Grow) +} + +func cmpBool(a, b bool) int { + if a == b { + return 0 + } + + if a { + return 1 + } + + return -1 +} + +// Retryable is an error tag. +type Retryable struct{} + +// DiskContext captures the context of a disk. +type DiskContext struct { + Disk *blockpb.DiskSpec + SystemDisk bool +} + +// ManagerContext captures the context of the volume manager. +type ManagerContext struct { + Cfg *block.VolumeConfig + Status *block.VolumeStatusSpec + DiscoveredVolumes []*blockpb.DiscoveredVolumeSpec + Disks []DiskContext + + DevicesReady bool + PreviousWaveProvisioned bool +} diff --git a/internal/app/machined/pkg/controllers/block/volume_config.go b/internal/app/machined/pkg/controllers/block/volume_config.go new file mode 100644 index 00000000000..4e9fee62033 --- /dev/null +++ b/internal/app/machined/pkg/controllers/block/volume_config.go @@ -0,0 +1,201 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package block + +import ( + "context" + "fmt" + + "github.com/cosi-project/runtime/pkg/controller" + "github.com/cosi-project/runtime/pkg/safe" + "github.com/cosi-project/runtime/pkg/state" + "github.com/siderolabs/gen/optional" + "go.uber.org/zap" + + "github.com/siderolabs/talos/internal/pkg/partition" + "github.com/siderolabs/talos/pkg/machinery/cel" + "github.com/siderolabs/talos/pkg/machinery/cel/celenv" + "github.com/siderolabs/talos/pkg/machinery/constants" + "github.com/siderolabs/talos/pkg/machinery/resources/block" + "github.com/siderolabs/talos/pkg/machinery/resources/config" +) + +// VolumeConfigController provides volume configuration based on Talos defaults and machine configuration. +type VolumeConfigController struct{} + +// Name implements controller.Controller interface. +func (ctrl *VolumeConfigController) Name() string { + return "block.VolumeConfigController" +} + +// Inputs implements controller.Controller interface. +func (ctrl *VolumeConfigController) Inputs() []controller.Input { + return []controller.Input{ + { + Namespace: config.NamespaceName, + Type: config.MachineConfigType, + ID: optional.Some(config.V1Alpha1ID), + Kind: controller.InputWeak, + }, + } +} + +// Outputs implements controller.Controller interface. +func (ctrl *VolumeConfigController) Outputs() []controller.Output { + return []controller.Output{ + { + Type: block.VolumeConfigType, + Kind: controller.OutputExclusive, + }, + } +} + +func labelVolumeMatch(label string) cel.Expression { + return cel.MustExpression(cel.ParseBooleanExpression(fmt.Sprintf("volume.partition_label == '%s'", label), celenv.VolumeLocator())) +} + +func systemDiskMatch() cel.Expression { + return cel.MustExpression(cel.ParseBooleanExpression("system_disk", celenv.DiskLocator())) +} + +// Run implements controller.Controller interface. +// +//nolint:gocyclo +func (ctrl *VolumeConfigController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error { + for { + select { + case <-r.EventCh(): + case <-ctx.Done(): + return nil + } + + cfg, err := safe.ReaderGetByID[*config.MachineConfig](ctx, r, config.V1Alpha1ID) + if err != nil && !state.IsNotFoundError(err) { + return fmt.Errorf("error fetching machine configuration") + } + + r.StartTrackingOutputs() + + // META volume discovery, always created unconditionally + if err = safe.WriterModify(ctx, r, + block.NewVolumeConfig(block.NamespaceName, constants.MetaPartitionLabel), + func(vc *block.VolumeConfig) error { + vc.TypedSpec().Type = block.VolumeTypePartition + vc.TypedSpec().Locator = block.LocatorSpec{ + Match: labelVolumeMatch(constants.MetaPartitionLabel), + } + + return nil + }, + ); err != nil { + return fmt.Errorf("error creating meta volume configuration: %w", err) + } + + // if config is present (v1apha1 part of now) + // [TODO]: support custom configuration later + configurationPresent := cfg != nil && cfg.Config().Machine() != nil + + // STATE configuration should be always created, but it depends on the configuration presence + if err = safe.WriterModify(ctx, r, + block.NewVolumeConfig(block.NamespaceName, constants.StatePartitionLabel), + func(vc *block.VolumeConfig) error { + vc.TypedSpec().Type = block.VolumeTypePartition + + if configurationPresent { + vc.TypedSpec().Provisioning = block.ProvisioningSpec{ + Wave: block.WaveSystemDisk, + DiskSelector: block.DiskSelector{ + Match: systemDiskMatch(), + }, + PartitionSpec: block.PartitionSpec{ + MinSize: partition.StateSize, + MaxSize: partition.StateSize, + Label: constants.StatePartitionLabel, + TypeUUID: partition.LinuxFilesystemData, + }, + FilesystemSpec: block.FilesystemSpec{ + Type: block.FilesystemTypeXFS, + }, + } + } + + vc.TypedSpec().Locator = block.LocatorSpec{ + Match: labelVolumeMatch(constants.StatePartitionLabel), + } + + return nil + }, + ); err != nil { + return fmt.Errorf("error creating state volume configuration: %w", err) + } + + if configurationPresent { + if err = safe.WriterModify(ctx, r, + block.NewVolumeConfig(block.NamespaceName, constants.EphemeralPartitionLabel), + func(vc *block.VolumeConfig) error { + vc.TypedSpec().Type = block.VolumeTypePartition + + vc.TypedSpec().Provisioning = block.ProvisioningSpec{ + Wave: block.WaveSystemDisk, + DiskSelector: block.DiskSelector{ + Match: systemDiskMatch(), + }, + PartitionSpec: block.PartitionSpec{ + MinSize: partition.EphemeralMinSize, + Grow: true, + Label: constants.EphemeralPartitionLabel, + TypeUUID: partition.LinuxFilesystemData, + }, + FilesystemSpec: block.FilesystemSpec{ + Type: block.FilesystemTypeXFS, + }, + } + + vc.TypedSpec().Locator = block.LocatorSpec{ + Match: labelVolumeMatch(constants.EphemeralPartitionLabel), + } + + return nil + }, + ); err != nil { + return fmt.Errorf("error creating ephemeral volume configuration: %w", err) + } + + // [TODO]: test volume + if err = safe.WriterModify(ctx, r, + block.NewVolumeConfig(block.NamespaceName, "TEST"), + func(vc *block.VolumeConfig) error { + vc.TypedSpec().Type = block.VolumeTypePartition + + vc.TypedSpec().Provisioning = block.ProvisioningSpec{ + Wave: block.WaveUserDisks, + DiskSelector: block.DiskSelector{ + Match: cel.MustExpression(cel.ParseBooleanExpression("disk.size >= 100000u", celenv.DiskLocator())), + }, + PartitionSpec: block.PartitionSpec{ + MinSize: partition.EphemeralMinSize, + Grow: true, + Label: "TEST", + TypeUUID: partition.LinuxFilesystemData, + }, + } + + vc.TypedSpec().Locator = block.LocatorSpec{ + Match: labelVolumeMatch("TEST"), + } + + return nil + }, + ); err != nil { + return fmt.Errorf("error creating ephemeral volume configuration: %w", err) + } + } + + // [TODO]: this would fail as it doesn't handle finalizers properly + if err = safe.CleanupOutputs[*block.VolumeConfig](ctx, r); err != nil { + return fmt.Errorf("error cleaning up volume configuration: %w", err) + } + } +} diff --git a/internal/app/machined/pkg/controllers/block/volume_manager.go b/internal/app/machined/pkg/controllers/block/volume_manager.go new file mode 100644 index 00000000000..baf40c6febf --- /dev/null +++ b/internal/app/machined/pkg/controllers/block/volume_manager.go @@ -0,0 +1,344 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package block + +import ( + "context" + "fmt" + "math" + "slices" + "time" + + "github.com/cosi-project/runtime/pkg/controller" + "github.com/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/safe" + "github.com/cosi-project/runtime/pkg/state" + "github.com/siderolabs/gen/optional" + "github.com/siderolabs/gen/xerrors" + "github.com/siderolabs/gen/xslices" + "go.uber.org/zap" + + "github.com/siderolabs/talos/internal/app/machined/pkg/controllers/block/internal/volumes" + blockpb "github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/block" + "github.com/siderolabs/talos/pkg/machinery/resources/block" + "github.com/siderolabs/talos/pkg/machinery/resources/runtime" +) + +// VolumeManagerController manages volumes in the system, converting VolumeConfig resources to VolumeStatuses. +type VolumeManagerController struct{} + +// Name implements controller.Controller interface. +func (ctrl *VolumeManagerController) Name() string { + return "block.VolumeManagerController" +} + +// Inputs implements controller.Controller interface. +func (ctrl *VolumeManagerController) Inputs() []controller.Input { + return []controller.Input{ + { + Namespace: block.NamespaceName, + Type: block.VolumeConfigType, + Kind: controller.InputStrong, + }, + { + Namespace: block.NamespaceName, + Type: block.DiscoveredVolumeType, + Kind: controller.InputWeak, + }, + { + Namespace: block.NamespaceName, + Type: block.DiskType, + Kind: controller.InputWeak, + }, + { + Namespace: block.NamespaceName, + Type: block.SystemDiskType, + ID: optional.Some(block.SystemDiskID), + Kind: controller.InputWeak, + }, + { + Namespace: runtime.NamespaceName, + Type: runtime.DevicesStatusType, + ID: optional.Some(runtime.DevicesID), + Kind: controller.InputWeak, + }, + { + Namespace: block.NamespaceName, + Type: block.DiscoveryRefreshStatusType, + Kind: controller.InputWeak, + }, + } +} + +// Outputs implements controller.Controller interface. +func (ctrl *VolumeManagerController) Outputs() []controller.Output { + return []controller.Output{ + { + Type: block.VolumeStatusType, + Kind: controller.OutputExclusive, + }, + { + Type: block.DiscoveryRefreshRequestType, + Kind: controller.OutputExclusive, + }, + } +} + +// Run implements controller.Controller interface. +// +//nolint:gocyclo,cyclop +func (ctrl *VolumeManagerController) Run(ctx context.Context, r controller.Runtime, logger *zap.Logger) error { + var ( + deviceReadyObserved bool + deviceReadyRequest int + ) + + retryTicker := time.NewTicker(30 * time.Second) + defer retryTicker.Stop() + + shouldRetry := false + + for { + select { + case <-r.EventCh(): + case <-ctx.Done(): + return nil + case <-retryTicker.C: + if !shouldRetry { + continue + } + + shouldRetry = false + } + + // if devices are not ready, we can't provision and locate most volumes + devicesStatus, err := safe.ReaderGetByID[*runtime.DevicesStatus](ctx, r, runtime.DevicesID) + if err != nil && !state.IsNotFoundError(err) { + return fmt.Errorf("error fetching devices status: %w", err) + } + + devicesReady := devicesStatus != nil && devicesStatus.TypedSpec().Ready + + if devicesReady && !deviceReadyObserved { + deviceReadyObserved = true + + // udevd reports that devices are ready, now it's time to refresh the discovery volumes + if err = safe.WriterModify(ctx, r, block.NewDiscoveryRefreshRequest(block.NamespaceName, block.RefreshID), func(drr *block.DiscoveryRefreshRequest) error { + drr.TypedSpec().Request++ + deviceReadyRequest = drr.TypedSpec().Request + + return nil + }); err != nil { + return fmt.Errorf("error updating discovery refresh request: %w", err) + } + } + + refreshStatus, err := safe.ReaderGetByID[*block.DiscoveryRefreshStatus](ctx, r, block.RefreshID) + if err != nil && !state.IsNotFoundError(err) { + return fmt.Errorf("error fetching discovery refresh status: %w", err) + } + + // now devicesReady is only true if the refresh status is up to date + devicesReady = devicesReady && refreshStatus != nil && refreshStatus.TypedSpec().Request == deviceReadyRequest + + discoveredVolumes, err := safe.ReaderListAll[*block.DiscoveredVolume](ctx, r) + if err != nil { + return fmt.Errorf("error fetching discovered volumes: %w", err) + } + + discoveredVolumesSpecs, err := safe.Map(discoveredVolumes, func(dv *block.DiscoveredVolume) (*blockpb.DiscoveredVolumeSpec, error) { + spec := &blockpb.DiscoveredVolumeSpec{} + + return spec, volumes.ResourceSpecToProto(dv, spec) + }) + if err != nil { + return fmt.Errorf("error mapping discovered volumes: %w", err) + } + + disks, err := safe.ReaderListAll[*block.Disk](ctx, r) + if err != nil { + return fmt.Errorf("error fetching disks: %w", err) + } + + systemDisk, err := safe.ReaderGetByID[*block.SystemDisk](ctx, r, block.SystemDiskID) + if err != nil && !state.IsNotFoundError(err) { + return fmt.Errorf("error fetching system disk: %w", err) + } + + diskSpecs, err := safe.Map(disks, func(d *block.Disk) (volumes.DiskContext, error) { + spec := &blockpb.DiskSpec{} + + if err := volumes.ResourceSpecToProto(d, spec); err != nil { + return volumes.DiskContext{}, err + } + + return volumes.DiskContext{ + Disk: spec, + SystemDisk: systemDisk != nil && d.Metadata().ID() == systemDisk.TypedSpec().DiskID, + }, nil + }) + if err != nil { + return fmt.Errorf("error mapping disks: %w", err) + } + + volumeConfigList, err := safe.ReaderListAll[*block.VolumeConfig](ctx, r) + if err != nil { + return fmt.Errorf("error fetching volume configurations: %w", err) + } + + volumeStatusList, err := safe.ReaderListAll[*block.VolumeStatus](ctx, r) + if err != nil { + return fmt.Errorf("error fetching volume statuses: %w", err) + } + + volumeConfigIDs := xslices.ToSet(safe.ToSlice(volumeConfigList, func(vc *block.VolumeConfig) resource.ID { return vc.Metadata().ID() })) + + volumeStatuses := xslices.ToMap( + safe.ToSlice(volumeStatusList, func(vs *block.VolumeStatus) *block.VolumeStatus { return vs }), + func(vs *block.VolumeStatus) (resource.ID, *block.VolumeStatusSpec) { + return vs.Metadata().ID(), vs.TypedSpec() + }, + ) + + if volumeStatuses == nil { + volumeStatuses = map[resource.ID]*block.VolumeStatusSpec{} + } + + // ensure all volume configs have our finalizers + for iter := volumeConfigList.Iterator(); iter.Next(); { + vc := iter.Value() + + if vc.Metadata().Phase() != resource.PhaseRunning { + continue + } + + if vc.Metadata().Finalizers().Has(ctrl.Name()) { + continue + } + + if err = r.AddFinalizer(ctx, vc.Metadata(), ctrl.Name()); err != nil { + return fmt.Errorf("error adding finalizer to volume configuration: %w", err) + } + } + + // remove statuses for volume configs that no longer exist + for id := range volumeStatuses { + if _, exists := volumeConfigIDs[id]; !exists { + delete(volumeStatuses, id) + + if err := r.Destroy(ctx, block.NewVolumeStatus(block.NamespaceName, id).Metadata()); err != nil { + return fmt.Errorf("error destroying volume status: %w", err) + } + } + } + + // fill in statuses for volume configs that don't have a status yet + for id := range volumeConfigIDs { + if _, exists := volumeStatuses[id]; !exists { + volumeStatuses[id] = &block.VolumeStatusSpec{ + Phase: block.VolumePhaseWaiting, + } + } + } + + volumeConfigs := safe.ToSlice(volumeConfigList, func(vc *block.VolumeConfig) *block.VolumeConfig { return vc }) + + // re-sort volume configs by provisioning wave + slices.SortStableFunc(volumeConfigs, volumes.CompareVolumeConfigs) + + fullyProvisionedWave := math.MaxInt + + for _, vc := range volumeConfigs { + volumeStatus := volumeStatuses[vc.Metadata().ID()] + volumeLogger := logger.With(zap.String("volume", vc.Metadata().ID())) + + if vc.Metadata().Phase() != resource.PhaseRunning { + // [TODO]: handle me later + continue + } + + if err = ctrl.processVolumeConfig( + volumeLogger, + volumes.ManagerContext{ + Cfg: vc, + Status: volumeStatus, + DiscoveredVolumes: discoveredVolumesSpecs, + Disks: diskSpecs, + DevicesReady: devicesReady, + PreviousWaveProvisioned: vc.TypedSpec().Provisioning.Wave <= fullyProvisionedWave, + }, + ); err != nil { + volumeStatus.PreFailPhase = volumeStatus.Phase + volumeStatus.Phase = block.VolumePhaseFailed + volumeStatus.ErrorMessage = err.Error() + + if xerrors.TagIs[volumes.Retryable](err) { + shouldRetry = true + } + + volumeLogger.Error("error processing volume config", zap.Error(err)) + } else { + volumeStatus.ErrorMessage = "" + volumeStatus.PreFailPhase = block.VolumePhase(0) + } + + if volumeStatus.Phase != block.VolumePhaseReady { + fullyProvisionedWave = vc.TypedSpec().Provisioning.Wave - 1 + } + + volumeLogger.Info("volume status", zap.Stringer("phase", volumeStatus.Phase)) + } + + // update statuses + for id, spec := range volumeStatuses { + if err = safe.WriterModify(ctx, r, block.NewVolumeStatus(block.NamespaceName, id), func(vs *block.VolumeStatus) error { + *vs.TypedSpec() = *spec + + return nil + }); err != nil { + return fmt.Errorf("error updating volume status: %w", err) + } + } + } +} + +//nolint:gocyclo +func (ctrl *VolumeManagerController) processVolumeConfig(logger *zap.Logger, volumeContext volumes.ManagerContext) error { + prevPhase := volumeContext.Status.Phase + + for { + switch volumeContext.Status.Phase { + case block.VolumePhaseReady: + // nothing to do, ready + return nil + case block.VolumePhaseWaiting, block.VolumePhaseMissing: + if err := volumes.LocateAndProvision(logger, volumeContext); err != nil { + return err + } + case block.VolumePhaseLocated: + // grow the partition if needed + if err := volumes.Grow(logger, volumeContext); err != nil { + return err + } + case block.VolumePhaseProvisioned: + // format the volume + if err := volumes.Format(logger, volumeContext); err != nil { + return err + } + + return nil + case block.VolumePhaseFailed: + // recover from the failure by restoring the pre-failure phase + volumeContext.Status.Phase = volumeContext.Status.PreFailPhase + } + + if volumeContext.Status.Phase == prevPhase { + // doesn't progress, stop the loop + return nil + } + + prevPhase = volumeContext.Status.Phase + } +} diff --git a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/bootloader.go b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/bootloader.go index 4702a7fad18..5130ea11495 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/bootloader.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/bootloader.go @@ -6,33 +6,34 @@ package bootloader import ( - "context" "os" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot" + "github.com/siderolabs/talos/internal/pkg/partition" "github.com/siderolabs/talos/pkg/machinery/imager/quirks" ) // Bootloader describes a bootloader. type Bootloader interface { - // Install installs the bootloader - Install(options options.InstallOptions) error + // Install the bootloader. + // + // Install mounts the partitions as required. + Install(options options.InstallOptions) (*options.InstallResult, error) // Revert reverts the bootloader entry to the previous state. - Revert(ctx context.Context) error - // PreviousLabel returns the previous bootloader label. - PreviousLabel() string - // UEFIBoot returns true if the bootloader is UEFI-only. - UEFIBoot() bool + // + // Revert mounts the partitions as required. + Revert(disk string) error + // RequiredPartitions returns the required partitions for the bootloader. + RequiredPartitions() []partition.Options } // Probe checks if any supported bootloaders are installed. // -// If 'disk' is empty, it will probe all disks. // Returns nil if it cannot detect any supported bootloader. -func Probe(ctx context.Context, disk string) (Bootloader, error) { - grubBootloader, err := grub.Probe(ctx, disk) +func Probe(disk string, options options.ProbeOptions) (Bootloader, error) { + grubBootloader, err := grub.Probe(disk, options) if err != nil { return nil, err } @@ -41,7 +42,7 @@ func Probe(ctx context.Context, disk string) (Bootloader, error) { return grubBootloader, nil } - sdbootBootloader, err := sdboot.Probe(ctx, disk) + sdbootBootloader, err := sdboot.Probe(disk, options) if err != nil { return nil, err } diff --git a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/boot_label.go b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/boot_label.go index 9a44bdd4c9a..4973250b375 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/boot_label.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/boot_label.go @@ -42,11 +42,6 @@ func (c *Config) flip() error { return nil } -// PreviousLabel returns the previous bootloader label. -func (c *Config) PreviousLabel() string { - return string(c.Fallback) -} - // ParseBootLabel parses the given human-readable boot label to a BootLabel. func ParseBootLabel(name string) (BootLabel, error) { switch { diff --git a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/grub.go b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/grub.go index e0f877bf5b1..8ff1e4f25ce 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/grub.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/grub.go @@ -10,6 +10,7 @@ import ( "fmt" "path/filepath" + "github.com/siderolabs/talos/internal/pkg/partition" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/machinery/version" ) @@ -43,10 +44,13 @@ func NewConfig() *Config { } } -// UEFIBoot returns true if bootloader is UEFI-only. -func (c *Config) UEFIBoot() bool { - // grub supports BIOS boot, so false here. - return false +// RequiredPartitions returns the list of partitions required by the bootloader. +func (c *Config) RequiredPartitions() []partition.Options { + return []partition.Options{ + partition.NewPartitionOptions(constants.EFIPartitionLabel, false), + partition.NewPartitionOptions(constants.BIOSGrubPartitionLabel, false), + partition.NewPartitionOptions(constants.BootPartitionLabel, false), + } } // Put puts a new menu entry to the grub config (nothing is written to disk). diff --git a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/install.go b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/install.go index dedcc66ba83..5aad846634e 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/install.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/install.go @@ -10,10 +10,12 @@ import ( "runtime" "strings" - "github.com/siderolabs/go-blockdevice/blockdevice" + "github.com/siderolabs/go-blockdevice/v2/blkid" "github.com/siderolabs/go-cmd/pkg/cmd" + "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/mount" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options" + "github.com/siderolabs/talos/internal/pkg/partition" "github.com/siderolabs/talos/pkg/imager/utils" "github.com/siderolabs/talos/pkg/machinery/constants" ) @@ -24,62 +26,91 @@ const ( ) // Install validates the grub configuration and writes it to the disk. -// +func (c *Config) Install(opts options.InstallOptions) (*options.InstallResult, error) { + var installResult *options.InstallResult + + err := mount.PartitionOp( + opts.BootDisk, + []mount.Spec{ + { + PartitionLabel: constants.BootPartitionLabel, + FilesystemType: partition.FilesystemTypeXFS, + MountTarget: filepath.Join(opts.MountPrefix, constants.BootMountPoint), + }, + { + PartitionLabel: constants.EFIPartitionLabel, + FilesystemType: partition.FilesystemTypeVFAT, + MountTarget: filepath.Join(opts.MountPrefix, constants.EFIMountPoint), + }, + }, + func() error { + var installErr error + + installResult, installErr = c.install(opts) + + return installErr + }, + []blkid.ProbeOption{ + // installation happens with locked blockdevice + blkid.WithSkipLocking(true), + }, + nil, + nil, + ) + + return installResult, err +} + //nolint:gocyclo -func (c *Config) Install(options options.InstallOptions) error { +func (c *Config) install(opts options.InstallOptions) (*options.InstallResult, error) { if err := c.flip(); err != nil { - return err + return nil, err } if err := utils.CopyFiles( - options.Printf, + opts.Printf, utils.SourceDestination( - options.BootAssets.KernelPath, - filepath.Join(options.MountPrefix, constants.BootMountPoint, string(c.Default), constants.KernelAsset), + opts.BootAssets.KernelPath, + filepath.Join(opts.MountPrefix, constants.BootMountPoint, string(c.Default), constants.KernelAsset), ), utils.SourceDestination( - options.BootAssets.InitramfsPath, - filepath.Join(options.MountPrefix, constants.BootMountPoint, string(c.Default), constants.InitramfsAsset), + opts.BootAssets.InitramfsPath, + filepath.Join(opts.MountPrefix, constants.BootMountPoint, string(c.Default), constants.InitramfsAsset), ), ); err != nil { - return err - } - - if err := c.Put(c.Default, options.Cmdline, options.Version); err != nil { - return err + return nil, err } - if err := c.Write(filepath.Join(options.MountPrefix, ConfigPath), options.Printf); err != nil { - return err + if err := c.Put(c.Default, opts.Cmdline, opts.Version); err != nil { + return nil, err } - blk, err := getBlockDeviceName(options.BootDisk) - if err != nil { - return err + if err := c.Write(filepath.Join(opts.MountPrefix, ConfigPath), opts.Printf); err != nil { + return nil, err } var platforms []string - switch options.Arch { + switch opts.Arch { case amd64: platforms = []string{"x86_64-efi", "i386-pc"} case arm64: platforms = []string{"arm64-efi"} } - if runtime.GOARCH == amd64 && options.Arch == amd64 && !options.ImageMode { + if runtime.GOARCH == amd64 && opts.Arch == amd64 && !opts.ImageMode { // let grub choose the platform automatically if not building an image platforms = []string{""} } for _, platform := range platforms { args := []string{ - "--boot-directory=" + filepath.Join(options.MountPrefix, constants.BootMountPoint), - "--efi-directory=" + filepath.Join(options.MountPrefix, constants.EFIMountPoint), + "--boot-directory=" + filepath.Join(opts.MountPrefix, constants.BootMountPoint), + "--efi-directory=" + filepath.Join(opts.MountPrefix, constants.EFIMountPoint), "--removable", } - if options.ImageMode { + if opts.ImageMode { args = append(args, "--no-nvram") } @@ -87,34 +118,22 @@ func (c *Config) Install(options options.InstallOptions) error { args = append(args, "--target="+platform) } - args = append(args, blk) + args = append(args, opts.BootDisk) - options.Printf("executing: grub-install %s", strings.Join(args, " ")) + opts.Printf("executing: grub-install %s", strings.Join(args, " ")) if _, err := cmd.Run("grub-install", args...); err != nil { - return fmt.Errorf("failed to install grub: %w", err) + return nil, fmt.Errorf("failed to install grub: %w", err) } } - return nil -} - -func getBlockDeviceName(bootDisk string) (string, error) { - dev, err := blockdevice.Open(bootDisk, blockdevice.WithMode(blockdevice.ReadonlyMode)) - if err != nil { - return "", err - } - - //nolint:errcheck - defer dev.Close() - - // verify that BootDisk has boot partition - _, err = dev.GetPartition(constants.BootPartitionLabel) - if err != nil { - return "", err + if opts.ExtraInstallStep != nil { + if err := opts.ExtraInstallStep(); err != nil { + return nil, err + } } - blk := dev.Device().Name() - - return blk, nil + return &options.InstallResult{ + PreviousLabel: string(c.Fallback), + }, nil } diff --git a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/probe.go b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/probe.go index 1450f19303c..0c4b401ad94 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/probe.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/probe.go @@ -6,28 +6,51 @@ package grub import ( - "context" + "github.com/siderolabs/gen/xerrors" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/mount" + "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options" + mountv2 "github.com/siderolabs/talos/internal/pkg/mount/v2" + "github.com/siderolabs/talos/internal/pkg/partition" "github.com/siderolabs/talos/pkg/machinery/constants" ) // Probe probes a block device for GRUB bootloader. -// -// If the 'disk' is passed, search happens on that disk only, otherwise searches all partitions. -func Probe(ctx context.Context, disk string) (*Config, error) { +func Probe(disk string, options options.ProbeOptions) (*Config, error) { var grubConf *Config - if err := mount.PartitionOp(ctx, disk, constants.BootPartitionLabel, func() error { - var err error - - grubConf, err = Read(ConfigPath) - if err != nil { - return err + if err := mount.PartitionOp( + disk, + []mount.Spec{ + { + PartitionLabel: constants.BootPartitionLabel, + FilesystemType: partition.FilesystemTypeXFS, + MountTarget: constants.BootMountPoint, + }, + }, + func() error { + var err error + + grubConf, err = Read(ConfigPath) + if err != nil { + return err + } + + return nil + }, + options.BlockProbeOptions, + []mountv2.NewPointOption{ + mountv2.WithReadonly(), + }, + []mountv2.MountOption{ + mountv2.WithSkipIfMounted(), + }, + ); err != nil { + if xerrors.TagIs[mount.NotFoundTag](err) { + // if partitions are not found, it means GRUB is not installed + return nil, nil } - return nil - }); err != nil { return nil, err } diff --git a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/revert.go b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/revert.go index 5a2cbae66fd..4c58d07ff63 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/revert.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/revert.go @@ -6,68 +6,55 @@ package grub import ( - "context" "errors" "fmt" "log" "os" "path/filepath" - "github.com/siderolabs/go-blockdevice/blockdevice/probe" + "github.com/siderolabs/gen/xerrors" - "github.com/siderolabs/talos/internal/pkg/mount" + "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/mount" + mountv2 "github.com/siderolabs/talos/internal/pkg/mount/v2" + "github.com/siderolabs/talos/internal/pkg/partition" "github.com/siderolabs/talos/pkg/machinery/constants" ) // Revert reverts the bootloader to the previous version. -// -//nolint:gocyclo -func (c *Config) Revert(ctx context.Context) error { +func (c *Config) Revert(disk string) error { if c == nil { return fmt.Errorf("cannot revert bootloader: %w", bootloaderNotInstalledError{}) } - if err := c.flip(); err != nil { + err := mount.PartitionOp( + disk, + []mount.Spec{ + { + PartitionLabel: constants.BootPartitionLabel, + FilesystemType: partition.FilesystemTypeXFS, + MountTarget: constants.BootMountPoint, + }, + }, + c.revert, + nil, + nil, + []mountv2.MountOption{ + mountv2.WithSkipIfMounted(), + }, + ) + if err != nil && !xerrors.TagIs[mount.NotFoundTag](err) { return err } - // attempt to probe BOOT partition directly - dev, err := probe.GetDevWithPartitionName(constants.BootPartitionLabel) - if os.IsNotExist(err) { - // no BOOT partition, nothing to revert - return nil - } - - if err != nil { - return err - } - - defer dev.Close() //nolint:errcheck - - mp, err := mount.SystemMountPointForLabel(ctx, dev.BlockDevice, constants.BootPartitionLabel) - if err != nil { - return err - } - - // if no BOOT partition nothing to revert - if mp == nil { - return nil - } + return nil +} - alreadyMounted, err := mp.IsMounted() - if err != nil { +func (c *Config) revert() error { + if err := c.flip(); err != nil { return err } - if !alreadyMounted { - if err = mp.Mount(); err != nil { - return err - } - - defer mp.Unmount() //nolint:errcheck - } - - if _, err = os.Stat(filepath.Join(constants.BootMountPoint, string(c.Default))); errors.Is(err, os.ErrNotExist) { + if _, err := os.Stat(filepath.Join(constants.BootMountPoint, string(c.Default))); errors.Is(err, os.ErrNotExist) { return fmt.Errorf("cannot rollback to %q, label does not exist", "") } diff --git a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/mount/mount.go b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/mount/mount.go index e6dfe3fda30..95fa541f5d9 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/mount/mount.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/mount/mount.go @@ -6,102 +6,77 @@ package mount import ( - "context" - "errors" "fmt" - "os" - "github.com/siderolabs/go-blockdevice/blockdevice" - "github.com/siderolabs/go-blockdevice/blockdevice/probe" + "github.com/siderolabs/gen/xerrors" + "github.com/siderolabs/go-blockdevice/v2/blkid" + "github.com/siderolabs/go-blockdevice/v2/partitioning" + "github.com/siderolabs/go-pointer" - "github.com/siderolabs/talos/internal/pkg/mount" + "github.com/siderolabs/talos/internal/pkg/mount/v2" ) -// PartitionOp mounts a partition with the specified label, executes the operation func, and unmounts the partition. -// -//nolint:gocyclo -func PartitionOp(ctx context.Context, disk string, partitionLabel string, opFunc func() error) error { - var probedBlockDevice *blockdevice.BlockDevice - - switch { - case disk != "": - dev, err := blockdevice.Open(disk, blockdevice.WithMode(blockdevice.ReadonlyMode)) - if err != nil { - return err - } - - defer dev.Close() //nolint:errcheck - - _, err = dev.GetPartition(partitionLabel) - if err != nil { - if errors.Is(err, blockdevice.ErrMissingPartitionTable) || os.IsNotExist(err) { - return nil - } +// Spec specifies what has to be mounted. +type Spec struct { + PartitionLabel string - return err - } - - probedBlockDevice = dev - case disk == "": - // attempt to probe partition with partitionLabel on any disk - dev, err := probe.GetDevWithPartitionName(partitionLabel) - if os.IsNotExist(err) { - // no EFI partition, nothing to do - return nil - } + FilesystemType string - if err != nil { - return err - } - - defer dev.Close() //nolint:errcheck - - probedBlockDevice = dev.BlockDevice - } + MountTarget string +} - mp, err := mount.SystemMountPointForLabel(ctx, probedBlockDevice, partitionLabel, mount.WithFlags(mount.ReadOnly)) +// NotFoundTag is a tag for a partition not found/mismatch errors. +type NotFoundTag struct{} + +// PartitionOp mounts specified partitions with the specified label, executes the operation func, and unmounts the partition(s). +func PartitionOp( + disk string, specs []Spec, opFunc func() error, + probeOptions []blkid.ProbeOption, + newPointOptions []mount.NewPointOption, + mountOptions []mount.MountOption, +) error { + info, err := blkid.ProbePath(disk, probeOptions...) if err != nil { - return err + return fmt.Errorf("error probing disk %s: %w", disk, err) } - // no mountpoint defined for this partition, should not happen - if mp == nil { - return fmt.Errorf("no mountpoint defined for %s", partitionLabel) - } + var points mount.Points - alreadyMounted, err := mp.IsMounted() - if err != nil { - return err - } + for _, spec := range specs { + var found bool - if !alreadyMounted { - if err = mp.Mount(); err != nil { - return err - } + for _, partition := range info.Parts { + if pointer.SafeDeref(partition.PartitionLabel) == spec.PartitionLabel { + if partition.Name != spec.FilesystemType { + return xerrors.NewTaggedf[NotFoundTag]("partition with label %s is not of type %s (actual %s)", *partition.PartitionLabel, spec.FilesystemType, partition.Name) + } - defer mp.Unmount() //nolint:errcheck - } + points = append(points, + mount.NewPoint( + partitioning.DevName(disk, partition.PartitionIndex), + spec.MountTarget, + partition.Name, + newPointOptions..., + ), + ) - return opFunc() -} + found = true -// GetBlockDeviceName returns the block device name for the specified boot disk and partition label. -func GetBlockDeviceName(bootDisk, partitionLabel string) (string, error) { - dev, err := blockdevice.Open(bootDisk, blockdevice.WithMode(blockdevice.ReadonlyMode)) - if err != nil { - return "", err - } + break + } + } - //nolint:errcheck - defer dev.Close() + if !found { + return xerrors.NewTaggedf[NotFoundTag]("partition with label %s not found", spec.PartitionLabel) + } + } - // verify that BootDisk has partition with the specified label - _, err = dev.GetPartition(partitionLabel) + unmounter, err := points.Mount(mountOptions...) if err != nil { - return "", err + return fmt.Errorf("error mounting partitions: %w", err) } - blk := dev.Device().Name() + defer unmounter() //nolint:errcheck - return blk, nil + return opFunc() } diff --git a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options/options.go b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options/options.go index 4ff9719d896..9af893b3b6d 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options/options.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options/options.go @@ -8,6 +8,7 @@ package options import ( "fmt" + "github.com/siderolabs/go-blockdevice/v2/blkid" "github.com/siderolabs/talos/pkg/machinery/constants" ) @@ -31,10 +32,19 @@ type InstallOptions struct { // Boot assets to install. BootAssets BootAssets + // ExtraInstallStep is a function to run after the bootloader is installed. + ExtraInstallStep func() error + // Printf-like function to use. Printf func(format string, v ...any) } +// InstallResult is the result of the installation. +type InstallResult struct { + // Previous label (if upgrading). + PreviousLabel string +} + // BootAssets describes the assets to be installed by the bootloader. type BootAssets struct { KernelPath string @@ -80,3 +90,8 @@ func (assets *BootAssets) FillDefaults(arch string) { } } } + +// ProbeOptions configures bootloader probing. +type ProbeOptions struct { + BlockProbeOptions []blkid.ProbeOption +} diff --git a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot/sdboot.go b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot/sdboot.go index 1dc3788f558..2528e59cd73 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot/sdboot.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot/sdboot.go @@ -6,7 +6,6 @@ package sdboot import ( - "context" "errors" "fmt" "log" @@ -15,9 +14,13 @@ import ( "strings" "github.com/ecks/uefi/efi/efivario" + "github.com/siderolabs/gen/xerrors" + "github.com/siderolabs/go-blockdevice/v2/blkid" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/mount" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options" + mountv2 "github.com/siderolabs/talos/internal/pkg/mount/v2" + "github.com/siderolabs/talos/internal/pkg/partition" "github.com/siderolabs/talos/pkg/imager/utils" "github.com/siderolabs/talos/pkg/machinery/constants" ) @@ -52,7 +55,7 @@ func New() *Config { // Probe for existing sd-boot bootloader. // //nolint:gocyclo -func Probe(ctx context.Context, disk string) (*Config, error) { +func Probe(disk string, options options.ProbeOptions) (*Config, error) { // if not UEFI boot, nothing to do if !isUEFIBoot() { return nil, nil @@ -64,19 +67,40 @@ func Probe(ctx context.Context, disk string) (*Config, error) { // read /boot/EFI and find if sd-boot is already being used // this is to make sure sd-boot from Talos is being used and not sd-boot from another distro - if err := mount.PartitionOp(ctx, disk, constants.EFIPartitionLabel, func() error { - // list existing boot*.efi files in boot folder - files, err := filepath.Glob(filepath.Join(constants.EFIMountPoint, "EFI", "boot", "BOOT*.efi")) - if err != nil { - return err - } + if err := mount.PartitionOp( + disk, + []mount.Spec{ + { + PartitionLabel: constants.EFIPartitionLabel, + FilesystemType: partition.FilesystemTypeVFAT, + MountTarget: constants.EFIMountPoint, + }, + }, + func() error { + // list existing boot*.efi files in boot folder + files, err := filepath.Glob(filepath.Join(constants.EFIMountPoint, "EFI", "boot", "BOOT*.efi")) + if err != nil { + return err + } - if len(files) == 0 { - return fmt.Errorf("no boot*.efi files found in %q", filepath.Join(constants.EFIMountPoint, "EFI", "boot")) + if len(files) == 0 { + return fmt.Errorf("no boot*.efi files found in %q", filepath.Join(constants.EFIMountPoint, "EFI", "boot")) + } + + return nil + }, + options.BlockProbeOptions, + []mountv2.NewPointOption{ + mountv2.WithReadonly(), + }, + []mountv2.MountOption{ + mountv2.WithSkipIfMounted(), + }, + ); err != nil { + if xerrors.TagIs[mount.NotFoundTag](err) { + return nil, nil } - return nil - }); err != nil { return nil, err } @@ -94,21 +118,38 @@ func Probe(ctx context.Context, disk string) (*Config, error) { log.Printf("booted entry: %q", bootedEntry) - if opErr := mount.PartitionOp(ctx, disk, constants.EFIPartitionLabel, func() error { - // list existing UKIs, and check if the current one is present - files, err := filepath.Glob(filepath.Join(constants.EFIMountPoint, "EFI", "Linux", "Talos-*.efi")) - if err != nil { - return err - } + if opErr := mount.PartitionOp( + disk, + []mount.Spec{ + { + PartitionLabel: constants.EFIPartitionLabel, + FilesystemType: partition.FilesystemTypeVFAT, + MountTarget: constants.EFIMountPoint, + }, + }, + func() error { + // list existing UKIs, and check if the current one is present + files, err := filepath.Glob(filepath.Join(constants.EFIMountPoint, "EFI", "Linux", "Talos-*.efi")) + if err != nil { + return err + } - for _, file := range files { - if strings.EqualFold(filepath.Base(file), bootedEntry) { - return nil + for _, file := range files { + if strings.EqualFold(filepath.Base(file), bootedEntry) { + return nil + } } - } - return fmt.Errorf("booted entry %q not found", bootedEntry) - }); opErr != nil { + return fmt.Errorf("booted entry %q not found", bootedEntry) + }, + options.BlockProbeOptions, + []mountv2.NewPointOption{ + mountv2.WithReadonly(), + }, + []mountv2.MountOption{ + mountv2.WithSkipIfMounted(), + }, + ); opErr != nil { return nil, opErr } @@ -117,9 +158,42 @@ func Probe(ctx context.Context, disk string) (*Config, error) { }, nil } -// UEFIBoot returns true if bootloader is UEFI-only. -func (c *Config) UEFIBoot() bool { - return true +// RequiredPartitions returns the list of partitions required by the bootloader. +func (c *Config) RequiredPartitions() []partition.Options { + return []partition.Options{ + partition.NewPartitionOptions(constants.EFIPartitionLabel, true), + } +} + +// Install the bootloader. +func (c *Config) Install(opts options.InstallOptions) (*options.InstallResult, error) { + var installResult *options.InstallResult + + err := mount.PartitionOp( + opts.BootDisk, + []mount.Spec{ + { + PartitionLabel: constants.EFIPartitionLabel, + FilesystemType: partition.FilesystemTypeVFAT, + MountTarget: filepath.Join(opts.MountPrefix, constants.EFIMountPoint), + }, + }, + func() error { + var installErr error + + installResult, installErr = c.install(opts) + + return installErr + }, + []blkid.ProbeOption{ + // installation happens with locked blockdevice + blkid.WithSkipLocking(true), + }, + nil, + nil, + ) + + return installResult, err } // Install the bootloader. @@ -128,26 +202,26 @@ func (c *Config) UEFIBoot() bool { // Writes down the UKI and updates the EFI variables. // //nolint:gocyclo -func (c *Config) Install(options options.InstallOptions) error { +func (c *Config) install(opts options.InstallOptions) (*options.InstallResult, error) { var sdbootFilename string - switch options.Arch { + switch opts.Arch { case "amd64": sdbootFilename = "BOOTX64.efi" case "arm64": sdbootFilename = "BOOTAA64.efi" default: - return fmt.Errorf("unsupported architecture: %s", options.Arch) + return nil, fmt.Errorf("unsupported architecture: %s", opts.Arch) } // list existing UKIs, and clean up all but the current one (used to boot) - files, err := filepath.Glob(filepath.Join(options.MountPrefix, constants.EFIMountPoint, "EFI", "Linux", "Talos-*.efi")) + files, err := filepath.Glob(filepath.Join(opts.MountPrefix, constants.EFIMountPoint, "EFI", "Linux", "Talos-*.efi")) if err != nil { - return err + return nil, err } // writing UKI by version-based filename here - ukiPath := fmt.Sprintf("%s-%s.efi", "Talos", options.Version) + ukiPath := fmt.Sprintf("%s-%s.efi", "Talos", opts.Version) for _, file := range files { if strings.EqualFold(filepath.Base(file), c.Default) { @@ -159,75 +233,96 @@ func (c *Config) Install(options options.InstallOptions) error { continue } - options.Printf("removing old UKI: %s", file) + opts.Printf("removing old UKI: %s", file) if err = os.Remove(file); err != nil { - return err + return nil, err } } if err := utils.CopyFiles( - options.Printf, + opts.Printf, utils.SourceDestination( - options.BootAssets.UKIPath, - filepath.Join(options.MountPrefix, constants.EFIMountPoint, "EFI", "Linux", ukiPath), + opts.BootAssets.UKIPath, + filepath.Join(opts.MountPrefix, constants.EFIMountPoint, "EFI", "Linux", ukiPath), ), utils.SourceDestination( - options.BootAssets.SDBootPath, - filepath.Join(options.MountPrefix, constants.EFIMountPoint, "EFI", "boot", sdbootFilename), + opts.BootAssets.SDBootPath, + filepath.Join(opts.MountPrefix, constants.EFIMountPoint, "EFI", "boot", sdbootFilename), ), ); err != nil { - return err + return nil, err } // don't update EFI variables if we're installing to a loop device - if !options.ImageMode { - options.Printf("updating EFI variables") + if !opts.ImageMode { + opts.Printf("updating EFI variables") efiCtx := efivario.NewDefaultContext() // set the new entry as a default one if err := WriteVariable(efiCtx, LoaderEntryDefaultName, ukiPath); err != nil { - return err + return nil, err } // set default 5 second boot timeout if err := WriteVariable(efiCtx, LoaderConfigTimeoutName, "5"); err != nil { - return err + return nil, err } } - return nil -} + if opts.ExtraInstallStep != nil { + if err := opts.ExtraInstallStep(); err != nil { + return nil, err + } + } -// PreviousLabel returns the label of the previous bootloader version. -func (c *Config) PreviousLabel() string { - return c.Fallback + return &options.InstallResult{ + PreviousLabel: c.Fallback, + }, nil } // Revert the bootloader to the previous version. -func (c *Config) Revert(ctx context.Context) error { - if err := mount.PartitionOp(ctx, "", constants.EFIPartitionLabel, func() error { - // use c.Default as the current entry, list other UKIs, find the one which is not c.Default, and update EFI var - files, err := filepath.Glob(filepath.Join(constants.EFIMountPoint, "EFI", "Linux", "Talos-*.efi")) - if err != nil { - return err - } +func (c *Config) Revert(disk string) error { + err := mount.PartitionOp( + disk, + []mount.Spec{ + { + PartitionLabel: constants.EFIPartitionLabel, + FilesystemType: partition.FilesystemTypeVFAT, + MountTarget: constants.EFIMountPoint, + }, + }, + c.revert, + nil, + nil, + []mountv2.MountOption{ + mountv2.WithSkipIfMounted(), + }, + ) + if err != nil && !xerrors.TagIs[mount.NotFoundTag](err) { + return err + } - for _, file := range files { - if strings.EqualFold(filepath.Base(file), c.Default) { - continue - } + return nil +} - log.Printf("reverting to previous UKI: %s", file) +func (c *Config) revert() error { + // use c.Default as the current entry, list other UKIs, find the one which is not c.Default, and update EFI var + files, err := filepath.Glob(filepath.Join(constants.EFIMountPoint, "EFI", "Linux", "Talos-*.efi")) + if err != nil { + return err + } - return WriteVariable(efivario.NewDefaultContext(), LoaderEntryDefaultName, filepath.Base(file)) + for _, file := range files { + if strings.EqualFold(filepath.Base(file), c.Default) { + continue } - return errors.New("previous UKI not found") - }); err != nil { - return err + log.Printf("reverting to previous UKI: %s", file) + + return WriteVariable(efivario.NewDefaultContext(), LoaderEntryDefaultName, filepath.Base(file)) } - return nil + return errors.New("previous UKI not found") } diff --git a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go index 2fca1649109..6a311712765 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_sequencer_tasks.go @@ -31,9 +31,7 @@ import ( "github.com/hashicorp/go-multierror" "github.com/opencontainers/runtime-spec/specs-go" pprocfs "github.com/prometheus/procfs" - "github.com/siderolabs/gen/xslices" "github.com/siderolabs/go-blockdevice/blockdevice" - "github.com/siderolabs/go-blockdevice/blockdevice/partition/gpt" "github.com/siderolabs/go-blockdevice/blockdevice/util" "github.com/siderolabs/go-cmd/pkg/cmd" "github.com/siderolabs/go-cmd/pkg/cmd/proc" @@ -44,7 +42,6 @@ import ( "golang.org/x/sys/unix" runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1" - installer "github.com/siderolabs/talos/cmd/installer/pkg/install" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/disk" "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/emergency" @@ -61,7 +58,6 @@ import ( "github.com/siderolabs/talos/internal/pkg/logind" "github.com/siderolabs/talos/internal/pkg/meta" "github.com/siderolabs/talos/internal/pkg/mount" - "github.com/siderolabs/talos/internal/pkg/partition" "github.com/siderolabs/talos/internal/pkg/secureboot" "github.com/siderolabs/talos/internal/pkg/secureboot/tpm2" "github.com/siderolabs/talos/pkg/conditions" @@ -74,6 +70,7 @@ import ( "github.com/siderolabs/talos/pkg/machinery/config/types/v1alpha1" "github.com/siderolabs/talos/pkg/machinery/constants" metamachinery "github.com/siderolabs/talos/pkg/machinery/meta" + "github.com/siderolabs/talos/pkg/machinery/resources/block" resourcefiles "github.com/siderolabs/talos/pkg/machinery/resources/files" "github.com/siderolabs/talos/pkg/machinery/resources/k8s" resourceruntime "github.com/siderolabs/talos/pkg/machinery/resources/runtime" @@ -466,7 +463,7 @@ func SaveConfig(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) { func MemorySizeCheck(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error { if r.State().Platform().Mode() == runtime.ModeContainer { - log.Println("skipping memory size check in the container") + logger.Println("skipping memory size check in the container") return nil } @@ -488,17 +485,17 @@ func MemorySizeCheck(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) switch memTotal := pointer.SafeDeref(info.MemTotal) * humanize.KiByte; { case memTotal < minimum: - log.Println("WARNING: memory size is less than recommended") - log.Println("WARNING: Talos may not work properly") - log.Println("WARNING: minimum memory size is", minimum/humanize.MiByte, "MiB") - log.Println("WARNING: recommended memory size is", recommended/humanize.MiByte, "MiB") - log.Println("WARNING: current total memory size is", memTotal/humanize.MiByte, "MiB") + logger.Println("WARNING: memory size is less than recommended") + logger.Println("WARNING: Talos may not work properly") + logger.Println("WARNING: minimum memory size is", minimum/humanize.MiByte, "MiB") + logger.Println("WARNING: recommended memory size is", recommended/humanize.MiByte, "MiB") + logger.Println("WARNING: current total memory size is", memTotal/humanize.MiByte, "MiB") case memTotal < recommended: - log.Println("NOTE: recommended memory size is", recommended/humanize.MiByte, "MiB") - log.Println("NOTE: current total memory size is", memTotal/humanize.MiByte, "MiB") + logger.Println("NOTE: recommended memory size is", recommended/humanize.MiByte, "MiB") + logger.Println("NOTE: current total memory size is", memTotal/humanize.MiByte, "MiB") default: - log.Println("memory size is OK") - log.Println("memory size is", memTotal/humanize.MiByte, "MiB") + logger.Println("memory size is OK") + logger.Println("memory size is", memTotal/humanize.MiByte, "MiB") } return nil @@ -509,29 +506,26 @@ func MemorySizeCheck(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) func DiskSizeCheck(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error { if r.State().Platform().Mode() == runtime.ModeContainer { - log.Println("skipping disk size check in the container") + logger.Println("skipping disk size check in the container") return nil } - disk := r.State().Machine().Disk() // get ephemeral disk state - if disk == nil { - return errors.New("failed to get ephemeral disk state") - } - - diskSize, err := disk.Size() + ephemeralStatus, err := waitForVolumeReady(ctx, r, constants.EphemeralPartitionLabel) if err != nil { - return fmt.Errorf("failed to get ephemeral disk size: %w", err) + return err } + diskSize := ephemeralStatus.TypedSpec().Size + if minimum := minimal.DiskSize(); diskSize < minimum { - log.Println("WARNING: disk size is less than recommended") - log.Println("WARNING: Talos may not work properly") - log.Println("WARNING: minimum recommended disk size is", minimum/humanize.MiByte, "MiB") - log.Println("WARNING: current total disk size is", diskSize/humanize.MiByte, "MiB") + logger.Println("WARNING: disk size is less than recommended") + logger.Println("WARNING: Talos may not work properly") + logger.Println("WARNING: minimum recommended disk size is", minimum/humanize.MiByte, "MiB") + logger.Println("WARNING: current total disk size is", diskSize/humanize.MiByte, "MiB") } else { - log.Println("disk size is OK") - log.Println("disk size is", diskSize/humanize.MiByte, "MiB") + logger.Println("disk size is OK") + logger.Println("disk size is", diskSize/humanize.MiByte, "MiB") } return nil @@ -833,9 +827,9 @@ func SetupVarDirectory(runtime.Sequence, any) (runtime.TaskExecutionFunc, string // MountUserDisks represents the MountUserDisks task. func MountUserDisks(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { - if err = partitionAndFormatDisks(logger, r); err != nil { - return err - } + // if err = partitionAndFormatDisks(logger, r); err != nil { + // return err + // } return mountDisks(logger, r) }, "mountUserDisks" @@ -843,81 +837,82 @@ func MountUserDisks(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) { // TODO(andrewrynhard): We shouldn't pull in the installer command package // here. -func partitionAndFormatDisks(logger *log.Logger, r runtime.Runtime) error { - m := &installer.Manifest{ - Devices: map[string]installer.Device{}, - Targets: map[string][]*installer.Target{}, - Printf: logger.Printf, - } - - for _, disk := range r.Config().Machine().Disks() { - if err := func() error { - bd, err := blockdevice.Open(disk.Device(), blockdevice.WithMode(blockdevice.ReadonlyMode), blockdevice.WithExclusiveLock(true)) - if err != nil { - return err - } - - deviceName := bd.Device().Name() - - if disk.Device() != deviceName { - logger.Printf("using device name %q instead of %q", deviceName, disk.Device()) - } - - //nolint:errcheck - defer bd.Close() - - var pt *gpt.GPT - - pt, err = bd.PartitionTable() - if err != nil { - if !errors.Is(err, blockdevice.ErrMissingPartitionTable) { - return err - } - } - - // Partitions will be created/recreated if either of the following - // conditions are true: - // - a partition table exists AND there are no partitions - // - a partition table does not exist - - if pt != nil { - if len(pt.Partitions().Items()) > 0 { - logger.Printf(("skipping setup of %q, found existing partitions"), deviceName) - - return nil - } - } - - m.Devices[deviceName] = installer.Device{ - Device: deviceName, - ResetPartitionTable: true, - SkipOverlayMountsCheck: true, - } - for _, part := range disk.Partitions() { - extraTarget := &installer.Target{ - Device: deviceName, - FormatOptions: &partition.FormatOptions{ - Force: true, - FileSystemType: partition.FilesystemTypeXFS, - }, - Options: &partition.Options{ - Size: part.Size(), - PartitionType: partition.LinuxFilesystemData, - }, - } - - m.Targets[deviceName] = append(m.Targets[deviceName], extraTarget) - } - - return nil - }(); err != nil { - return err - } - } - - return m.Execute() -} +// func partitionAndFormatDisks(logger *log.Logger, r runtime.Runtime) error { +// m := &installer.Manifest{ +// Devices: map[string]installer.Device{}, +// Targets: map[string][]*installer.Target{}, +// Printf: logger.Printf, +// } + +// for _, disk := range r.Config().Machine().Disks() { +// if err := func() error { +// bd, err := blockdevice.Open(disk.Device(), blockdevice.WithMode(blockdevice.ReadonlyMode), blockdevice.WithExclusiveLock(true)) +// if err != nil { +// return err +// } + +// deviceName := bd.Device().Name() + +// if disk.Device() != deviceName { +// logger.Printf("using device name %q instead of %q", deviceName, disk.Device()) +// } + +// //nolint:errcheck +// defer bd.Close() + +// var pt *gpt.GPT + +// pt, err = bd.PartitionTable() +// if err != nil { +// if !errors.Is(err, blockdevice.ErrMissingPartitionTable) { +// return err +// } +// } + +// // Partitions will be created/recreated if either of the following +// // conditions are true: +// // - a partition table exists AND there are no partitions +// // - a partition table does not exist + +// if pt != nil { +// if len(pt.Partitions().Items()) > 0 { +// logger.Printf(("skipping setup of %q, found existing partitions"), deviceName) + +// return nil +// } +// } + +// m.Devices[deviceName] = installer.Device{ +// Device: deviceName, +// ResetPartitionTable: true, +// SkipOverlayMountsCheck: true, +// } + +// for _, part := range disk.Partitions() { +// extraTarget := &installer.Target{ +// Device: deviceName, +// FormatOptions: &partition.FormatOptions{ +// Force: true, +// FileSystemType: partition.FilesystemTypeXFS, +// }, +// Options: &partition.Options{ +// Size: part.Size(), +// PartitionType: partition.LinuxFilesystemData, +// }, +// } + +// m.Targets[deviceName] = append(m.Targets[deviceName], extraTarget) +// } + +// return nil +// }(); err != nil { +// return err +// } +// } + +// return m.Execute() +// } func mountDisks(logger *log.Logger, r runtime.Runtime) (err error) { mountpoints := mount.NewMountPoints() @@ -1530,32 +1525,32 @@ func ResetSystemDiskPartitions(seq runtime.Sequence, _ any) (runtime.TaskExecuti } return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error { - targets, err := parseTargets(r, *wipeStr) - if err != nil { - return err - } + // targets, err := parseTargets(r, *wipeStr) + // if err != nil { + // return err + // } - fn, _ := ResetSystemDiskSpec(seq, targets) - diskTargets := targets.GetSystemDiskTargets() + // fn, _ := ResetSystemDiskSpec(seq, targets) + // diskTargets := targets.GetSystemDiskTargets() - logger.Printf("resetting system disks %s", diskTargets) + // logger.Printf("resetting system disks %s", diskTargets) - err = fn(ctx, logger, r) - if err != nil { - logger.Printf("resetting system disks %s failed", diskTargets) + // err = fn(ctx, logger, r) + // if err != nil { + // logger.Printf("resetting system disks %s failed", diskTargets) - return err - } + // return err + // } - logger.Printf("finished resetting system disks %s", diskTargets) + // logger.Printf("finished resetting system disks %s", diskTargets) - bootWiped := slices.ContainsFunc(diskTargets, func(t runtime.PartitionTarget) bool { - return t.GetLabel() == constants.BootPartitionLabel - }) + // bootWiped := slices.ContainsFunc(diskTargets, func(t runtime.PartitionTarget) bool { + // return t.GetLabel() == constants.BootPartitionLabel + // }) - if bootWiped { - return reboot(ctx, logger, r) // only reboot when we wiped boot partition - } + // if bootWiped { + // return reboot(ctx, logger, r) // only reboot when we wiped boot partition + // } return nil }, "wipeSystemDiskPartitions" @@ -1618,49 +1613,49 @@ func ResetUserDisks(_ runtime.Sequence, data any) (runtime.TaskExecutionFunc, st }, "resetUserDisks" } -type targets struct { - systemDiskTargets []*installer.Target -} +// type targets struct { +// systemDiskTargets []*installer.Target +// } -func (opt targets) GetSystemDiskTargets() []runtime.PartitionTarget { - return xslices.Map(opt.systemDiskTargets, func(t *installer.Target) runtime.PartitionTarget { return t }) -} +// func (opt targets) GetSystemDiskTargets() []runtime.PartitionTarget { +// return xslices.Map(opt.systemDiskTargets, func(t *installer.Target) runtime.PartitionTarget { return t }) +// } -func parseTargets(r runtime.Runtime, wipeStr string) (targets, error) { - after, found := strings.CutPrefix(wipeStr, "system:") - if !found { - return targets{}, fmt.Errorf("invalid wipe labels string: %q", wipeStr) - } +// func parseTargets(r runtime.Runtime, wipeStr string) (targets, error) { +// after, found := strings.CutPrefix(wipeStr, "system:") +// if !found { +// return targets{}, fmt.Errorf("invalid wipe labels string: %q", wipeStr) +// } - var result []*installer.Target //nolint:prealloc +// var result []*installer.Target //nolint:prealloc - for _, part := range strings.Split(after, ",") { - bd := r.State().Machine().Disk().BlockDevice +// for _, part := range strings.Split(after, ",") { +// bd := r.State().Machine().Disk().BlockDevice - target, err := installer.ParseTarget(part, bd.Device().Name()) - if err != nil { - return targets{}, fmt.Errorf("error parsing target label %q: %w", part, err) - } +// target, err := installer.ParseTarget(part, bd.Device().Name()) +// if err != nil { +// return targets{}, fmt.Errorf("error parsing target label %q: %w", part, err) +// } - pt, err := bd.PartitionTable() - if err != nil { - return targets{}, fmt.Errorf("error reading partition table: %w", err) - } +// pt, err := bd.PartitionTable() +// if err != nil { +// return targets{}, fmt.Errorf("error reading partition table: %w", err) +// } - _, err = target.Locate(pt) - if err != nil { - return targets{}, fmt.Errorf("error locating partition %q: %w", part, err) - } +// _, err = target.Locate(pt) +// if err != nil { +// return targets{}, fmt.Errorf("error locating partition %q: %w", part, err) +// } - result = append(result, target) - } +// result = append(result, target) +// } - if len(result) == 0 { - return targets{}, errors.New("no wipe labels specified") - } +// if len(result) == 0 { +// return targets{}, errors.New("no wipe labels specified") +// } - return targets{systemDiskTargets: result}, nil -} +// return targets{systemDiskTargets: result}, nil +// } // SystemDiskTargets represents the interface for getting the system disk targets. // It's a subset of [runtime.ResetOptions]. @@ -1911,6 +1906,10 @@ func UnmountEFIPartition(runtime.Sequence, any) (runtime.TaskExecutionFunc, stri // MountStatePartition mounts the system partition. func MountStatePartition(seq runtime.Sequence, _ any) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) (err error) { + if _, err = waitForVolumeReady(ctx, r, constants.StatePartitionLabel); err != nil { + return err + } + flags := mount.SkipIfMounted if seq == runtime.SequenceInitialize { @@ -1958,6 +1957,10 @@ func UnmountStatePartition(runtime.Sequence, any) (runtime.TaskExecutionFunc, st // MountEphemeralPartition mounts the ephemeral partition. func MountEphemeralPartition(runtime.Sequence, any) (runtime.TaskExecutionFunc, string) { return func(ctx context.Context, logger *log.Logger, r runtime.Runtime) error { + if _, err := waitForVolumeReady(ctx, r, constants.EphemeralPartitionLabel); err != nil { + return err + } + return mount.SystemPartitionMount(ctx, r, logger, constants.EphemeralPartitionLabel, mount.WithFlags(mount.Resize), mount.WithProjectQuota(r.Config().Machine().Features().DiskQuotaSupportEnabled())) @@ -2396,3 +2399,22 @@ func logError(err error, logger *log.Logger) error { return nil } + +func waitForVolumeReady(ctx context.Context, r runtime.Runtime, volumeID string) (*block.VolumeStatus, error) { + volumeStatus, err := r.State().V1Alpha2().Resources().WatchFor(ctx, + block.NewVolumeStatus(block.NamespaceName, volumeID).Metadata(), + state.WithCondition(func(r resource.Resource) (bool, error) { + volumeStatus, ok := r.(*block.VolumeStatus) + if !ok { + return false, nil + } + + return volumeStatus.TypedSpec().Phase == block.VolumePhaseReady, nil + }), + ) + if err != nil { + return nil, fmt.Errorf("error waiting for volume %q to be ready: %w", volumeID, err) + } + + return volumeStatus.(*block.VolumeStatus), nil +} diff --git a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_state.go b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_state.go index 0eb0cb1543a..95a23f7f204 100644 --- a/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_state.go +++ b/internal/app/machined/pkg/runtime/v1alpha1/v1alpha1_state.go @@ -10,7 +10,10 @@ import ( "log" "os" "sync" + "time" + "github.com/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/safe" "github.com/cosi-project/runtime/pkg/state" multierror "github.com/hashicorp/go-multierror" "github.com/siderolabs/go-blockdevice/blockdevice/probe" @@ -21,6 +24,7 @@ import ( "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha2" "github.com/siderolabs/talos/internal/pkg/meta" "github.com/siderolabs/talos/pkg/machinery/constants" + "github.com/siderolabs/talos/pkg/machinery/resources/block" ) // State implements the state interface. @@ -296,9 +300,43 @@ func (s *MachineState) Close() error { // Installed implements the machine state interface. func (s *MachineState) Installed() bool { - return s.Disk( - disk.WithPartitionLabel(constants.EphemeralPartitionLabel), - ) != nil + // undefined in container mode + if s.platform.Mode() == runtime.ModeContainer { + return true + } + + // legacy flow, no context available + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute) + defer cancel() + + metaStatus, err := safe.StateWatchFor[*block.VolumeStatus]( + ctx, + s.resources, + block.NewVolumeStatus(block.NamespaceName, constants.MetaPartitionLabel).Metadata(), + state.WithEventTypes(state.Created, state.Updated), + state.WithCondition(func(r resource.Resource) (bool, error) { + vs, ok := r.(*block.VolumeStatus) + if !ok { + return false, nil + } + + switch vs.TypedSpec().Phase { //nolint:exhaustive + case block.VolumePhaseMissing: + // no META, talos is not installed + return true, nil + case block.VolumePhaseReady: + // META found + return true, nil + default: + return false, nil + } + }), + ) + if err != nil { + return false + } + + return metaStatus.TypedSpec().Phase == block.VolumePhaseReady } // IsInstallStaged implements the machine state interface. diff --git a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go index 2eefb73f806..0ab43043f02 100644 --- a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go +++ b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_controller.go @@ -94,6 +94,8 @@ func (ctrl *Controller) Run(ctx context.Context, drainer *runtime.Drainer) error &block.DiscoveryController{}, &block.DisksController{}, &block.SystemDiskController{}, + &block.VolumeConfigController{}, + &block.VolumeManagerController{}, &cluster.AffiliateMergeController{}, cluster.NewConfigController(), &cluster.DiscoveryServiceController{}, diff --git a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go index 4354d73c853..7ffae737b18 100644 --- a/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go +++ b/internal/app/machined/pkg/runtime/v1alpha2/v1alpha2_state.go @@ -97,8 +97,12 @@ func NewState() (*State, error) { for _, r := range []meta.ResourceWithRD{ &block.Device{}, &block.DiscoveredVolume{}, + &block.DiscoveryRefreshRequest{}, + &block.DiscoveryRefreshStatus{}, &block.Disk{}, &block.SystemDisk{}, + &block.VolumeConfig{}, + &block.VolumeStatus{}, &cluster.Affiliate{}, &cluster.Config{}, &cluster.Identity{}, diff --git a/internal/app/machined/revert.go b/internal/app/machined/revert.go index bd48c3ca078..c106eee2780 100644 --- a/internal/app/machined/revert.go +++ b/internal/app/machined/revert.go @@ -9,7 +9,6 @@ import ( "log" "os" - "github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader" "github.com/siderolabs/talos/internal/pkg/meta" ) @@ -45,6 +44,7 @@ func revertBootloadInternal(ctx context.Context) error { log.Printf("reverting failed upgrade, switching to %q", label) + /* [TODO] restore me if err = func() error { config, probeErr := bootloader.Probe(ctx, "") if probeErr != nil { @@ -60,6 +60,7 @@ func revertBootloadInternal(ctx context.Context) error { }(); err != nil { return err } + */ if _, err = metaState.DeleteTag(ctx, meta.Upgrade); err != nil { return err diff --git a/internal/pkg/meta/meta.go b/internal/pkg/meta/meta.go index cb10e6b02ac..5add6b6a8b3 100644 --- a/internal/pkg/meta/meta.go +++ b/internal/pkg/meta/meta.go @@ -7,21 +7,25 @@ package meta import ( "context" + "errors" "fmt" "io" "log" "os" + goruntime "runtime" "sync" "github.com/cosi-project/runtime/pkg/resource" "github.com/cosi-project/runtime/pkg/safe" "github.com/cosi-project/runtime/pkg/state" "github.com/siderolabs/go-blockdevice/blockdevice/probe" + "golang.org/x/sys/unix" "github.com/siderolabs/talos/internal/pkg/meta/internal/adv" "github.com/siderolabs/talos/internal/pkg/meta/internal/adv/syslinux" "github.com/siderolabs/talos/internal/pkg/meta/internal/adv/talos" "github.com/siderolabs/talos/pkg/machinery/constants" + "github.com/siderolabs/talos/pkg/machinery/resources/block" "github.com/siderolabs/talos/pkg/machinery/resources/runtime" ) @@ -90,11 +94,29 @@ func New(ctx context.Context, st state.State, opts ...Option) (*Meta, error) { return meta, err } -func (meta *Meta) getPath() (string, error) { +func (meta *Meta) getPath(ctx context.Context) (string, error) { if meta.opts.fixedPath != "" { return meta.opts.fixedPath, nil } + if meta.state != nil { + metaStatus, err := safe.StateGetByID[*block.VolumeStatus](ctx, meta.state, constants.MetaPartitionLabel) + if err != nil { + if state.IsNotFoundError(err) { + return "", os.ErrNotExist + } + + return "", err + } + + if metaStatus.TypedSpec().Phase != block.VolumePhaseReady { + return "", os.ErrNotExist + } + + return metaStatus.TypedSpec().Location, nil + } + + // legacy support, without state dev, err := probe.GetDevWithPartitionName(constants.MetaPartitionLabel) if err != nil { return "", err @@ -110,7 +132,7 @@ func (meta *Meta) Reload(ctx context.Context) error { meta.mu.Lock() defer meta.mu.Unlock() - path, err := meta.getPath() + path, err := meta.getPath(ctx) if err != nil { return err } @@ -122,6 +144,10 @@ func (meta *Meta) Reload(ctx context.Context) error { defer f.Close() //nolint:errcheck + if err := flock(f, unix.LOCK_SH); err != nil { + return err + } + adv, err := talos.NewADV(f) if adv == nil && err != nil { // if adv is not nil, but err is nil, it might be missing ADV, ignore it @@ -183,11 +209,13 @@ func (meta *Meta) syncState(ctx context.Context) error { } // Flush writes the META to the disk. +// +//nolint:gocyclo func (meta *Meta) Flush() error { meta.mu.Lock() defer meta.mu.Unlock() - path, err := meta.getPath() + path, err := meta.getPath(context.TODO()) if err != nil { return err } @@ -199,6 +227,10 @@ func (meta *Meta) Flush() error { defer f.Close() //nolint:errcheck + if err := flock(f, unix.LOCK_EX); err != nil { + return err + } + serialized, err := meta.talos.Bytes() if err != nil { return err @@ -343,3 +375,13 @@ func updateTagResource(ctx context.Context, st state.State, t uint8, val string) return err } + +func flock(f *os.File, flag int) error { + for { + if err := unix.Flock(int(f.Fd()), flag); !errors.Is(err, unix.EINTR) { + return err + } + + goruntime.KeepAlive(f) + } +} diff --git a/internal/pkg/mount/v2/mount.go b/internal/pkg/mount/v2/mount.go new file mode 100644 index 00000000000..590b66cc769 --- /dev/null +++ b/internal/pkg/mount/v2/mount.go @@ -0,0 +1,264 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package mount handles filesystem mount operations. +package mount + +import ( + "bufio" + "context" + "fmt" + "os" + "strings" + "time" + + "github.com/siderolabs/go-retry/retry" + "golang.org/x/sys/unix" +) + +// Point represents a mount point. +type Point struct { + source string + target string + fstype string + flags uintptr + data string +} + +// NewPointOption is a mount point option. +type NewPointOption func(*Point) + +// WithProjectQuota sets the project quota flag. +func WithProjectQuota() NewPointOption { + return func(p *Point) { + if len(p.data) > 0 { + p.data += "," + } + + p.data += "prjquota" + } +} + +// WithFlags sets the mount flags. +func WithFlags(flags uintptr) NewPointOption { + return func(p *Point) { + p.flags |= flags + } +} + +// WithReadonly sets the read-only flag. +func WithReadonly() NewPointOption { + return WithFlags(unix.MS_RDONLY) +} + +// NewPoint creates a new mount point. +func NewPoint(source, target, fstype string, opts ...NewPointOption) *Point { + p := &Point{ + source: source, + target: target, + fstype: fstype, + } + + for _, opt := range opts { + opt(p) + } + + return p +} + +// PrinterOptions are printer options. +type PrinterOptions struct { + Printer func(string, ...any) +} + +// Printf prints a formatted string (or skips if printer is nil). +func (o PrinterOptions) Printf(format string, args ...any) { + if o.Printer != nil { + o.Printer(format, args...) + } +} + +// MountOptions are mount options. +type MountOptions struct { + PrinterOptions + + SkipIfMounted bool + + TargetMode os.FileMode +} + +// MountOption is a mount option. +type MountOption func(*MountOptions) + +// WithSkipIfMounted sets the skip if mounted flag. +func WithSkipIfMounted() MountOption { + return func(o *MountOptions) { + o.SkipIfMounted = true + } +} + +// WithMountPrinter sets the printer. +func WithMountPrinter(printer func(string, ...any)) MountOption { + return func(o *MountOptions) { + o.Printer = printer + } +} + +// UnmountOptions is unmount options. +type UnmountOptions struct { + PrinterOptions +} + +// UnmountOption is an unmount option. +type UnmountOption func(*UnmountOptions) + +// WithUnmountPrinter sets the printer. +func WithUnmountPrinter(printer func(string, ...any)) UnmountOption { + return func(o *UnmountOptions) { + o.Printer = printer + } +} + +// IsMounted checks if the mount point is mounted by checking the mount on the target. +func (p *Point) IsMounted() (bool, error) { + f, err := os.Open("/proc/mounts") + if err != nil { + return false, err + } + + defer f.Close() //nolint:errcheck + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + fields := strings.Fields(scanner.Text()) + + if len(fields) < 2 { + continue + } + + mountpoint := fields[1] + + if mountpoint == p.target { + return true, nil + } + } + + return false, scanner.Err() +} + +// Mount the mount point. +// +// Mount returns an unmounter function to unmount the mount point. +func (p *Point) Mount(opts ...MountOption) (unmounter func() error, err error) { + options := MountOptions{ + TargetMode: 0o755, + } + + for _, opt := range opts { + opt(&options) + } + + if options.SkipIfMounted { + isMounted, err := p.IsMounted() + if err != nil { + return nil, err + } + + // already mounted, return a no-op unmounter + if isMounted { + return func() error { + return nil + }, nil + } + } + + if err = os.MkdirAll(p.target, options.TargetMode); err != nil { + return nil, fmt.Errorf("error creating mount point directory %s: %w", p.target, err) + } + + err = p.retry(p.mount, false, options.PrinterOptions) + if err != nil { + return nil, fmt.Errorf("error mounting %s: %w", p.source, err) + } + + return func() error { + return p.Unmount(WithUnmountPrinter(options.Printer)) + }, nil +} + +// Unmount the mount point. +func (p *Point) Unmount(opts ...UnmountOption) error { + var options UnmountOptions + + for _, opt := range opts { + opt(&options) + } + + mounted, err := p.IsMounted() + if err != nil { + return err + } + + if !mounted { + return nil + } + + return p.retry(func() error { + return p.unmount(options.Printer) + }, true, options.PrinterOptions) +} + +func (p *Point) mount() error { + return unix.Mount(p.source, p.target, p.fstype, p.flags, p.data) +} + +func (p *Point) unmount(printer func(string, ...any)) error { + return SafeUnmount(context.Background(), printer, p.target) +} + +//nolint:gocyclo +func (p *Point) retry(f func() error, isUnmount bool, printerOptions PrinterOptions) error { + return retry.Constant(5*time.Second, retry.WithUnits(50*time.Millisecond)).Retry(func() error { + if err := f(); err != nil { + switch err { + case unix.EBUSY: + return retry.ExpectedError(err) + case unix.ENOENT, unix.ENXIO: + // if udevd triggers BLKRRPART ioctl, partition device entry might disappear temporarily + return retry.ExpectedError(err) + case unix.EUCLEAN, unix.EIO: + if !isUnmount { + if errRepair := p.repair(printerOptions); errRepair != nil { + return fmt.Errorf("error repairing: %w", errRepair) + } + } + + return retry.ExpectedError(err) + case unix.EINVAL: + isMounted, checkErr := p.IsMounted() + if checkErr != nil { + return retry.ExpectedError(checkErr) + } + + if !isMounted && !isUnmount { + if errRepair := p.repair(printerOptions); errRepair != nil { + return fmt.Errorf("error repairing: %w", errRepair) + } + + return retry.ExpectedError(err) + } + + if !isMounted && isUnmount { // if partition is already unmounted, ignore EINVAL + return nil + } + + return err + default: + return err + } + } + + return nil + }) +} diff --git a/internal/pkg/mount/v2/points.go b/internal/pkg/mount/v2/points.go new file mode 100644 index 00000000000..b0d1f925a6c --- /dev/null +++ b/internal/pkg/mount/v2/points.go @@ -0,0 +1,46 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package mount + +import ( + "errors" + "slices" +) + +// Points is a list of mount points. +type Points []*Point + +// Mount all mount points. +func (points Points) Mount(opts ...MountOption) (unmounter func() error, err error) { + unmounters := make([]func() error, 0, len(points)) + + for _, point := range points { + unmounter, err := point.Mount(opts...) + if err != nil { + // unmount what got already mounted + slices.Reverse(unmounters) + + for _, unmounter := range unmounters { + _ = unmounter() //nolint:errcheck + } + + return nil, err + } + + unmounters = append(unmounters, unmounter) + } + + slices.Reverse(unmounters) + + return func() error { + var unmountErr error + + for _, unmounter := range unmounters { + unmountErr = errors.Join(unmounter()) + } + + return unmountErr + }, nil +} diff --git a/internal/pkg/mount/v2/repair.go b/internal/pkg/mount/v2/repair.go new file mode 100644 index 00000000000..06ffacad90e --- /dev/null +++ b/internal/pkg/mount/v2/repair.go @@ -0,0 +1,24 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package mount + +import ( + "fmt" + + "github.com/siderolabs/talos/pkg/makefs" +) + +// repair a filesystem. +func (p *Point) repair(printerOptions PrinterOptions) error { + printerOptions.Printf("filesystem on %s needs cleaning, running repair", p.source) + + if err := makefs.XFSRepair(p.source, p.fstype); err != nil { + return fmt.Errorf("xfs_repair: %w", err) + } + + printerOptions.Printf("filesystem successfully repaired on %s", p.source) + + return nil +} diff --git a/internal/pkg/mount/v2/unmount.go b/internal/pkg/mount/v2/unmount.go new file mode 100644 index 00000000000..ef6c8904272 --- /dev/null +++ b/internal/pkg/mount/v2/unmount.go @@ -0,0 +1,76 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package mount + +import ( + "context" + "fmt" + "time" + + "golang.org/x/sys/unix" +) + +func unmountLoop(ctx context.Context, printer func(string, ...any), target string, flags int, timeout time.Duration, extraMessage string) (bool, error) { + errCh := make(chan error, 1) + + go func() { + errCh <- unix.Unmount(target, flags) + }() + + start := time.Now() + + progressTicker := time.NewTicker(timeout / 5) + defer progressTicker.Stop() + +unmountLoop: + for { + select { + case <-ctx.Done(): + return true, ctx.Err() + case err := <-errCh: + return true, err + case <-progressTicker.C: + timeLeft := timeout - time.Since(start) + + if timeLeft <= 0 { + break unmountLoop + } + + if printer != nil { + printer("unmounting %s%s is taking longer than expected, still waiting for %s", target, extraMessage, timeLeft) + } + } + } + + return false, nil +} + +// SafeUnmount unmounts the target path, first without force, then with force if the first attempt fails. +// +// It makes sure that unmounting has a finite operation timeout. +func SafeUnmount(ctx context.Context, printer func(string, ...any), target string) error { + const ( + unmountTimeout = 90 * time.Second + unmountForceTimeout = 10 * time.Second + ) + + ok, err := unmountLoop(ctx, printer, target, 0, unmountTimeout, "") + + if ok { + return err + } + + if printer != nil { + printer("unmounting %s with force", target) + } + + ok, err = unmountLoop(ctx, printer, target, unix.MNT_FORCE, unmountTimeout, " with force flag") + + if ok { + return err + } + + return fmt.Errorf("unmounting %s with force flag timed out", target) +} diff --git a/internal/pkg/partition/constants.go b/internal/pkg/partition/constants.go index 53453718196..0f2c8d17f99 100644 --- a/internal/pkg/partition/constants.go +++ b/internal/pkg/partition/constants.go @@ -21,14 +21,16 @@ type FileSystemType = string // Filesystem types. const ( - FilesystemTypeNone FileSystemType = "none" - FilesystemTypeXFS FileSystemType = "xfs" - FilesystemTypeVFAT FileSystemType = "vfat" + FilesystemTypeNone FileSystemType = "none" + FilesystemTypeZeroes FileSystemType = "zeroes" + FilesystemTypeXFS FileSystemType = "xfs" + FilesystemTypeVFAT FileSystemType = "vfat" ) // Partition default sizes. const ( MiB = 1024 * 1024 + GiB = 1024 * MiB EFISize = 100 * MiB BIOSGrubSize = 1 * MiB @@ -36,7 +38,8 @@ const ( // EFIUKISize is the size of the EFI partition when UKI is enabled. // With UKI all assets are stored in the EFI partition. // This is the size of the old EFISize + BIOSGrubSize + BootSize. - EFIUKISize = EFISize + BIOSGrubSize + BootSize - MetaSize = 1 * MiB - StateSize = 100 * MiB + EFIUKISize = EFISize + BIOSGrubSize + BootSize + MetaSize = 1 * MiB + StateSize = 100 * MiB + EphemeralMinSize = 2 * GiB ) diff --git a/internal/pkg/partition/format.go b/internal/pkg/partition/format.go index 8c59742ddbc..e3be84e522d 100644 --- a/internal/pkg/partition/format.go +++ b/internal/pkg/partition/format.go @@ -8,7 +8,7 @@ package partition import ( "fmt" - "github.com/siderolabs/go-blockdevice/blockdevice" + "github.com/siderolabs/go-blockdevice/v2/block" "github.com/siderolabs/talos/pkg/machinery/constants" "github.com/siderolabs/talos/pkg/makefs" @@ -29,10 +29,6 @@ func NewFormatOptions(label string) *FormatOptions { // Format zeroes the device and formats it using filesystem type provided. func Format(devname string, t *FormatOptions, printf func(string, ...any)) error { - if t.FileSystemType == FilesystemTypeNone { - return zeroPartition(devname, printf) - } - opts := []makefs.Option{makefs.WithForce(t.Force), makefs.WithLabel(t.Label)} if t.UnsupportedFSOption { @@ -42,6 +38,10 @@ func Format(devname string, t *FormatOptions, printf func(string, ...any)) error printf("formatting the partition %q as %q with label %q\n", devname, t.FileSystemType, t.Label) switch t.FileSystemType { + case FilesystemTypeNone: + return nil + case FilesystemTypeZeroes: + return zeroPartition(devname, printf) case FilesystemTypeVFAT: return makefs.VFAT(devname, opts...) case FilesystemTypeXFS: @@ -55,7 +55,7 @@ func Format(devname string, t *FormatOptions, printf func(string, ...any)) error func zeroPartition(devname string, printf func(string, ...any)) (err error) { printf("zeroing out %q", devname) - part, err := blockdevice.Open(devname, blockdevice.WithExclusiveLock(true)) + part, err := block.NewFromPath(devname, block.OpenForWrite()) if err != nil { return err } @@ -76,7 +76,7 @@ func systemPartitionsFormatOptions(label string) *FormatOptions { case constants.BIOSGrubPartitionLabel: return &FormatOptions{ Label: constants.BIOSGrubPartitionLabel, - FileSystemType: FilesystemTypeNone, + FileSystemType: FilesystemTypeZeroes, Force: true, } case constants.BootPartitionLabel: @@ -88,21 +88,18 @@ func systemPartitionsFormatOptions(label string) *FormatOptions { case constants.MetaPartitionLabel: return &FormatOptions{ Label: constants.MetaPartitionLabel, - FileSystemType: FilesystemTypeNone, + FileSystemType: FilesystemTypeZeroes, Force: true, } case constants.StatePartitionLabel: return &FormatOptions{ - Label: constants.StatePartitionLabel, - FileSystemType: FilesystemTypeXFS, - Force: true, - UnsupportedFSOption: true, + Label: constants.StatePartitionLabel, + FileSystemType: FilesystemTypeNone, } case constants.EphemeralPartitionLabel: return &FormatOptions{ Label: constants.EphemeralPartitionLabel, - FileSystemType: FilesystemTypeXFS, - Force: true, + FileSystemType: FilesystemTypeNone, } default: return nil diff --git a/internal/pkg/partition/format_test.go b/internal/pkg/partition/format_test.go deleted file mode 100644 index 79ffe22f1f7..00000000000 --- a/internal/pkg/partition/format_test.go +++ /dev/null @@ -1,157 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -// Package partition provides common utils for system partition format. -package partition_test - -import ( - "bytes" - "io" - "os" - "testing" - - "github.com/siderolabs/go-blockdevice/blockdevice" - "github.com/siderolabs/go-blockdevice/blockdevice/loopback" - "github.com/siderolabs/go-blockdevice/blockdevice/partition/gpt" - "github.com/stretchr/testify/suite" - - "github.com/siderolabs/talos/internal/pkg/partition" -) - -type manifestSuite struct { - suite.Suite - - disk *os.File - loopbackDevice *os.File -} - -const ( - diskSize = 10 * 1024 * 1024 // 10 MiB -) - -func TestManifestSuite(t *testing.T) { - suite.Run(t, new(manifestSuite)) -} - -func (suite *manifestSuite) SetupTest() { - suite.skipIfNotRoot() - - var err error - - suite.disk, err = os.CreateTemp("", "talos") - suite.Require().NoError(err) - - suite.Require().NoError(suite.disk.Truncate(diskSize)) - - suite.loopbackDevice, err = loopback.NextLoopDevice() - suite.Require().NoError(err) - - suite.T().Logf("Using %s", suite.loopbackDevice.Name()) - - suite.Require().NoError(loopback.Loop(suite.loopbackDevice, suite.disk)) - - suite.Require().NoError(loopback.LoopSetReadWrite(suite.loopbackDevice)) -} - -func (suite *manifestSuite) TearDownTest() { - if suite.loopbackDevice != nil { - suite.Assert().NoError(loopback.Unloop(suite.loopbackDevice)) - } - - if suite.disk != nil { - suite.Assert().NoError(os.Remove(suite.disk.Name())) - suite.Assert().NoError(suite.disk.Close()) - } -} - -func (suite *manifestSuite) skipIfNotRoot() { - if os.Getuid() != 0 { - suite.T().Skip("can't run the test as non-root") - } -} - -func (suite *manifestSuite) skipUnderBuildkit() { - hostname, _ := os.Hostname() //nolint:errcheck - - if hostname == "buildkitsandbox" { - suite.T().Skip("test not supported under buildkit as partition devices are not propagated from /dev") - } -} - -func (suite *manifestSuite) TestZeroPartition() { - suite.skipUnderBuildkit() - - bd, err := blockdevice.Open(suite.loopbackDevice.Name(), blockdevice.WithExclusiveLock(true)) - suite.Require().NoError(err) - - defer bd.Close() //nolint:errcheck - - pt, err := gpt.New(bd.Device(), gpt.WithMarkMBRBootable(false)) - suite.Require().NoError(err) - - // Create a partition table with a single partition. - _, err = pt.Add(0, gpt.WithMaximumSize(true), gpt.WithPartitionName("zerofill")) - suite.Require().NoError(err) - - suite.Require().NoError(pt.Write()) - suite.Require().NoError(bd.Close()) - - bd, err = blockdevice.Open(suite.loopbackDevice.Name(), blockdevice.WithExclusiveLock(true)) - suite.Require().NoError(err) - - defer bd.Close() //nolint:errcheck - - fills := bytes.NewBuffer(bytes.Repeat([]byte{1}, 10)) - - parts, err := bd.GetPartition("zerofill") - suite.Require().NoError(err) - - part, err := parts.Path() - suite.Require().NoError(err) - - // open the partition as read write - dst, err := os.OpenFile(part, os.O_WRONLY, 0o644) - suite.Require().NoError(err) - - defer dst.Close() //nolint:errcheck - - // Write some data to the partition. - _, err = io.Copy(dst, fills) - suite.Require().NoError(err) - - data, err := os.Open(part) - suite.Require().NoError(err) - - defer data.Close() //nolint:errcheck - - read := make([]byte, fills.Len()) - - _, err = data.Read(read) - suite.Require().NoError(err) - suite.Require().NoError(data.Close()) - - suite.Assert().True(bytes.Equal(fills.Bytes(), read)) - - suite.Require().NoError(bd.Close()) - - err = partition.Format(part, &partition.FormatOptions{ - FileSystemType: partition.FilesystemTypeNone, - }, suite.T().Logf) - suite.Require().NoError(err) - - // reading 10 times more than what we wrote should still return 0 since the partition is wiped - zerofills := bytes.NewBuffer(bytes.Repeat([]byte{0}, 100)) - - data, err = os.Open(part) - suite.Require().NoError(err) - - defer data.Close() //nolint:errcheck - - read = make([]byte, zerofills.Len()) - - _, err = data.Read(read) - suite.Require().NoError(err) - - suite.Assert().True(bytes.Equal(zerofills.Bytes(), read)) -} diff --git a/internal/pkg/partition/partition.go b/internal/pkg/partition/partition.go index fcafa687a93..e0c8fc3dcb7 100644 --- a/internal/pkg/partition/partition.go +++ b/internal/pkg/partition/partition.go @@ -6,75 +6,36 @@ package partition import ( - "github.com/dustin/go-humanize" - "github.com/siderolabs/go-blockdevice/blockdevice/partition/gpt" + "fmt" "github.com/siderolabs/talos/pkg/machinery/constants" ) // Options contains the options for creating a partition. type Options struct { - PartitionLabel string - PartitionType Type - Size uint64 - LegacyBIOSBootable bool -} - -// NewPartitionOptions returns a new PartitionOptions. -func NewPartitionOptions(label string, uki bool) *Options { - return systemPartitionsPartitonOptions(label, uki) -} - -// Locate existing partition on the disk by label. -func Locate(pt *gpt.GPT, label string) (*gpt.Partition, error) { - for _, part := range pt.Partitions().Items() { - if part.Name == label { - return part, nil - } - } + FormatOptions - return nil, nil + PartitionLabel string + PartitionType Type + Size uint64 } -// Partition creates a new partition on the specified device. -// Returns the path to the newly created partition. -func Partition(pt *gpt.GPT, pos int, device string, partitionOpts Options, printf func(string, ...any)) (string, error) { - printf("partitioning %s - %s %q\n", device, partitionOpts.PartitionLabel, humanize.Bytes(partitionOpts.Size)) - - opts := []gpt.PartitionOption{ - gpt.WithPartitionType(partitionOpts.PartitionType), - gpt.WithPartitionName(partitionOpts.PartitionLabel), - } - - if partitionOpts.Size == 0 { - opts = append(opts, gpt.WithMaximumSize(true)) - } - - if partitionOpts.LegacyBIOSBootable { - opts = append(opts, gpt.WithLegacyBIOSBootableAttribute(true)) - } - - part, err := pt.InsertAt(pos, partitionOpts.Size, opts...) - if err != nil { - return "", err - } - - partitionName, err := part.Path() - if err != nil { - return "", err +// NewPartitionOptions returns a new PartitionOptions. +// +//nolint:gocyclo +func NewPartitionOptions(label string, uki bool) Options { + formatOptions := NewFormatOptions(label) + if formatOptions == nil { + panic(fmt.Sprintf("unknown format options for label %q", label)) } - printf("created %s (%s) size %d blocks", partitionName, partitionOpts.PartitionLabel, part.Length()) - - return partitionName, nil -} - -func systemPartitionsPartitonOptions(label string, uki bool) *Options { switch label { case constants.EFIPartitionLabel: - partitionOptions := &Options{ - PartitionType: EFISystemPartition, - Size: EFISize, + partitionOptions := Options{ + FormatOptions: *formatOptions, + PartitionLabel: label, + PartitionType: EFISystemPartition, + Size: EFISize, } if uki { @@ -87,35 +48,45 @@ func systemPartitionsPartitonOptions(label string, uki bool) *Options { panic("BIOS partition is not supported with UKI") } - return &Options{ - PartitionType: BIOSBootPartition, - Size: BIOSGrubSize, + return Options{ + FormatOptions: *formatOptions, + PartitionLabel: label, + PartitionType: BIOSBootPartition, + Size: BIOSGrubSize, } case constants.BootPartitionLabel: if uki { panic("BOOT partition is not supported with UKI") } - return &Options{ - PartitionType: LinuxFilesystemData, - Size: BootSize, + return Options{ + FormatOptions: *formatOptions, + PartitionLabel: label, + PartitionType: LinuxFilesystemData, + Size: BootSize, } case constants.MetaPartitionLabel: - return &Options{ - PartitionType: LinuxFilesystemData, - Size: MetaSize, + return Options{ + FormatOptions: *formatOptions, + PartitionLabel: label, + PartitionType: LinuxFilesystemData, + Size: MetaSize, } case constants.StatePartitionLabel: - return &Options{ - PartitionType: LinuxFilesystemData, - Size: StateSize, + return Options{ + FormatOptions: *formatOptions, + PartitionLabel: label, + PartitionType: LinuxFilesystemData, + Size: StateSize, } case constants.EphemeralPartitionLabel: - return &Options{ - PartitionType: LinuxFilesystemData, - Size: 0, + return Options{ + FormatOptions: *formatOptions, + PartitionLabel: label, + PartitionType: LinuxFilesystemData, + Size: 0, } default: - return nil + panic(fmt.Sprintf("unknown partition label %q", label)) } } diff --git a/pkg/machinery/api/resource/definitions/block/block.pb.go b/pkg/machinery/api/resource/definitions/block/block.pb.go index f2901db7ef6..cbe2918b152 100644 --- a/pkg/machinery/api/resource/definitions/block/block.pb.go +++ b/pkg/machinery/api/resource/definitions/block/block.pb.go @@ -10,8 +10,11 @@ import ( reflect "reflect" sync "sync" + v1alpha1 "google.golang.org/genproto/googleapis/api/expr/v1alpha1" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + + enums "github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums" ) const ( @@ -147,6 +150,8 @@ type DiscoveredVolumeSpec struct { Type string `protobuf:"bytes,14,opt,name=type,proto3" json:"type,omitempty"` DevicePath string `protobuf:"bytes,15,opt,name=device_path,json=devicePath,proto3" json:"device_path,omitempty"` Parent string `protobuf:"bytes,16,opt,name=parent,proto3" json:"parent,omitempty"` + DevPath string `protobuf:"bytes,17,opt,name=dev_path,json=devPath,proto3" json:"dev_path,omitempty"` + ParentDevPath string `protobuf:"bytes,18,opt,name=parent_dev_path,json=parentDevPath,proto3" json:"parent_dev_path,omitempty"` } func (x *DiscoveredVolumeSpec) Reset() { @@ -293,6 +298,164 @@ func (x *DiscoveredVolumeSpec) GetParent() string { return "" } +func (x *DiscoveredVolumeSpec) GetDevPath() string { + if x != nil { + return x.DevPath + } + return "" +} + +func (x *DiscoveredVolumeSpec) GetParentDevPath() string { + if x != nil { + return x.ParentDevPath + } + return "" +} + +// DiscoveryRefreshRequestSpec is the spec for DiscoveryRefreshRequest. +type DiscoveryRefreshRequestSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Request int64 `protobuf:"varint,1,opt,name=request,proto3" json:"request,omitempty"` +} + +func (x *DiscoveryRefreshRequestSpec) Reset() { + *x = DiscoveryRefreshRequestSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_resource_definitions_block_block_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DiscoveryRefreshRequestSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DiscoveryRefreshRequestSpec) ProtoMessage() {} + +func (x *DiscoveryRefreshRequestSpec) ProtoReflect() protoreflect.Message { + mi := &file_resource_definitions_block_block_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DiscoveryRefreshRequestSpec.ProtoReflect.Descriptor instead. +func (*DiscoveryRefreshRequestSpec) Descriptor() ([]byte, []int) { + return file_resource_definitions_block_block_proto_rawDescGZIP(), []int{2} +} + +func (x *DiscoveryRefreshRequestSpec) GetRequest() int64 { + if x != nil { + return x.Request + } + return 0 +} + +// DiscoveryRefreshStatusSpec is the spec for DiscoveryRefreshStatus status. +type DiscoveryRefreshStatusSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Request int64 `protobuf:"varint,1,opt,name=request,proto3" json:"request,omitempty"` +} + +func (x *DiscoveryRefreshStatusSpec) Reset() { + *x = DiscoveryRefreshStatusSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_resource_definitions_block_block_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DiscoveryRefreshStatusSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DiscoveryRefreshStatusSpec) ProtoMessage() {} + +func (x *DiscoveryRefreshStatusSpec) ProtoReflect() protoreflect.Message { + mi := &file_resource_definitions_block_block_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DiscoveryRefreshStatusSpec.ProtoReflect.Descriptor instead. +func (*DiscoveryRefreshStatusSpec) Descriptor() ([]byte, []int) { + return file_resource_definitions_block_block_proto_rawDescGZIP(), []int{3} +} + +func (x *DiscoveryRefreshStatusSpec) GetRequest() int64 { + if x != nil { + return x.Request + } + return 0 +} + +// DiskSelector selects a disk for the volume. +type DiskSelector struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Match *v1alpha1.CheckedExpr `protobuf:"bytes,1,opt,name=match,proto3" json:"match,omitempty"` +} + +func (x *DiskSelector) Reset() { + *x = DiskSelector{} + if protoimpl.UnsafeEnabled { + mi := &file_resource_definitions_block_block_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DiskSelector) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DiskSelector) ProtoMessage() {} + +func (x *DiskSelector) ProtoReflect() protoreflect.Message { + mi := &file_resource_definitions_block_block_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DiskSelector.ProtoReflect.Descriptor instead. +func (*DiskSelector) Descriptor() ([]byte, []int) { + return file_resource_definitions_block_block_proto_rawDescGZIP(), []int{4} +} + +func (x *DiskSelector) GetMatch() *v1alpha1.CheckedExpr { + if x != nil { + return x.Match + } + return nil +} + // DiskSpec is the spec for Disks status. type DiskSpec struct { state protoimpl.MessageState @@ -312,12 +475,13 @@ type DiskSpec struct { Transport string `protobuf:"bytes,11,opt,name=transport,proto3" json:"transport,omitempty"` Rotational bool `protobuf:"varint,12,opt,name=rotational,proto3" json:"rotational,omitempty"` Cdrom bool `protobuf:"varint,13,opt,name=cdrom,proto3" json:"cdrom,omitempty"` + DevPath string `protobuf:"bytes,14,opt,name=dev_path,json=devPath,proto3" json:"dev_path,omitempty"` } func (x *DiskSpec) Reset() { *x = DiskSpec{} if protoimpl.UnsafeEnabled { - mi := &file_resource_definitions_block_block_proto_msgTypes[2] + mi := &file_resource_definitions_block_block_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -330,7 +494,7 @@ func (x *DiskSpec) String() string { func (*DiskSpec) ProtoMessage() {} func (x *DiskSpec) ProtoReflect() protoreflect.Message { - mi := &file_resource_definitions_block_block_proto_msgTypes[2] + mi := &file_resource_definitions_block_block_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -343,7 +507,7 @@ func (x *DiskSpec) ProtoReflect() protoreflect.Message { // Deprecated: Use DiskSpec.ProtoReflect.Descriptor instead. func (*DiskSpec) Descriptor() ([]byte, []int) { - return file_resource_definitions_block_block_proto_rawDescGZIP(), []int{2} + return file_resource_definitions_block_block_proto_rawDescGZIP(), []int{5} } func (x *DiskSpec) GetSize() uint64 { @@ -437,6 +601,261 @@ func (x *DiskSpec) GetCdrom() bool { return false } +func (x *DiskSpec) GetDevPath() string { + if x != nil { + return x.DevPath + } + return "" +} + +// FilesystemSpec is the spec for volume filesystem. +type FilesystemSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type enums.BlockFilesystemType `protobuf:"varint,1,opt,name=type,proto3,enum=talos.resource.definitions.enums.BlockFilesystemType" json:"type,omitempty"` +} + +func (x *FilesystemSpec) Reset() { + *x = FilesystemSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_resource_definitions_block_block_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FilesystemSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FilesystemSpec) ProtoMessage() {} + +func (x *FilesystemSpec) ProtoReflect() protoreflect.Message { + mi := &file_resource_definitions_block_block_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FilesystemSpec.ProtoReflect.Descriptor instead. +func (*FilesystemSpec) Descriptor() ([]byte, []int) { + return file_resource_definitions_block_block_proto_rawDescGZIP(), []int{6} +} + +func (x *FilesystemSpec) GetType() enums.BlockFilesystemType { + if x != nil { + return x.Type + } + return enums.BlockFilesystemType(0) +} + +// LocatorSpec is the spec for volume locator. +type LocatorSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Match *v1alpha1.CheckedExpr `protobuf:"bytes,1,opt,name=match,proto3" json:"match,omitempty"` +} + +func (x *LocatorSpec) Reset() { + *x = LocatorSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_resource_definitions_block_block_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LocatorSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LocatorSpec) ProtoMessage() {} + +func (x *LocatorSpec) ProtoReflect() protoreflect.Message { + mi := &file_resource_definitions_block_block_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LocatorSpec.ProtoReflect.Descriptor instead. +func (*LocatorSpec) Descriptor() ([]byte, []int) { + return file_resource_definitions_block_block_proto_rawDescGZIP(), []int{7} +} + +func (x *LocatorSpec) GetMatch() *v1alpha1.CheckedExpr { + if x != nil { + return x.Match + } + return nil +} + +// PartitionSpec is the spec for volume partitioning. +type PartitionSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MinSize uint64 `protobuf:"varint,1,opt,name=min_size,json=minSize,proto3" json:"min_size,omitempty"` + MaxSize uint64 `protobuf:"varint,2,opt,name=max_size,json=maxSize,proto3" json:"max_size,omitempty"` + Grow bool `protobuf:"varint,3,opt,name=grow,proto3" json:"grow,omitempty"` + Label string `protobuf:"bytes,4,opt,name=label,proto3" json:"label,omitempty"` + TypeUuid string `protobuf:"bytes,5,opt,name=type_uuid,json=typeUuid,proto3" json:"type_uuid,omitempty"` +} + +func (x *PartitionSpec) Reset() { + *x = PartitionSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_resource_definitions_block_block_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PartitionSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PartitionSpec) ProtoMessage() {} + +func (x *PartitionSpec) ProtoReflect() protoreflect.Message { + mi := &file_resource_definitions_block_block_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PartitionSpec.ProtoReflect.Descriptor instead. +func (*PartitionSpec) Descriptor() ([]byte, []int) { + return file_resource_definitions_block_block_proto_rawDescGZIP(), []int{8} +} + +func (x *PartitionSpec) GetMinSize() uint64 { + if x != nil { + return x.MinSize + } + return 0 +} + +func (x *PartitionSpec) GetMaxSize() uint64 { + if x != nil { + return x.MaxSize + } + return 0 +} + +func (x *PartitionSpec) GetGrow() bool { + if x != nil { + return x.Grow + } + return false +} + +func (x *PartitionSpec) GetLabel() string { + if x != nil { + return x.Label + } + return "" +} + +func (x *PartitionSpec) GetTypeUuid() string { + if x != nil { + return x.TypeUuid + } + return "" +} + +// ProvisioningSpec is the spec for volume provisioning. +type ProvisioningSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DiskSelector *DiskSelector `protobuf:"bytes,1,opt,name=disk_selector,json=diskSelector,proto3" json:"disk_selector,omitempty"` + PartitionSpec *PartitionSpec `protobuf:"bytes,2,opt,name=partition_spec,json=partitionSpec,proto3" json:"partition_spec,omitempty"` + Wave int64 `protobuf:"varint,3,opt,name=wave,proto3" json:"wave,omitempty"` + FilesystemSpec *FilesystemSpec `protobuf:"bytes,4,opt,name=filesystem_spec,json=filesystemSpec,proto3" json:"filesystem_spec,omitempty"` +} + +func (x *ProvisioningSpec) Reset() { + *x = ProvisioningSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_resource_definitions_block_block_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ProvisioningSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ProvisioningSpec) ProtoMessage() {} + +func (x *ProvisioningSpec) ProtoReflect() protoreflect.Message { + mi := &file_resource_definitions_block_block_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ProvisioningSpec.ProtoReflect.Descriptor instead. +func (*ProvisioningSpec) Descriptor() ([]byte, []int) { + return file_resource_definitions_block_block_proto_rawDescGZIP(), []int{9} +} + +func (x *ProvisioningSpec) GetDiskSelector() *DiskSelector { + if x != nil { + return x.DiskSelector + } + return nil +} + +func (x *ProvisioningSpec) GetPartitionSpec() *PartitionSpec { + if x != nil { + return x.PartitionSpec + } + return nil +} + +func (x *ProvisioningSpec) GetWave() int64 { + if x != nil { + return x.Wave + } + return 0 +} + +func (x *ProvisioningSpec) GetFilesystemSpec() *FilesystemSpec { + if x != nil { + return x.FilesystemSpec + } + return nil +} + // SystemDiskSpec is the spec for SystemDisks status. type SystemDiskSpec struct { state protoimpl.MessageState @@ -449,7 +868,7 @@ type SystemDiskSpec struct { func (x *SystemDiskSpec) Reset() { *x = SystemDiskSpec{} if protoimpl.UnsafeEnabled { - mi := &file_resource_definitions_block_block_proto_msgTypes[3] + mi := &file_resource_definitions_block_block_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -462,7 +881,7 @@ func (x *SystemDiskSpec) String() string { func (*SystemDiskSpec) ProtoMessage() {} func (x *SystemDiskSpec) ProtoReflect() protoreflect.Message { - mi := &file_resource_definitions_block_block_proto_msgTypes[3] + mi := &file_resource_definitions_block_block_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -475,7 +894,7 @@ func (x *SystemDiskSpec) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemDiskSpec.ProtoReflect.Descriptor instead. func (*SystemDiskSpec) Descriptor() ([]byte, []int) { - return file_resource_definitions_block_block_proto_rawDescGZIP(), []int{3} + return file_resource_definitions_block_block_proto_rawDescGZIP(), []int{10} } func (x *SystemDiskSpec) GetDiskId() string { @@ -485,6 +904,190 @@ func (x *SystemDiskSpec) GetDiskId() string { return "" } +// VolumeConfigSpec is the spec for VolumeConfig resource. +type VolumeConfigSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ParentId string `protobuf:"bytes,1,opt,name=parent_id,json=parentId,proto3" json:"parent_id,omitempty"` + Type enums.BlockVolumeType `protobuf:"varint,2,opt,name=type,proto3,enum=talos.resource.definitions.enums.BlockVolumeType" json:"type,omitempty"` + Provisioning *ProvisioningSpec `protobuf:"bytes,3,opt,name=provisioning,proto3" json:"provisioning,omitempty"` + Locator *LocatorSpec `protobuf:"bytes,4,opt,name=locator,proto3" json:"locator,omitempty"` +} + +func (x *VolumeConfigSpec) Reset() { + *x = VolumeConfigSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_resource_definitions_block_block_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VolumeConfigSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VolumeConfigSpec) ProtoMessage() {} + +func (x *VolumeConfigSpec) ProtoReflect() protoreflect.Message { + mi := &file_resource_definitions_block_block_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VolumeConfigSpec.ProtoReflect.Descriptor instead. +func (*VolumeConfigSpec) Descriptor() ([]byte, []int) { + return file_resource_definitions_block_block_proto_rawDescGZIP(), []int{11} +} + +func (x *VolumeConfigSpec) GetParentId() string { + if x != nil { + return x.ParentId + } + return "" +} + +func (x *VolumeConfigSpec) GetType() enums.BlockVolumeType { + if x != nil { + return x.Type + } + return enums.BlockVolumeType(0) +} + +func (x *VolumeConfigSpec) GetProvisioning() *ProvisioningSpec { + if x != nil { + return x.Provisioning + } + return nil +} + +func (x *VolumeConfigSpec) GetLocator() *LocatorSpec { + if x != nil { + return x.Locator + } + return nil +} + +// VolumeStatusSpec is the spec for VolumeStatus resource. +type VolumeStatusSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Phase enums.BlockVolumePhase `protobuf:"varint,1,opt,name=phase,proto3,enum=talos.resource.definitions.enums.BlockVolumePhase" json:"phase,omitempty"` + Location string `protobuf:"bytes,2,opt,name=location,proto3" json:"location,omitempty"` + ErrorMessage string `protobuf:"bytes,3,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` + Uuid string `protobuf:"bytes,4,opt,name=uuid,proto3" json:"uuid,omitempty"` + PartitionUuid string `protobuf:"bytes,5,opt,name=partition_uuid,json=partitionUuid,proto3" json:"partition_uuid,omitempty"` + PreFailPhase enums.BlockVolumePhase `protobuf:"varint,6,opt,name=pre_fail_phase,json=preFailPhase,proto3,enum=talos.resource.definitions.enums.BlockVolumePhase" json:"pre_fail_phase,omitempty"` + ParentLocation string `protobuf:"bytes,7,opt,name=parent_location,json=parentLocation,proto3" json:"parent_location,omitempty"` + PartitionIndex int64 `protobuf:"varint,8,opt,name=partition_index,json=partitionIndex,proto3" json:"partition_index,omitempty"` + Size uint64 `protobuf:"varint,9,opt,name=size,proto3" json:"size,omitempty"` +} + +func (x *VolumeStatusSpec) Reset() { + *x = VolumeStatusSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_resource_definitions_block_block_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VolumeStatusSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VolumeStatusSpec) ProtoMessage() {} + +func (x *VolumeStatusSpec) ProtoReflect() protoreflect.Message { + mi := &file_resource_definitions_block_block_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VolumeStatusSpec.ProtoReflect.Descriptor instead. +func (*VolumeStatusSpec) Descriptor() ([]byte, []int) { + return file_resource_definitions_block_block_proto_rawDescGZIP(), []int{12} +} + +func (x *VolumeStatusSpec) GetPhase() enums.BlockVolumePhase { + if x != nil { + return x.Phase + } + return enums.BlockVolumePhase(0) +} + +func (x *VolumeStatusSpec) GetLocation() string { + if x != nil { + return x.Location + } + return "" +} + +func (x *VolumeStatusSpec) GetErrorMessage() string { + if x != nil { + return x.ErrorMessage + } + return "" +} + +func (x *VolumeStatusSpec) GetUuid() string { + if x != nil { + return x.Uuid + } + return "" +} + +func (x *VolumeStatusSpec) GetPartitionUuid() string { + if x != nil { + return x.PartitionUuid + } + return "" +} + +func (x *VolumeStatusSpec) GetPreFailPhase() enums.BlockVolumePhase { + if x != nil { + return x.PreFailPhase + } + return enums.BlockVolumePhase(0) +} + +func (x *VolumeStatusSpec) GetParentLocation() string { + if x != nil { + return x.ParentLocation + } + return "" +} + +func (x *VolumeStatusSpec) GetPartitionIndex() int64 { + if x != nil { + return x.PartitionIndex + } + return 0 +} + +func (x *VolumeStatusSpec) GetSize() uint64 { + if x != nil { + return x.Size + } + return 0 +} + var File_resource_definitions_block_block_proto protoreflect.FileDescriptor var file_resource_definitions_block_block_proto_rawDesc = []byte{ @@ -492,7 +1095,12 @@ var file_resource_definitions_block_block_proto_rawDesc = []byte{ 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x20, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0xf7, 0x01, 0x0a, 0x0a, 0x44, + 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x1a, 0x26, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x65, 0x78, 0x70, 0x72, 0x2f, 0x76, 0x31, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x31, 0x2f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x1a, 0x26, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x64, 0x65, 0x66, + 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x2f, 0x65, + 0x6e, 0x75, 0x6d, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf7, 0x01, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6d, 0x61, @@ -508,7 +1116,7 @@ var file_resource_definitions_block_block_proto_rawDesc = []byte{ 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x22, 0x83, 0x04, 0x0a, 0x14, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, + 0x72, 0x65, 0x6e, 0x74, 0x22, 0xc6, 0x04, 0x0a, 0x14, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x65, 0x64, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x73, 0x69, 0x7a, 0x65, @@ -540,37 +1148,137 @@ var file_resource_definitions_block_block_proto_rawDesc = []byte{ 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x10, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x22, 0xe0, 0x02, 0x0a, 0x08, 0x44, - 0x69, 0x73, 0x6b, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x69, - 0x6f, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x69, 0x6f, - 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x73, - 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x73, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, - 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, - 0x79, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, - 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, - 0x1a, 0x0a, 0x08, 0x6d, 0x6f, 0x64, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x6d, 0x6f, 0x64, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x77, - 0x77, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x77, 0x77, 0x69, 0x64, 0x12, - 0x19, 0x0a, 0x08, 0x62, 0x75, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x62, 0x75, 0x73, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x75, - 0x62, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x73, 0x75, 0x62, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x6f, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x72, 0x6f, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x64, 0x72, 0x6f, 0x6d, - 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x63, 0x64, 0x72, 0x6f, 0x6d, 0x22, 0x29, 0x0a, - 0x0e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x44, 0x69, 0x73, 0x6b, 0x53, 0x70, 0x65, 0x63, 0x12, - 0x17, 0x0a, 0x07, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x64, 0x69, 0x73, 0x6b, 0x49, 0x64, 0x42, 0x4a, 0x5a, 0x48, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, 0x6c, 0x61, 0x62, - 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, - 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x62, - 0x6c, 0x6f, 0x63, 0x6b, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x28, 0x09, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x65, + 0x76, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, + 0x76, 0x50, 0x61, 0x74, 0x68, 0x12, 0x26, 0x0a, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, + 0x64, 0x65, 0x76, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x44, 0x65, 0x76, 0x50, 0x61, 0x74, 0x68, 0x22, 0x37, 0x0a, + 0x1b, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, + 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x70, 0x65, 0x63, 0x12, 0x18, 0x0a, 0x07, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x36, 0x0a, 0x1a, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, + 0x65, 0x72, 0x79, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x53, 0x70, 0x65, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4b, + 0x0a, 0x0c, 0x44, 0x69, 0x73, 0x6b, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x3b, + 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, + 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, + 0x45, 0x78, 0x70, 0x72, 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x22, 0xfb, 0x02, 0x0a, 0x08, + 0x44, 0x69, 0x73, 0x6b, 0x53, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x17, 0x0a, 0x07, + 0x69, 0x6f, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x69, + 0x6f, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, + 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x73, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, + 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, + 0x6c, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x6f, 0x64, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6d, 0x6f, 0x64, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x12, 0x0a, 0x04, + 0x77, 0x77, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x77, 0x77, 0x69, 0x64, + 0x12, 0x19, 0x0a, 0x08, 0x62, 0x75, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x62, 0x75, 0x73, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x73, + 0x75, 0x62, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x73, 0x75, 0x62, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x6f, 0x74, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x72, 0x6f, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x64, 0x72, 0x6f, + 0x6d, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x63, 0x64, 0x72, 0x6f, 0x6d, 0x12, 0x19, + 0x0a, 0x08, 0x64, 0x65, 0x76, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x64, 0x65, 0x76, 0x50, 0x61, 0x74, 0x68, 0x22, 0x5b, 0x0a, 0x0e, 0x46, 0x69, 0x6c, + 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x53, 0x70, 0x65, 0x63, 0x12, 0x49, 0x0a, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x35, 0x2e, 0x74, 0x61, 0x6c, 0x6f, + 0x73, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x2e, 0x42, 0x6c, 0x6f, + 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x4a, 0x0a, 0x0b, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, + 0x72, 0x53, 0x70, 0x65, 0x63, 0x12, 0x3b, 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x65, 0x78, 0x70, 0x72, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x45, 0x78, 0x70, 0x72, 0x52, 0x05, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x22, 0x8c, 0x01, 0x0a, 0x0d, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x53, 0x70, 0x65, 0x63, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x69, 0x7a, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x6d, 0x69, 0x6e, 0x53, 0x69, 0x7a, 0x65, 0x12, + 0x19, 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x67, 0x72, + 0x6f, 0x77, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x67, 0x72, 0x6f, 0x77, 0x12, 0x14, + 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, + 0x61, 0x62, 0x65, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x75, 0x75, 0x69, + 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x55, 0x75, 0x69, + 0x64, 0x22, 0xae, 0x02, 0x0a, 0x10, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, + 0x6e, 0x67, 0x53, 0x70, 0x65, 0x63, 0x12, 0x53, 0x0a, 0x0d, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x73, + 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, + 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x64, + 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x2e, 0x44, 0x69, 0x73, 0x6b, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x0c, 0x64, + 0x69, 0x73, 0x6b, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x56, 0x0a, 0x0e, 0x70, + 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x53, 0x70, 0x65, 0x63, 0x52, 0x0d, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, + 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x77, 0x61, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x04, 0x77, 0x61, 0x76, 0x65, 0x12, 0x59, 0x0a, 0x0f, 0x66, 0x69, 0x6c, 0x65, 0x73, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x30, 0x2e, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x53, 0x70, + 0x65, 0x63, 0x52, 0x0e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x53, 0x70, + 0x65, 0x63, 0x22, 0x29, 0x0a, 0x0e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x44, 0x69, 0x73, 0x6b, + 0x53, 0x70, 0x65, 0x63, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x73, 0x6b, 0x49, 0x64, 0x22, 0x97, 0x02, + 0x0a, 0x10, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x70, + 0x65, 0x63, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, + 0x45, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x31, 0x2e, + 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x64, + 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x65, 0x6e, 0x75, 0x6d, 0x73, + 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x56, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, + 0x61, 0x6c, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x64, 0x65, + 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, + 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x53, 0x70, 0x65, 0x63, + 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x47, + 0x0a, 0x07, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2d, 0x2e, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x2e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x62, 0x6c, 0x6f, + 0x63, 0x6b, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x53, 0x70, 0x65, 0x63, 0x52, 0x07, + 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x98, 0x03, 0x0a, 0x10, 0x56, 0x6f, 0x6c, 0x75, + 0x6d, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x53, 0x70, 0x65, 0x63, 0x12, 0x48, 0x0a, 0x05, + 0x70, 0x68, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x74, 0x61, + 0x6c, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x64, 0x65, 0x66, + 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x2e, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x50, 0x68, 0x61, 0x73, 0x65, 0x52, + 0x05, 0x70, 0x68, 0x61, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x70, + 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x75, + 0x69, 0x64, 0x12, 0x58, 0x0a, 0x0e, 0x70, 0x72, 0x65, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x5f, 0x70, + 0x68, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x74, 0x61, 0x6c, + 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x64, 0x65, 0x66, 0x69, + 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x2e, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x50, 0x68, 0x61, 0x73, 0x65, 0x52, 0x0c, + 0x70, 0x72, 0x65, 0x46, 0x61, 0x69, 0x6c, 0x50, 0x68, 0x61, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, + 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x4c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, + 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x12, + 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, + 0x7a, 0x65, 0x42, 0x4a, 0x5a, 0x48, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, + 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x64, 0x65, 0x66, + 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -585,19 +1293,43 @@ func file_resource_definitions_block_block_proto_rawDescGZIP() []byte { return file_resource_definitions_block_block_proto_rawDescData } -var file_resource_definitions_block_block_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_resource_definitions_block_block_proto_msgTypes = make([]protoimpl.MessageInfo, 13) var file_resource_definitions_block_block_proto_goTypes = []any{ - (*DeviceSpec)(nil), // 0: talos.resource.definitions.block.DeviceSpec - (*DiscoveredVolumeSpec)(nil), // 1: talos.resource.definitions.block.DiscoveredVolumeSpec - (*DiskSpec)(nil), // 2: talos.resource.definitions.block.DiskSpec - (*SystemDiskSpec)(nil), // 3: talos.resource.definitions.block.SystemDiskSpec + (*DeviceSpec)(nil), // 0: talos.resource.definitions.block.DeviceSpec + (*DiscoveredVolumeSpec)(nil), // 1: talos.resource.definitions.block.DiscoveredVolumeSpec + (*DiscoveryRefreshRequestSpec)(nil), // 2: talos.resource.definitions.block.DiscoveryRefreshRequestSpec + (*DiscoveryRefreshStatusSpec)(nil), // 3: talos.resource.definitions.block.DiscoveryRefreshStatusSpec + (*DiskSelector)(nil), // 4: talos.resource.definitions.block.DiskSelector + (*DiskSpec)(nil), // 5: talos.resource.definitions.block.DiskSpec + (*FilesystemSpec)(nil), // 6: talos.resource.definitions.block.FilesystemSpec + (*LocatorSpec)(nil), // 7: talos.resource.definitions.block.LocatorSpec + (*PartitionSpec)(nil), // 8: talos.resource.definitions.block.PartitionSpec + (*ProvisioningSpec)(nil), // 9: talos.resource.definitions.block.ProvisioningSpec + (*SystemDiskSpec)(nil), // 10: talos.resource.definitions.block.SystemDiskSpec + (*VolumeConfigSpec)(nil), // 11: talos.resource.definitions.block.VolumeConfigSpec + (*VolumeStatusSpec)(nil), // 12: talos.resource.definitions.block.VolumeStatusSpec + (*v1alpha1.CheckedExpr)(nil), // 13: google.api.expr.v1alpha1.CheckedExpr + (enums.BlockFilesystemType)(0), // 14: talos.resource.definitions.enums.BlockFilesystemType + (enums.BlockVolumeType)(0), // 15: talos.resource.definitions.enums.BlockVolumeType + (enums.BlockVolumePhase)(0), // 16: talos.resource.definitions.enums.BlockVolumePhase } var file_resource_definitions_block_block_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 13, // 0: talos.resource.definitions.block.DiskSelector.match:type_name -> google.api.expr.v1alpha1.CheckedExpr + 14, // 1: talos.resource.definitions.block.FilesystemSpec.type:type_name -> talos.resource.definitions.enums.BlockFilesystemType + 13, // 2: talos.resource.definitions.block.LocatorSpec.match:type_name -> google.api.expr.v1alpha1.CheckedExpr + 4, // 3: talos.resource.definitions.block.ProvisioningSpec.disk_selector:type_name -> talos.resource.definitions.block.DiskSelector + 8, // 4: talos.resource.definitions.block.ProvisioningSpec.partition_spec:type_name -> talos.resource.definitions.block.PartitionSpec + 6, // 5: talos.resource.definitions.block.ProvisioningSpec.filesystem_spec:type_name -> talos.resource.definitions.block.FilesystemSpec + 15, // 6: talos.resource.definitions.block.VolumeConfigSpec.type:type_name -> talos.resource.definitions.enums.BlockVolumeType + 9, // 7: talos.resource.definitions.block.VolumeConfigSpec.provisioning:type_name -> talos.resource.definitions.block.ProvisioningSpec + 7, // 8: talos.resource.definitions.block.VolumeConfigSpec.locator:type_name -> talos.resource.definitions.block.LocatorSpec + 16, // 9: talos.resource.definitions.block.VolumeStatusSpec.phase:type_name -> talos.resource.definitions.enums.BlockVolumePhase + 16, // 10: talos.resource.definitions.block.VolumeStatusSpec.pre_fail_phase:type_name -> talos.resource.definitions.enums.BlockVolumePhase + 11, // [11:11] is the sub-list for method output_type + 11, // [11:11] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name } func init() { file_resource_definitions_block_block_proto_init() } @@ -631,7 +1363,7 @@ func file_resource_definitions_block_block_proto_init() { } } file_resource_definitions_block_block_proto_msgTypes[2].Exporter = func(v any, i int) any { - switch v := v.(*DiskSpec); i { + switch v := v.(*DiscoveryRefreshRequestSpec); i { case 0: return &v.state case 1: @@ -643,6 +1375,90 @@ func file_resource_definitions_block_block_proto_init() { } } file_resource_definitions_block_block_proto_msgTypes[3].Exporter = func(v any, i int) any { + switch v := v.(*DiscoveryRefreshStatusSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_resource_definitions_block_block_proto_msgTypes[4].Exporter = func(v any, i int) any { + switch v := v.(*DiskSelector); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_resource_definitions_block_block_proto_msgTypes[5].Exporter = func(v any, i int) any { + switch v := v.(*DiskSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_resource_definitions_block_block_proto_msgTypes[6].Exporter = func(v any, i int) any { + switch v := v.(*FilesystemSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_resource_definitions_block_block_proto_msgTypes[7].Exporter = func(v any, i int) any { + switch v := v.(*LocatorSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_resource_definitions_block_block_proto_msgTypes[8].Exporter = func(v any, i int) any { + switch v := v.(*PartitionSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_resource_definitions_block_block_proto_msgTypes[9].Exporter = func(v any, i int) any { + switch v := v.(*ProvisioningSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_resource_definitions_block_block_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*SystemDiskSpec); i { case 0: return &v.state @@ -654,6 +1470,30 @@ func file_resource_definitions_block_block_proto_init() { return nil } } + file_resource_definitions_block_block_proto_msgTypes[11].Exporter = func(v any, i int) any { + switch v := v.(*VolumeConfigSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_resource_definitions_block_block_proto_msgTypes[12].Exporter = func(v any, i int) any { + switch v := v.(*VolumeStatusSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -661,7 +1501,7 @@ func file_resource_definitions_block_block_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_resource_definitions_block_block_proto_rawDesc, NumEnums: 0, - NumMessages: 4, + NumMessages: 13, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/machinery/api/resource/definitions/block/block_vtproto.pb.go b/pkg/machinery/api/resource/definitions/block/block_vtproto.pb.go index 2c8d9f31944..d446b27a772 100644 --- a/pkg/machinery/api/resource/definitions/block/block_vtproto.pb.go +++ b/pkg/machinery/api/resource/definitions/block/block_vtproto.pb.go @@ -9,7 +9,11 @@ import ( io "io" protohelpers "github.com/planetscale/vtprotobuf/protohelpers" + v1alpha1 "google.golang.org/genproto/googleapis/api/expr/v1alpha1" + proto "google.golang.org/protobuf/proto" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + + enums "github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/enums" ) const ( @@ -130,6 +134,24 @@ func (m *DiscoveredVolumeSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if len(m.ParentDevPath) > 0 { + i -= len(m.ParentDevPath) + copy(dAtA[i:], m.ParentDevPath) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ParentDevPath))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x92 + } + if len(m.DevPath) > 0 { + i -= len(m.DevPath) + copy(dAtA[i:], m.DevPath) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DevPath))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x8a + } if len(m.Parent) > 0 { i -= len(m.Parent) copy(dAtA[i:], m.Parent) @@ -233,6 +255,137 @@ func (m *DiscoveredVolumeSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *DiscoveryRefreshRequestSpec) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DiscoveryRefreshRequestSpec) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DiscoveryRefreshRequestSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Request != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Request)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *DiscoveryRefreshStatusSpec) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DiscoveryRefreshStatusSpec) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DiscoveryRefreshStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Request != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Request)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *DiskSelector) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DiskSelector) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *DiskSelector) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Match != nil { + if vtmsg, ok := interface{}(m.Match).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Match) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *DiskSpec) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil @@ -263,6 +416,13 @@ func (m *DiskSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } + if len(m.DevPath) > 0 { + i -= len(m.DevPath) + copy(dAtA[i:], m.DevPath) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DevPath))) + i-- + dAtA[i] = 0x72 + } if m.Cdrom { i-- if m.Cdrom { @@ -360,7 +520,7 @@ func (m *DiskSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *SystemDiskSpec) MarshalVT() (dAtA []byte, err error) { +func (m *FilesystemSpec) MarshalVT() (dAtA []byte, err error) { if m == nil { return nil, nil } @@ -373,12 +533,12 @@ func (m *SystemDiskSpec) MarshalVT() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *SystemDiskSpec) MarshalToVT(dAtA []byte) (int, error) { +func (m *FilesystemSpec) MarshalToVT(dAtA []byte) (int, error) { size := m.SizeVT() return m.MarshalToSizedBufferVT(dAtA[:size]) } -func (m *SystemDiskSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { +func (m *FilesystemSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { if m == nil { return 0, nil } @@ -390,122 +550,436 @@ func (m *SystemDiskSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { i -= len(m.unknownFields) copy(dAtA[i:], m.unknownFields) } - if len(m.DiskId) > 0 { - i -= len(m.DiskId) - copy(dAtA[i:], m.DiskId) - i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DiskId))) + if m.Type != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type)) i-- - dAtA[i] = 0xa + dAtA[i] = 0x8 } return len(dAtA) - i, nil } -func (m *DeviceSpec) SizeVT() (n int) { +func (m *LocatorSpec) MarshalVT() (dAtA []byte, err error) { if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Type) - if l > 0 { - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) - } - if m.Major != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Major)) + return nil, nil } - if m.Minor != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Minor)) + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err } - l = len(m.PartitionName) - if l > 0 { - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + return dAtA[:n], nil +} + +func (m *LocatorSpec) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *LocatorSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil } - if m.PartitionNumber != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.PartitionNumber)) + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) } - if m.Generation != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Generation)) + if m.Match != nil { + if vtmsg, ok := interface{}(m.Match).(interface { + MarshalToSizedBufferVT([]byte) (int, error) + }); ok { + size, err := vtmsg.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + } else { + encoded, err := proto.Marshal(m.Match) + if err != nil { + return 0, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(encoded))) + } + i-- + dAtA[i] = 0xa } - l = len(m.DevicePath) - if l > 0 { - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + return len(dAtA) - i, nil +} + +func (m *PartitionSpec) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil } - l = len(m.Parent) - if l > 0 { - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err } - n += len(m.unknownFields) - return n + return dAtA[:n], nil } -func (m *DiscoveredVolumeSpec) SizeVT() (n int) { +func (m *PartitionSpec) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *PartitionSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { if m == nil { - return 0 + return 0, nil } + i := len(dAtA) + _ = i var l int _ = l - if m.Size != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.Size)) + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) } - if m.SectorSize != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.SectorSize)) + if len(m.TypeUuid) > 0 { + i -= len(m.TypeUuid) + copy(dAtA[i:], m.TypeUuid) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.TypeUuid))) + i-- + dAtA[i] = 0x2a } - if m.IoSize != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.IoSize)) + if len(m.Label) > 0 { + i -= len(m.Label) + copy(dAtA[i:], m.Label) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Label))) + i-- + dAtA[i] = 0x22 } - l = len(m.Name) - if l > 0 { - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + if m.Grow { + i-- + if m.Grow { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 } - l = len(m.Uuid) - if l > 0 { - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + if m.MaxSize != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.MaxSize)) + i-- + dAtA[i] = 0x10 } - l = len(m.Label) - if l > 0 { - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + if m.MinSize != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.MinSize)) + i-- + dAtA[i] = 0x8 } - if m.BlockSize != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.BlockSize)) + return len(dAtA) - i, nil +} + +func (m *ProvisioningSpec) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil } - if m.FilesystemBlockSize != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.FilesystemBlockSize)) + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err } - if m.ProbedSize != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.ProbedSize)) + return dAtA[:n], nil +} + +func (m *ProvisioningSpec) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *ProvisioningSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil } - l = len(m.PartitionUuid) - if l > 0 { - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) } - l = len(m.PartitionType) - if l > 0 { - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + if m.FilesystemSpec != nil { + size, err := m.FilesystemSpec.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x22 } - l = len(m.PartitionLabel) - if l > 0 { - n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + if m.Wave != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Wave)) + i-- + dAtA[i] = 0x18 + } + if m.PartitionSpec != nil { + size, err := m.PartitionSpec.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x12 + } + if m.DiskSelector != nil { + size, err := m.DiskSelector.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *SystemDiskSpec) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SystemDiskSpec) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *SystemDiskSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if len(m.DiskId) > 0 { + i -= len(m.DiskId) + copy(dAtA[i:], m.DiskId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.DiskId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *VolumeConfigSpec) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *VolumeConfigSpec) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *VolumeConfigSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Locator != nil { + size, err := m.Locator.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x22 + } + if m.Provisioning != nil { + size, err := m.Provisioning.MarshalToSizedBufferVT(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = protohelpers.EncodeVarint(dAtA, i, uint64(size)) + i-- + dAtA[i] = 0x1a + } + if m.Type != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Type)) + i-- + dAtA[i] = 0x10 + } + if len(m.ParentId) > 0 { + i -= len(m.ParentId) + copy(dAtA[i:], m.ParentId) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ParentId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *VolumeStatusSpec) MarshalVT() (dAtA []byte, err error) { + if m == nil { + return nil, nil + } + size := m.SizeVT() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBufferVT(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *VolumeStatusSpec) MarshalToVT(dAtA []byte) (int, error) { + size := m.SizeVT() + return m.MarshalToSizedBufferVT(dAtA[:size]) +} + +func (m *VolumeStatusSpec) MarshalToSizedBufferVT(dAtA []byte) (int, error) { + if m == nil { + return 0, nil + } + i := len(dAtA) + _ = i + var l int + _ = l + if m.unknownFields != nil { + i -= len(m.unknownFields) + copy(dAtA[i:], m.unknownFields) + } + if m.Size != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Size)) + i-- + dAtA[i] = 0x48 } if m.PartitionIndex != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.PartitionIndex)) + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.PartitionIndex)) + i-- + dAtA[i] = 0x40 + } + if len(m.ParentLocation) > 0 { + i -= len(m.ParentLocation) + copy(dAtA[i:], m.ParentLocation) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ParentLocation))) + i-- + dAtA[i] = 0x3a + } + if m.PreFailPhase != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.PreFailPhase)) + i-- + dAtA[i] = 0x30 + } + if len(m.PartitionUuid) > 0 { + i -= len(m.PartitionUuid) + copy(dAtA[i:], m.PartitionUuid) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.PartitionUuid))) + i-- + dAtA[i] = 0x2a + } + if len(m.Uuid) > 0 { + i -= len(m.Uuid) + copy(dAtA[i:], m.Uuid) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Uuid))) + i-- + dAtA[i] = 0x22 + } + if len(m.ErrorMessage) > 0 { + i -= len(m.ErrorMessage) + copy(dAtA[i:], m.ErrorMessage) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.ErrorMessage))) + i-- + dAtA[i] = 0x1a + } + if len(m.Location) > 0 { + i -= len(m.Location) + copy(dAtA[i:], m.Location) + i = protohelpers.EncodeVarint(dAtA, i, uint64(len(m.Location))) + i-- + dAtA[i] = 0x12 + } + if m.Phase != 0 { + i = protohelpers.EncodeVarint(dAtA, i, uint64(m.Phase)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *DeviceSpec) SizeVT() (n int) { + if m == nil { + return 0 } + var l int + _ = l l = len(m.Type) if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } + if m.Major != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Major)) + } + if m.Minor != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Minor)) + } + l = len(m.PartitionName) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.PartitionNumber != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.PartitionNumber)) + } + if m.Generation != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Generation)) + } l = len(m.DevicePath) if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } l = len(m.Parent) if l > 0 { - n += 2 + l + protohelpers.SizeOfVarint(uint64(l)) + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } n += len(m.unknownFields) return n } -func (m *DiskSpec) SizeVT() (n int) { +func (m *DiscoveredVolumeSpec) SizeVT() (n int) { if m == nil { return 0 } @@ -514,48 +988,258 @@ func (m *DiskSpec) SizeVT() (n int) { if m.Size != 0 { n += 1 + protohelpers.SizeOfVarint(uint64(m.Size)) } - if m.IoSize != 0 { - n += 1 + protohelpers.SizeOfVarint(uint64(m.IoSize)) - } if m.SectorSize != 0 { n += 1 + protohelpers.SizeOfVarint(uint64(m.SectorSize)) } - if m.Readonly { - n += 2 + if m.IoSize != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.IoSize)) } - l = len(m.Model) + l = len(m.Name) if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } - l = len(m.Serial) + l = len(m.Uuid) if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } - l = len(m.Modalias) + l = len(m.Label) if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } - l = len(m.Wwid) + if m.BlockSize != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.BlockSize)) + } + if m.FilesystemBlockSize != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.FilesystemBlockSize)) + } + if m.ProbedSize != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.ProbedSize)) + } + l = len(m.PartitionUuid) if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } - l = len(m.BusPath) + l = len(m.PartitionType) if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } - l = len(m.SubSystem) + l = len(m.PartitionLabel) if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } - l = len(m.Transport) + if m.PartitionIndex != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.PartitionIndex)) + } + l = len(m.Type) if l > 0 { n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } - if m.Rotational { - n += 2 + l = len(m.DevicePath) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } - if m.Cdrom { - n += 2 + l = len(m.Parent) + if l > 0 { + n += 2 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.DevPath) + if l > 0 { + n += 2 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.ParentDevPath) + if l > 0 { + n += 2 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *DiscoveryRefreshRequestSpec) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Request != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Request)) + } + n += len(m.unknownFields) + return n +} + +func (m *DiscoveryRefreshStatusSpec) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Request != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Request)) + } + n += len(m.unknownFields) + return n +} + +func (m *DiskSelector) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Match != nil { + if size, ok := interface{}(m.Match).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(m.Match) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *DiskSpec) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Size != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Size)) + } + if m.IoSize != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.IoSize)) + } + if m.SectorSize != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.SectorSize)) + } + if m.Readonly { + n += 2 + } + l = len(m.Model) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Serial) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Modalias) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Wwid) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.BusPath) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.SubSystem) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Transport) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Rotational { + n += 2 + } + if m.Cdrom { + n += 2 + } + l = len(m.DevPath) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *FilesystemSpec) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Type != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Type)) + } + n += len(m.unknownFields) + return n +} + +func (m *LocatorSpec) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Match != nil { + if size, ok := interface{}(m.Match).(interface { + SizeVT() int + }); ok { + l = size.SizeVT() + } else { + l = proto.Size(m.Match) + } + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *PartitionSpec) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.MinSize != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.MinSize)) + } + if m.MaxSize != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.MaxSize)) + } + if m.Grow { + n += 2 + } + l = len(m.Label) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.TypeUuid) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *ProvisioningSpec) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.DiskSelector != nil { + l = m.DiskSelector.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.PartitionSpec != nil { + l = m.PartitionSpec.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Wave != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Wave)) + } + if m.FilesystemSpec != nil { + l = m.FilesystemSpec.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) } n += len(m.unknownFields) return n @@ -575,6 +1259,73 @@ func (m *SystemDiskSpec) SizeVT() (n int) { return n } +func (m *VolumeConfigSpec) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ParentId) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Type != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Type)) + } + if m.Provisioning != nil { + l = m.Provisioning.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.Locator != nil { + l = m.Locator.SizeVT() + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + n += len(m.unknownFields) + return n +} + +func (m *VolumeStatusSpec) SizeVT() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Phase != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Phase)) + } + l = len(m.Location) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.ErrorMessage) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.Uuid) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + l = len(m.PartitionUuid) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.PreFailPhase != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.PreFailPhase)) + } + l = len(m.ParentLocation) + if l > 0 { + n += 1 + l + protohelpers.SizeOfVarint(uint64(l)) + } + if m.PartitionIndex != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.PartitionIndex)) + } + if m.Size != 0 { + n += 1 + protohelpers.SizeOfVarint(uint64(m.Size)) + } + n += len(m.unknownFields) + return n +} + func (m *DeviceSpec) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -606,7 +1357,1302 @@ func (m *DeviceSpec) UnmarshalVT(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Type = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Major", wireType) + } + m.Major = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Major |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Minor", wireType) + } + m.Minor = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Minor |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PartitionName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PartitionName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PartitionNumber", wireType) + } + m.PartitionNumber = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PartitionNumber |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Generation", wireType) + } + m.Generation = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Generation |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DevicePath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DevicePath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Parent", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Parent = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DiscoveredVolumeSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DiscoveredVolumeSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Size", wireType) + } + m.Size = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Size |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SectorSize", wireType) + } + m.SectorSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SectorSize |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IoSize", wireType) + } + m.IoSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.IoSize |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Uuid", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Uuid = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Label", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Label = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockSize", wireType) + } + m.BlockSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BlockSize |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FilesystemBlockSize", wireType) + } + m.FilesystemBlockSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.FilesystemBlockSize |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ProbedSize", wireType) + } + m.ProbedSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ProbedSize |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PartitionUuid", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PartitionUuid = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PartitionType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PartitionType = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PartitionLabel", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PartitionLabel = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 13: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PartitionIndex", wireType) + } + m.PartitionIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PartitionIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Type = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 15: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DevicePath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DevicePath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 16: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Parent", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Parent = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 17: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DevPath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DevPath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 18: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ParentDevPath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ParentDevPath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DiscoveryRefreshRequestSpec) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DiscoveryRefreshRequestSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DiscoveryRefreshRequestSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Request", wireType) + } + m.Request = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Request |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DiscoveryRefreshStatusSpec) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DiscoveryRefreshStatusSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DiscoveryRefreshStatusSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Request", wireType) + } + m.Request = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Request |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DiskSelector) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DiskSelector: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DiskSelector: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Match", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Match == nil { + m.Match = &v1alpha1.CheckedExpr{} + } + if unmarshal, ok := interface{}(m.Match).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Match); err != nil { + return err + } + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DiskSpec) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DiskSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DiskSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Size", wireType) + } + m.Size = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Size |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IoSize", wireType) + } + m.IoSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.IoSize |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SectorSize", wireType) + } + m.SectorSize = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SectorSize |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Readonly", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Readonly = bool(v != 0) + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Model", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Model = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Serial", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Serial = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Modalias", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Modalias = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Wwid", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Wwid = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BusPath", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BusPath = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SubSystem", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SubSystem = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Transport", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -634,13 +2680,13 @@ func (m *DeviceSpec) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Type = string(dAtA[iNdEx:postIndex]) + m.Transport = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: + case 12: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Major", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Rotational", wireType) } - m.Major = 0 + var v int for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -650,16 +2696,17 @@ func (m *DeviceSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Major |= int64(b&0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } } - case 3: + m.Rotational = bool(v != 0) + case 13: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Minor", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Cdrom", wireType) } - m.Minor = 0 + var v int for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -669,14 +2716,15 @@ func (m *DeviceSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Minor |= int64(b&0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } } - case 4: + m.Cdrom = bool(v != 0) + case 14: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PartitionName", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field DevPath", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -704,51 +2752,64 @@ func (m *DeviceSpec) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.PartitionName = string(dAtA[iNdEx:postIndex]) + m.DevPath = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PartitionNumber", wireType) + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err } - m.PartitionNumber = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.PartitionNumber |= int64(b&0x7F) << shift - if b < 0x80 { - break - } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength } - case 6: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Generation", wireType) + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF } - m.Generation = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Generation |= int64(b&0x7F) << shift - if b < 0x80 { - break - } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *FilesystemSpec) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow } - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DevicePath", wireType) + if iNdEx >= l { + return io.ErrUnexpectedEOF } - var stringLen uint64 + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: FilesystemSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FilesystemSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + m.Type = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -758,29 +2819,67 @@ func (m *DeviceSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.Type |= enums.BlockFilesystemType(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return protohelpers.ErrInvalidLength + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err } - postIndex := iNdEx + intStringLen - if postIndex < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return protohelpers.ErrInvalidLength } - if postIndex > l { + if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } - m.DevicePath = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 8: + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *LocatorSpec) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: LocatorSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LocatorSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Parent", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Match", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -790,23 +2889,35 @@ func (m *DeviceSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return protohelpers.ErrInvalidLength } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return protohelpers.ErrInvalidLength } if postIndex > l { return io.ErrUnexpectedEOF } - m.Parent = string(dAtA[iNdEx:postIndex]) + if m.Match == nil { + m.Match = &v1alpha1.CheckedExpr{} + } + if unmarshal, ok := interface{}(m.Match).(interface { + UnmarshalVT([]byte) error + }); ok { + if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } + } else { + if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Match); err != nil { + return err + } + } iNdEx = postIndex default: iNdEx = preIndex @@ -830,7 +2941,7 @@ func (m *DeviceSpec) UnmarshalVT(dAtA []byte) error { } return nil } -func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { +func (m *PartitionSpec) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -853,17 +2964,17 @@ func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: DiscoveredVolumeSpec: wiretype end group for non-group") + return fmt.Errorf("proto: PartitionSpec: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: DiscoveredVolumeSpec: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: PartitionSpec: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Size", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MinSize", wireType) } - m.Size = 0 + m.MinSize = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -873,16 +2984,16 @@ func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Size |= uint64(b&0x7F) << shift + m.MinSize |= uint64(b&0x7F) << shift if b < 0x80 { break } } case 2: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field SectorSize", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MaxSize", wireType) } - m.SectorSize = 0 + m.MaxSize = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -892,16 +3003,16 @@ func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.SectorSize |= uint64(b&0x7F) << shift + m.MaxSize |= uint64(b&0x7F) << shift if b < 0x80 { break } } case 3: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field IoSize", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Grow", wireType) } - m.IoSize = 0 + var v int for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -911,14 +3022,47 @@ func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.IoSize |= uint64(b&0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } } + m.Grow = bool(v != 0) case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Label", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protohelpers.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protohelpers.ErrInvalidLength + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Label = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TypeUuid", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -943,16 +3087,67 @@ func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { if postIndex < 0 { return protohelpers.ErrInvalidLength } - if postIndex > l { + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TypeUuid = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ProvisioningSpec) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { return io.ErrUnexpectedEOF } - m.Name = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 5: + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ProvisioningSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ProvisioningSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Uuid", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field DiskSelector", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -962,29 +3157,33 @@ func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return protohelpers.ErrInvalidLength } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return protohelpers.ErrInvalidLength } if postIndex > l { return io.ErrUnexpectedEOF } - m.Uuid = string(dAtA[iNdEx:postIndex]) + if m.DiskSelector == nil { + m.DiskSelector = &DiskSelector{} + } + if err := m.DiskSelector.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 6: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Label", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field PartitionSpec", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -994,67 +3193,33 @@ func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return protohelpers.ErrInvalidLength } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return protohelpers.ErrInvalidLength } if postIndex > l { return io.ErrUnexpectedEOF } - m.Label = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 7: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field BlockSize", wireType) - } - m.BlockSize = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.BlockSize |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 8: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field FilesystemBlockSize", wireType) + if m.PartitionSpec == nil { + m.PartitionSpec = &PartitionSpec{} } - m.FilesystemBlockSize = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.FilesystemBlockSize |= uint32(b&0x7F) << shift - if b < 0x80 { - break - } + if err := m.PartitionSpec.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err } - case 9: + iNdEx = postIndex + case 3: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ProbedSize", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Wave", wireType) } - m.ProbedSize = 0 + m.Wave = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -1064,16 +3229,16 @@ func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.ProbedSize |= uint64(b&0x7F) << shift + m.Wave |= int64(b&0x7F) << shift if b < 0x80 { break } } - case 10: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PartitionUuid", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field FilesystemSpec", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -1083,27 +3248,82 @@ func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return protohelpers.ErrInvalidLength } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return protohelpers.ErrInvalidLength } if postIndex > l { return io.ErrUnexpectedEOF } - m.PartitionUuid = string(dAtA[iNdEx:postIndex]) + if m.FilesystemSpec == nil { + m.FilesystemSpec = &FilesystemSpec{} + } + if err := m.FilesystemSpec.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 11: + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SystemDiskSpec) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SystemDiskSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SystemDiskSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PartitionType", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field DiskId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1131,11 +3351,62 @@ func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.PartitionType = string(dAtA[iNdEx:postIndex]) + m.DiskId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 12: + default: + iNdEx = preIndex + skippy, err := protohelpers.Skip(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protohelpers.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *VolumeConfigSpec) UnmarshalVT(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protohelpers.ErrIntOverflow + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: VolumeConfigSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: VolumeConfigSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PartitionLabel", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ParentId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1163,32 +3434,13 @@ func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.PartitionLabel = string(dAtA[iNdEx:postIndex]) + m.ParentId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 13: + case 2: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field PartitionIndex", wireType) - } - m.PartitionIndex = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.PartitionIndex |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 14: - if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) } - var stringLen uint64 + m.Type = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -1198,29 +3450,16 @@ func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.Type |= enums.BlockVolumeType(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Type = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 15: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DevicePath", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Provisioning", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -1230,29 +3469,33 @@ func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } - } - intStringLen := int(stringLen) - if intStringLen < 0 { + } + if msglen < 0 { return protohelpers.ErrInvalidLength } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return protohelpers.ErrInvalidLength } if postIndex > l { return io.ErrUnexpectedEOF } - m.DevicePath = string(dAtA[iNdEx:postIndex]) + if m.Provisioning == nil { + m.Provisioning = &ProvisioningSpec{} + } + if err := m.Provisioning.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 16: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Parent", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Locator", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -1262,23 +3505,27 @@ func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return protohelpers.ErrInvalidLength } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return protohelpers.ErrInvalidLength } if postIndex > l { return io.ErrUnexpectedEOF } - m.Parent = string(dAtA[iNdEx:postIndex]) + if m.Locator == nil { + m.Locator = &LocatorSpec{} + } + if err := m.Locator.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex default: iNdEx = preIndex @@ -1302,7 +3549,7 @@ func (m *DiscoveredVolumeSpec) UnmarshalVT(dAtA []byte) error { } return nil } -func (m *DiskSpec) UnmarshalVT(dAtA []byte) error { +func (m *VolumeStatusSpec) UnmarshalVT(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1325,17 +3572,17 @@ func (m *DiskSpec) UnmarshalVT(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: DiskSpec: wiretype end group for non-group") + return fmt.Errorf("proto: VolumeStatusSpec: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: DiskSpec: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: VolumeStatusSpec: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Size", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Phase", wireType) } - m.Size = 0 + m.Phase = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -1345,104 +3592,14 @@ func (m *DiskSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Size |= uint64(b&0x7F) << shift + m.Phase |= enums.BlockVolumePhase(b&0x7F) << shift if b < 0x80 { break } } case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field IoSize", wireType) - } - m.IoSize = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.IoSize |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field SectorSize", wireType) - } - m.SectorSize = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.SectorSize |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Readonly", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Readonly = bool(v != 0) - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Model", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Model = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Serial", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Location", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1470,11 +3627,11 @@ func (m *DiskSpec) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Serial = string(dAtA[iNdEx:postIndex]) + m.Location = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 7: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Modalias", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ErrorMessage", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1502,11 +3659,11 @@ func (m *DiskSpec) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Modalias = string(dAtA[iNdEx:postIndex]) + m.ErrorMessage = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 8: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Wwid", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Uuid", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1534,11 +3691,11 @@ func (m *DiskSpec) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Wwid = string(dAtA[iNdEx:postIndex]) + m.Uuid = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 9: + case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BusPath", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field PartitionUuid", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1566,13 +3723,13 @@ func (m *DiskSpec) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.BusPath = string(dAtA[iNdEx:postIndex]) + m.PartitionUuid = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 10: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SubSystem", wireType) + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PreFailPhase", wireType) } - var stringLen uint64 + m.PreFailPhase = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -1582,27 +3739,14 @@ func (m *DiskSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.PreFailPhase |= enums.BlockVolumePhase(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.SubSystem = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 11: + case 7: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Transport", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ParentLocation", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1630,13 +3774,13 @@ func (m *DiskSpec) UnmarshalVT(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Transport = string(dAtA[iNdEx:postIndex]) + m.ParentLocation = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 12: + case 8: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Rotational", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field PartitionIndex", wireType) } - var v int + m.PartitionIndex = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -1646,88 +3790,16 @@ func (m *DiskSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= int(b&0x7F) << shift + m.PartitionIndex |= int64(b&0x7F) << shift if b < 0x80 { break } } - m.Rotational = bool(v != 0) - case 13: + case 9: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Cdrom", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Cdrom = bool(v != 0) - default: - iNdEx = preIndex - skippy, err := protohelpers.Skip(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return protohelpers.ErrInvalidLength - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *SystemDiskSpec) UnmarshalVT(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return protohelpers.ErrIntOverflow - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: SystemDiskSpec: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: SystemDiskSpec: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DiskId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Size", wireType) } - var stringLen uint64 + m.Size = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protohelpers.ErrIntOverflow @@ -1737,24 +3809,11 @@ func (m *SystemDiskSpec) UnmarshalVT(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.Size |= uint64(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return protohelpers.ErrInvalidLength - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return protohelpers.ErrInvalidLength - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.DiskId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex default: iNdEx = preIndex skippy, err := protohelpers.Skip(dAtA[iNdEx:]) diff --git a/pkg/machinery/api/resource/definitions/enums/enums.pb.go b/pkg/machinery/api/resource/definitions/enums/enums.pb.go index 5cd93861d2d..3293ad15ea9 100644 --- a/pkg/machinery/api/resource/definitions/enums/enums.pb.go +++ b/pkg/machinery/api/resource/definitions/enums/enums.pb.go @@ -1831,6 +1831,162 @@ func (NethelpersVLANProtocol) EnumDescriptor() ([]byte, []int) { return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{26} } +// BlockFilesystemType describes filesystem type. +type BlockFilesystemType int32 + +const ( + BlockFilesystemType_FILESYSTEM_TYPE_NONE BlockFilesystemType = 0 + BlockFilesystemType_FILESYSTEM_TYPE_XFS BlockFilesystemType = 1 +) + +// Enum value maps for BlockFilesystemType. +var ( + BlockFilesystemType_name = map[int32]string{ + 0: "FILESYSTEM_TYPE_NONE", + 1: "FILESYSTEM_TYPE_XFS", + } + BlockFilesystemType_value = map[string]int32{ + "FILESYSTEM_TYPE_NONE": 0, + "FILESYSTEM_TYPE_XFS": 1, + } +) + +func (x BlockFilesystemType) Enum() *BlockFilesystemType { + p := new(BlockFilesystemType) + *p = x + return p +} + +func (x BlockFilesystemType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (BlockFilesystemType) Descriptor() protoreflect.EnumDescriptor { + return file_resource_definitions_enums_enums_proto_enumTypes[27].Descriptor() +} + +func (BlockFilesystemType) Type() protoreflect.EnumType { + return &file_resource_definitions_enums_enums_proto_enumTypes[27] +} + +func (x BlockFilesystemType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use BlockFilesystemType.Descriptor instead. +func (BlockFilesystemType) EnumDescriptor() ([]byte, []int) { + return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{27} +} + +// BlockVolumePhase describes volume phase. +type BlockVolumePhase int32 + +const ( + BlockVolumePhase_VOLUME_PHASE_WAITING BlockVolumePhase = 0 + BlockVolumePhase_VOLUME_PHASE_READY BlockVolumePhase = 1 + BlockVolumePhase_VOLUME_PHASE_FAILED BlockVolumePhase = 2 + BlockVolumePhase_VOLUME_PHASE_MISSING BlockVolumePhase = 3 + BlockVolumePhase_VOLUME_PHASE_LOCATED BlockVolumePhase = 4 + BlockVolumePhase_VOLUME_PHASE_PROVISIONED BlockVolumePhase = 5 +) + +// Enum value maps for BlockVolumePhase. +var ( + BlockVolumePhase_name = map[int32]string{ + 0: "VOLUME_PHASE_WAITING", + 1: "VOLUME_PHASE_READY", + 2: "VOLUME_PHASE_FAILED", + 3: "VOLUME_PHASE_MISSING", + 4: "VOLUME_PHASE_LOCATED", + 5: "VOLUME_PHASE_PROVISIONED", + } + BlockVolumePhase_value = map[string]int32{ + "VOLUME_PHASE_WAITING": 0, + "VOLUME_PHASE_READY": 1, + "VOLUME_PHASE_FAILED": 2, + "VOLUME_PHASE_MISSING": 3, + "VOLUME_PHASE_LOCATED": 4, + "VOLUME_PHASE_PROVISIONED": 5, + } +) + +func (x BlockVolumePhase) Enum() *BlockVolumePhase { + p := new(BlockVolumePhase) + *p = x + return p +} + +func (x BlockVolumePhase) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (BlockVolumePhase) Descriptor() protoreflect.EnumDescriptor { + return file_resource_definitions_enums_enums_proto_enumTypes[28].Descriptor() +} + +func (BlockVolumePhase) Type() protoreflect.EnumType { + return &file_resource_definitions_enums_enums_proto_enumTypes[28] +} + +func (x BlockVolumePhase) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use BlockVolumePhase.Descriptor instead. +func (BlockVolumePhase) EnumDescriptor() ([]byte, []int) { + return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{28} +} + +// BlockVolumeType describes volume type. +type BlockVolumeType int32 + +const ( + BlockVolumeType_VOLUME_TYPE_PARTITION BlockVolumeType = 0 + BlockVolumeType_VOLUME_TYPE_DISK BlockVolumeType = 1 + BlockVolumeType_VOLUME_TYPE_TMPFS BlockVolumeType = 2 +) + +// Enum value maps for BlockVolumeType. +var ( + BlockVolumeType_name = map[int32]string{ + 0: "VOLUME_TYPE_PARTITION", + 1: "VOLUME_TYPE_DISK", + 2: "VOLUME_TYPE_TMPFS", + } + BlockVolumeType_value = map[string]int32{ + "VOLUME_TYPE_PARTITION": 0, + "VOLUME_TYPE_DISK": 1, + "VOLUME_TYPE_TMPFS": 2, + } +) + +func (x BlockVolumeType) Enum() *BlockVolumeType { + p := new(BlockVolumeType) + *p = x + return p +} + +func (x BlockVolumeType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (BlockVolumeType) Descriptor() protoreflect.EnumDescriptor { + return file_resource_definitions_enums_enums_proto_enumTypes[29].Descriptor() +} + +func (BlockVolumeType) Type() protoreflect.EnumType { + return &file_resource_definitions_enums_enums_proto_enumTypes[29] +} + +func (x BlockVolumeType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use BlockVolumeType.Descriptor instead. +func (BlockVolumeType) EnumDescriptor() ([]byte, []int) { + return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{29} +} + // KubespanPeerState is KubeSpan peer current state. type KubespanPeerState int32 @@ -1865,11 +2021,11 @@ func (x KubespanPeerState) String() string { } func (KubespanPeerState) Descriptor() protoreflect.EnumDescriptor { - return file_resource_definitions_enums_enums_proto_enumTypes[27].Descriptor() + return file_resource_definitions_enums_enums_proto_enumTypes[30].Descriptor() } func (KubespanPeerState) Type() protoreflect.EnumType { - return &file_resource_definitions_enums_enums_proto_enumTypes[27] + return &file_resource_definitions_enums_enums_proto_enumTypes[30] } func (x KubespanPeerState) Number() protoreflect.EnumNumber { @@ -1878,7 +2034,7 @@ func (x KubespanPeerState) Number() protoreflect.EnumNumber { // Deprecated: Use KubespanPeerState.Descriptor instead. func (KubespanPeerState) EnumDescriptor() ([]byte, []int) { - return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{27} + return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{30} } // NetworkConfigLayer describes network configuration layers, with lowest priority first. @@ -1921,11 +2077,11 @@ func (x NetworkConfigLayer) String() string { } func (NetworkConfigLayer) Descriptor() protoreflect.EnumDescriptor { - return file_resource_definitions_enums_enums_proto_enumTypes[28].Descriptor() + return file_resource_definitions_enums_enums_proto_enumTypes[31].Descriptor() } func (NetworkConfigLayer) Type() protoreflect.EnumType { - return &file_resource_definitions_enums_enums_proto_enumTypes[28] + return &file_resource_definitions_enums_enums_proto_enumTypes[31] } func (x NetworkConfigLayer) Number() protoreflect.EnumNumber { @@ -1934,7 +2090,7 @@ func (x NetworkConfigLayer) Number() protoreflect.EnumNumber { // Deprecated: Use NetworkConfigLayer.Descriptor instead. func (NetworkConfigLayer) EnumDescriptor() ([]byte, []int) { - return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{28} + return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{31} } // NetworkOperator enumerates Talos network operators. @@ -1971,11 +2127,11 @@ func (x NetworkOperator) String() string { } func (NetworkOperator) Descriptor() protoreflect.EnumDescriptor { - return file_resource_definitions_enums_enums_proto_enumTypes[29].Descriptor() + return file_resource_definitions_enums_enums_proto_enumTypes[32].Descriptor() } func (NetworkOperator) Type() protoreflect.EnumType { - return &file_resource_definitions_enums_enums_proto_enumTypes[29] + return &file_resource_definitions_enums_enums_proto_enumTypes[32] } func (x NetworkOperator) Number() protoreflect.EnumNumber { @@ -1984,7 +2140,7 @@ func (x NetworkOperator) Number() protoreflect.EnumNumber { // Deprecated: Use NetworkOperator.Descriptor instead. func (NetworkOperator) EnumDescriptor() ([]byte, []int) { - return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{29} + return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{32} } // RuntimeMachineStage describes the stage of the machine boot/run process. @@ -2039,11 +2195,11 @@ func (x RuntimeMachineStage) String() string { } func (RuntimeMachineStage) Descriptor() protoreflect.EnumDescriptor { - return file_resource_definitions_enums_enums_proto_enumTypes[30].Descriptor() + return file_resource_definitions_enums_enums_proto_enumTypes[33].Descriptor() } func (RuntimeMachineStage) Type() protoreflect.EnumType { - return &file_resource_definitions_enums_enums_proto_enumTypes[30] + return &file_resource_definitions_enums_enums_proto_enumTypes[33] } func (x RuntimeMachineStage) Number() protoreflect.EnumNumber { @@ -2052,7 +2208,7 @@ func (x RuntimeMachineStage) Number() protoreflect.EnumNumber { // Deprecated: Use RuntimeMachineStage.Descriptor instead. func (RuntimeMachineStage) EnumDescriptor() ([]byte, []int) { - return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{30} + return file_resource_definitions_enums_enums_proto_rawDescGZIP(), []int{33} } var File_resource_definitions_enums_enums_proto protoreflect.FileDescriptor @@ -2419,49 +2575,71 @@ var file_resource_definitions_enums_enums_proto_rawDesc = []byte{ 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x13, 0x56, 0x4c, 0x41, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x38, 0x30, 0x32, 0x31, 0x5f, 0x51, 0x10, 0x80, 0x82, 0x02, 0x12, 0x1a, 0x0a, 0x14, 0x56, 0x4c, 0x41, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, - 0x4c, 0x38, 0x30, 0x32, 0x31, 0x5f, 0x41, 0x44, 0x10, 0xa8, 0x91, 0x02, 0x2a, 0x53, 0x0a, 0x11, - 0x4b, 0x75, 0x62, 0x65, 0x73, 0x70, 0x61, 0x6e, 0x50, 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, - 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x45, 0x45, - 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x50, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, - 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, - 0x02, 0x2a, 0x88, 0x01, 0x0a, 0x12, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4f, 0x4e, 0x46, - 0x49, 0x47, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, - 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x43, 0x4d, 0x44, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x01, - 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x50, 0x4c, 0x41, 0x54, 0x46, - 0x4f, 0x52, 0x4d, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, - 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x20, 0x0a, 0x1c, 0x43, 0x4f, - 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x43, 0x4f, 0x4e, - 0x46, 0x49, 0x47, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x2a, 0x4b, 0x0a, 0x0f, - 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, - 0x12, 0x0a, 0x0e, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x44, 0x48, 0x43, 0x50, - 0x34, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, - 0x44, 0x48, 0x43, 0x50, 0x36, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4f, 0x50, 0x45, 0x52, 0x41, - 0x54, 0x4f, 0x52, 0x5f, 0x56, 0x49, 0x50, 0x10, 0x02, 0x2a, 0x9b, 0x02, 0x0a, 0x13, 0x52, 0x75, - 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x53, 0x74, 0x61, 0x67, - 0x65, 0x12, 0x19, 0x0a, 0x15, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, - 0x47, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, - 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x42, 0x4f, - 0x4f, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x4d, 0x41, 0x43, 0x48, 0x49, - 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, - 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x1d, 0x0a, 0x19, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, - 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x4d, 0x41, 0x49, 0x4e, 0x54, 0x45, 0x4e, 0x41, 0x4e, - 0x43, 0x45, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, - 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, - 0x1b, 0x0a, 0x17, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, - 0x5f, 0x52, 0x45, 0x42, 0x4f, 0x4f, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x05, 0x12, 0x1f, 0x0a, 0x1b, - 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x53, 0x48, - 0x55, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x06, 0x12, 0x1b, 0x0a, - 0x17, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x52, - 0x45, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x07, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x41, - 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x55, 0x50, 0x47, 0x52, - 0x41, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x08, 0x42, 0x4a, 0x5a, 0x48, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x64, 0x65, 0x72, 0x6f, 0x6c, 0x61, 0x62, 0x73, - 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, - 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x65, 0x6e, - 0x75, 0x6d, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x4c, 0x38, 0x30, 0x32, 0x31, 0x5f, 0x41, 0x44, 0x10, 0xa8, 0x91, 0x02, 0x2a, 0x48, 0x0a, 0x13, + 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x59, 0x53, 0x54, 0x45, + 0x4d, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x17, 0x0a, + 0x13, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x58, 0x46, 0x53, 0x10, 0x01, 0x2a, 0xaf, 0x01, 0x0a, 0x10, 0x42, 0x6c, 0x6f, 0x63, 0x6b, + 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x50, 0x68, 0x61, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x56, + 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x50, 0x48, 0x41, 0x53, 0x45, 0x5f, 0x57, 0x41, 0x49, 0x54, + 0x49, 0x4e, 0x47, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, + 0x50, 0x48, 0x41, 0x53, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x59, 0x10, 0x01, 0x12, 0x17, 0x0a, + 0x13, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x50, 0x48, 0x41, 0x53, 0x45, 0x5f, 0x46, 0x41, + 0x49, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, + 0x5f, 0x50, 0x48, 0x41, 0x53, 0x45, 0x5f, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x10, 0x03, + 0x12, 0x18, 0x0a, 0x14, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x50, 0x48, 0x41, 0x53, 0x45, + 0x5f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, 0x1c, 0x0a, 0x18, 0x56, 0x4f, + 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x50, 0x48, 0x41, 0x53, 0x45, 0x5f, 0x50, 0x52, 0x4f, 0x56, 0x49, + 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x44, 0x10, 0x05, 0x2a, 0x59, 0x0a, 0x0f, 0x42, 0x6c, 0x6f, 0x63, + 0x6b, 0x56, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x56, + 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x41, 0x52, 0x54, 0x49, + 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x49, 0x53, 0x4b, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, + 0x56, 0x4f, 0x4c, 0x55, 0x4d, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x4d, 0x50, 0x46, + 0x53, 0x10, 0x02, 0x2a, 0x53, 0x0a, 0x11, 0x4b, 0x75, 0x62, 0x65, 0x73, 0x70, 0x61, 0x6e, 0x50, + 0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x45, 0x45, 0x52, + 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, + 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, + 0x50, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x45, 0x45, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, + 0x45, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x02, 0x2a, 0x88, 0x01, 0x0a, 0x12, 0x4e, 0x65, 0x74, + 0x77, 0x6f, 0x72, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x12, + 0x12, 0x0a, 0x0e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, + 0x54, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x43, 0x4d, + 0x44, 0x4c, 0x49, 0x4e, 0x45, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x4f, 0x4e, 0x46, 0x49, + 0x47, 0x5f, 0x50, 0x4c, 0x41, 0x54, 0x46, 0x4f, 0x52, 0x4d, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, + 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x10, + 0x03, 0x12, 0x20, 0x0a, 0x1c, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x4d, 0x41, 0x43, 0x48, + 0x49, 0x4e, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, + 0x4e, 0x10, 0x04, 0x2a, 0x4b, 0x0a, 0x0f, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x0e, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, + 0x4f, 0x52, 0x5f, 0x44, 0x48, 0x43, 0x50, 0x34, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4f, 0x50, + 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x44, 0x48, 0x43, 0x50, 0x36, 0x10, 0x01, 0x12, 0x10, + 0x0a, 0x0c, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x4f, 0x52, 0x5f, 0x56, 0x49, 0x50, 0x10, 0x02, + 0x2a, 0x9b, 0x02, 0x0a, 0x13, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x4d, 0x61, 0x63, 0x68, + 0x69, 0x6e, 0x65, 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x4d, 0x41, 0x43, 0x48, + 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, + 0x4e, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, + 0x54, 0x41, 0x47, 0x45, 0x5f, 0x42, 0x4f, 0x4f, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1c, + 0x0a, 0x18, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, + 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4c, 0x4c, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x1d, 0x0a, 0x19, + 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x4d, 0x41, + 0x49, 0x4e, 0x54, 0x45, 0x4e, 0x41, 0x4e, 0x43, 0x45, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x4d, + 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x52, 0x55, 0x4e, + 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, + 0x45, 0x5f, 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x52, 0x45, 0x42, 0x4f, 0x4f, 0x54, 0x49, 0x4e, + 0x47, 0x10, 0x05, 0x12, 0x1f, 0x0a, 0x1b, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, + 0x54, 0x41, 0x47, 0x45, 0x5f, 0x53, 0x48, 0x55, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x44, 0x4f, + 0x57, 0x4e, 0x10, 0x06, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, + 0x53, 0x54, 0x41, 0x47, 0x45, 0x5f, 0x52, 0x45, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x10, + 0x07, 0x12, 0x1b, 0x0a, 0x17, 0x4d, 0x41, 0x43, 0x48, 0x49, 0x4e, 0x45, 0x5f, 0x53, 0x54, 0x41, + 0x47, 0x45, 0x5f, 0x55, 0x50, 0x47, 0x52, 0x41, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x08, 0x42, 0x4a, + 0x5a, 0x48, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x64, + 0x65, 0x72, 0x6f, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, + 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -2476,7 +2654,7 @@ func file_resource_definitions_enums_enums_proto_rawDescGZIP() []byte { return file_resource_definitions_enums_enums_proto_rawDescData } -var file_resource_definitions_enums_enums_proto_enumTypes = make([]protoimpl.EnumInfo, 31) +var file_resource_definitions_enums_enums_proto_enumTypes = make([]protoimpl.EnumInfo, 34) var file_resource_definitions_enums_enums_proto_goTypes = []any{ (MachineType)(0), // 0: talos.resource.definitions.enums.MachineType (NethelpersAddressFlag)(0), // 1: talos.resource.definitions.enums.NethelpersAddressFlag @@ -2505,10 +2683,13 @@ var file_resource_definitions_enums_enums_proto_goTypes = []any{ (NethelpersRoutingTable)(0), // 24: talos.resource.definitions.enums.NethelpersRoutingTable (NethelpersScope)(0), // 25: talos.resource.definitions.enums.NethelpersScope (NethelpersVLANProtocol)(0), // 26: talos.resource.definitions.enums.NethelpersVLANProtocol - (KubespanPeerState)(0), // 27: talos.resource.definitions.enums.KubespanPeerState - (NetworkConfigLayer)(0), // 28: talos.resource.definitions.enums.NetworkConfigLayer - (NetworkOperator)(0), // 29: talos.resource.definitions.enums.NetworkOperator - (RuntimeMachineStage)(0), // 30: talos.resource.definitions.enums.RuntimeMachineStage + (BlockFilesystemType)(0), // 27: talos.resource.definitions.enums.BlockFilesystemType + (BlockVolumePhase)(0), // 28: talos.resource.definitions.enums.BlockVolumePhase + (BlockVolumeType)(0), // 29: talos.resource.definitions.enums.BlockVolumeType + (KubespanPeerState)(0), // 30: talos.resource.definitions.enums.KubespanPeerState + (NetworkConfigLayer)(0), // 31: talos.resource.definitions.enums.NetworkConfigLayer + (NetworkOperator)(0), // 32: talos.resource.definitions.enums.NetworkOperator + (RuntimeMachineStage)(0), // 33: talos.resource.definitions.enums.RuntimeMachineStage } var file_resource_definitions_enums_enums_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type @@ -2528,7 +2709,7 @@ func file_resource_definitions_enums_enums_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_resource_definitions_enums_enums_proto_rawDesc, - NumEnums: 31, + NumEnums: 34, NumMessages: 0, NumExtensions: 0, NumServices: 0, diff --git a/pkg/machinery/cel/cel.go b/pkg/machinery/cel/cel.go new file mode 100644 index 00000000000..eeba5cb906f --- /dev/null +++ b/pkg/machinery/cel/cel.go @@ -0,0 +1,159 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package cel provides helpers for working with CEL expressions. +package cel + +import ( + "encoding" + "fmt" + + "github.com/google/cel-go/cel" + "github.com/google/cel-go/common/types" + "github.com/siderolabs/go-pointer" + "github.com/siderolabs/protoenc" + exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" + "gopkg.in/yaml.v3" + + "github.com/siderolabs/talos/pkg/machinery/proto" +) + +// Expression is a CEL expression that can be marshaled/unmarshaled as part of the resource. +type Expression struct { + ast *cel.Ast + expression *string +} + +// Check interfaces. +var ( + _ encoding.TextMarshaler = Expression{} + _ encoding.TextUnmarshaler = (*Expression)(nil) + _ yaml.IsZeroer = Expression{} +) + +// MustExpression panics if the expression cannot be parsed. +func MustExpression(expr Expression, err error) Expression { + if err != nil { + panic(err) + } + + return expr +} + +// ParseBooleanExpression parses the expression and asserts the result to boolean. +func ParseBooleanExpression(expression string, env *cel.Env) (Expression, error) { + ast, issues := env.Parse(expression) + if issues != nil && issues.Err() != nil { + return Expression{}, issues.Err() + } + + ast, issues = env.Check(ast) + if issues != nil && issues.Err() != nil { + return Expression{}, issues.Err() + } + + if outputType := ast.OutputType(); !outputType.IsExactType(types.BoolType) { + return Expression{}, fmt.Errorf("expression output type is %s, expected bool", outputType) + } + + return Expression{ast: ast}, nil +} + +// EvalBool evaluates the expression in the given environment. +func (expr Expression) EvalBool(env *cel.Env, values map[string]any) (bool, error) { + prog, err := env.Program(expr.ast) + if err != nil { + return false, err + } + + out, _, err := prog.Eval(values) + if err != nil { + return false, err + } + + val, ok := out.Value().(bool) + if !ok { + return false, fmt.Errorf("expression output type is %s, expected bool", out.Type()) + } + + return val, nil +} + +// MarshalText marshals the expression to text. +func (expr Expression) MarshalText() ([]byte, error) { + if expr.expression != nil { + return []byte(*expr.expression), nil + } + + if expr.ast != nil { + repr, err := cel.AstToString(expr.ast) + if err != nil { + return nil, err + } + + return []byte(repr), nil + } + + return nil, nil +} + +// UnmarshalText unmarshals the expression from text. +func (expr *Expression) UnmarshalText(data []byte) error { + if len(data) == 0 { + return nil + } + + expr.expression = pointer.To(string(data)) + + return nil +} + +// IsZero returns true if the expression is zero. +func (expr Expression) IsZero() bool { + return expr.ast == nil && expr.expression == nil +} + +// MarshalProto marshals the expression to proto. +func (expr Expression) MarshalProto() ([]byte, error) { + if expr.ast == nil { + return nil, nil + } + + pbExpr, err := cel.AstToCheckedExpr(expr.ast) + if err != nil { + return nil, err + } + + return proto.Marshal(pbExpr) +} + +// UnmarshalProto unmarshals the expression from proto. +func (expr *Expression) UnmarshalProto(data []byte) error { + if len(data) == 0 { + return nil + } + + pbExpr := &exprpb.CheckedExpr{} + if err := proto.Unmarshal(data, pbExpr); err != nil { + return err + } + + expr.ast = cel.CheckedExprToAst(pbExpr) + + return nil +} + +func init() { + protoenc.RegisterEncoderDecoder( + func(v Expression) ([]byte, error) { + return v.MarshalProto() + }, + func(slc []byte) (Expression, error) { + var v Expression + err := v.UnmarshalProto(slc) + + return v, err + }, + ) +} diff --git a/pkg/machinery/cel/cel_test.go b/pkg/machinery/cel/cel_test.go new file mode 100644 index 00000000000..e79ac1b128a --- /dev/null +++ b/pkg/machinery/cel/cel_test.go @@ -0,0 +1,66 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package cel_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" + + "github.com/siderolabs/talos/pkg/machinery/cel" + "github.com/siderolabs/talos/pkg/machinery/cel/celenv" +) + +func TestCELMarshal(t *testing.T) { + t.Parallel() + + env := celenv.DiskLocator() + + type yamlTest struct { + Expr cel.Expression `yaml:"expr,omitempty"` + } + + for _, test := range []struct { + name string + + expression cel.Expression + + expectedYAML string + }{ + { + name: "empty", + + expectedYAML: "{}\n", + }, + { + name: "system disk", + + expression: cel.MustExpression(cel.ParseBooleanExpression("system_disk", env)), + + expectedYAML: "expr: system_disk\n", + }, + { + name: "disk size and rotational", + + expression: cel.MustExpression(cel.ParseBooleanExpression("disk.size > 1000u && !disk.rotational", env)), + + expectedYAML: "expr: disk.size > 1000u && !disk.rotational\n", + }, + } { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + yamlTest := yamlTest{ + Expr: test.expression, + } + + yaml, err := yaml.Marshal(yamlTest) + require.NoError(t, err) + + require.Equal(t, test.expectedYAML, string(yaml)) + }) + } +} diff --git a/pkg/machinery/cel/celenv/celenv.go b/pkg/machinery/cel/celenv/celenv.go new file mode 100644 index 00000000000..aec86ce4587 --- /dev/null +++ b/pkg/machinery/cel/celenv/celenv.go @@ -0,0 +1,46 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +// Package celenv provides standard CEL environments to evaluate CEL expressions. +package celenv + +import ( + "sync" + + "github.com/google/cel-go/cel" + "github.com/google/cel-go/common/types" + + "github.com/siderolabs/talos/pkg/machinery/api/resource/definitions/block" +) + +// DiskLocator is a disk locator CEL environment. +var DiskLocator = sync.OnceValue(func() *cel.Env { + var diskSpec block.DiskSpec + + env, err := cel.NewEnv( + cel.Types(&diskSpec), + cel.Variable("disk", cel.ObjectType(string(diskSpec.ProtoReflect().Descriptor().FullName()))), + cel.Variable("system_disk", types.BoolType), + ) + if err != nil { + panic(err) + } + + return env +}) + +// VolumeLocator is a volume locator CEL environment. +var VolumeLocator = sync.OnceValue(func() *cel.Env { + var volumeSpec block.DiscoveredVolumeSpec + + env, err := cel.NewEnv( + cel.Types(&volumeSpec), + cel.Variable("volume", cel.ObjectType(string(volumeSpec.ProtoReflect().Descriptor().FullName()))), + ) + if err != nil { + panic(err) + } + + return env +}) diff --git a/pkg/machinery/cel/celenv/celenv_test.go b/pkg/machinery/cel/celenv/celenv_test.go new file mode 100644 index 00000000000..e09e0b88b22 --- /dev/null +++ b/pkg/machinery/cel/celenv/celenv_test.go @@ -0,0 +1,64 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package celenv_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/siderolabs/talos/pkg/machinery/cel" + "github.com/siderolabs/talos/pkg/machinery/cel/celenv" +) + +func TestDiskLocator(t *testing.T) { + t.Parallel() + + env := celenv.DiskLocator() + + for _, test := range []struct { + name string + expression string + }{ + { + name: "system disk", + expression: "system_disk", + }, + { + name: "disk size", + expression: "disk.size > 1000u && !disk.rotational", + }, + } { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + _, err := cel.ParseBooleanExpression(test.expression, env) + require.NoError(t, err) + }) + } +} + +func TestVolumeLocator(t *testing.T) { + t.Parallel() + + env := celenv.VolumeLocator() + + for _, test := range []struct { + name string + expression string + }{ + { + name: "by label", + expression: "volume.label == 'EPHEMERAL'", + }, + } { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + _, err := cel.ParseBooleanExpression(test.expression, env) + require.NoError(t, err) + }) + } +} diff --git a/pkg/machinery/compatibility/talos_version.go b/pkg/machinery/compatibility/talos_version.go index cfa80abab0d..a783c5dd953 100644 --- a/pkg/machinery/compatibility/talos_version.go +++ b/pkg/machinery/compatibility/talos_version.go @@ -52,6 +52,17 @@ func (v *TalosVersion) DisablePredictableNetworkInterfaces() bool { return false } +// PrecreateStatePartition returns true if running an 1.8+ installer from a version before <=1.7.x. +// +// Host Talos needs STATE partition to save the machine configuration. +func (v *TalosVersion) PrecreateStatePartition() bool { + if v.majorMinor[0] <= talos17.MajorMinor[0] && v.majorMinor[1] <= talos17.MajorMinor[1] { + return true + } + + return false +} + // UpgradeableFrom checks if the current version of Talos can be used as an upgrade for the given host version. // //nolint:gocyclo diff --git a/pkg/machinery/go.mod b/pkg/machinery/go.mod index e20376e6d82..1db63eb6954 100644 --- a/pkg/machinery/go.mod +++ b/pkg/machinery/go.mod @@ -15,6 +15,7 @@ require ( github.com/evanphx/json-patch v5.9.0+incompatible github.com/fatih/color v1.17.0 github.com/ghodss/yaml v1.0.0 + github.com/google/cel-go v0.20.1 github.com/hashicorp/go-multierror v1.1.1 github.com/hexops/gotextdiff v1.0.3 github.com/jsimonetti/rtnetlink/v2 v2.0.2 @@ -41,6 +42,7 @@ require ( github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect github.com/ProtonMail/gopenpgp/v2 v2.7.5 // indirect github.com/adrg/xdg v0.4.0 // indirect + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/cloudflare/circl v1.3.9 // indirect github.com/containernetworking/cni v1.2.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -58,6 +60,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/stoewer/go-strcase v1.2.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.26.0 // indirect diff --git a/pkg/machinery/go.sum b/pkg/machinery/go.sum index ba1d08368e0..a573f9372b9 100644 --- a/pkg/machinery/go.sum +++ b/pkg/machinery/go.sum @@ -7,6 +7,8 @@ github.com/ProtonMail/gopenpgp/v2 v2.7.5 h1:STOY3vgES59gNgoOt2w0nyHBjKViB/qSg7Nj github.com/ProtonMail/gopenpgp/v2 v2.7.5/go.mod h1:IhkNEDaxec6NyzSI0PlxapinnwPVIESk8/76da3Ct3g= github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/brianvoe/gofakeit/v6 v6.24.0 h1:74yq7RRz/noddscZHRS2T84oHZisW9muwbb8sRnU52A= @@ -43,6 +45,8 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84= +github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= @@ -113,9 +117,12 @@ github.com/siderolabs/net v0.4.0 h1:1bOgVay/ijPkJz4qct98nHsiB/ysLQU0KLoBC4qLm7I= github.com/siderolabs/net v0.4.0/go.mod h1:/ibG+Hm9HU27agp5r9Q3eZicEfjquzNzQNux5uEk0kM= github.com/siderolabs/protoenc v0.2.1 h1:BqxEmeWQeMpNP3R6WrPqDatX8sM/r4t97OP8mFmg6GA= github.com/siderolabs/protoenc v0.2.1/go.mod h1:StTHxjet1g11GpNAWiATgc8K0HMKiFSEVVFOa/H0otc= +github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= @@ -200,5 +207,6 @@ google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWn gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/pkg/machinery/imager/quirks/quirks.go b/pkg/machinery/imager/quirks/quirks.go index 5c942e8b2e2..e8f81bae995 100644 --- a/pkg/machinery/imager/quirks/quirks.go +++ b/pkg/machinery/imager/quirks/quirks.go @@ -86,3 +86,15 @@ func (q Quirks) SupportsMultidoc() bool { return q.v.GTE(minVersionMultidoc) } + +var minVersionSkipDataPartitions = semver.MustParse("1.8.0") + +// SkipDataPartitions returns true if the Talos version supports creating EPHEMERAL/STATE partitions on its own. +func (q Quirks) SkipDataPartitions() bool { + // if the version doesn't parse, we assume it's latest Talos + if q.v == nil { + return true + } + + return q.v.GTE(minVersionSkipDataPartitions) +} diff --git a/pkg/machinery/resources/block/block.go b/pkg/machinery/resources/block/block.go index 3ca9b814f62..b064cbe00a3 100644 --- a/pkg/machinery/resources/block/block.go +++ b/pkg/machinery/resources/block/block.go @@ -11,7 +11,9 @@ import ( "github.com/siderolabs/talos/pkg/machinery/resources/v1alpha1" ) -//go:generate deep-copy -type DeviceSpec -type DiscoveredVolumeSpec -type DiskSpec -type SystemDiskSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go . +//go:generate deep-copy -type DeviceSpec -type DiscoveredVolumeSpec -type DiscoveryRefreshRequestSpec -type DiscoveryRefreshStatusSpec -type DiskSpec -type SystemDiskSpec -type VolumeConfigSpec -type VolumeStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go . + +//go:generate enumer -type=VolumeType,VolumePhase,FilesystemType -linecomment -text // NamespaceName contains configuration resources. const NamespaceName resource.Namespace = v1alpha1.NamespaceName diff --git a/pkg/machinery/resources/block/block_test.go b/pkg/machinery/resources/block/block_test.go index f5314a6c68c..e0254da7906 100644 --- a/pkg/machinery/resources/block/block_test.go +++ b/pkg/machinery/resources/block/block_test.go @@ -26,9 +26,13 @@ func TestRegisterResource(t *testing.T) { for _, resource := range []meta.ResourceWithRD{ &block.Device{}, + &block.DiscoveryRefreshRequest{}, + &block.DiscoveryRefreshStatus{}, &block.DiscoveredVolume{}, &block.Disk{}, &block.SystemDisk{}, + &block.VolumeConfig{}, + &block.VolumeStatus{}, } { assert.NoError(t, resourceRegistry.Register(ctx, resource)) } diff --git a/pkg/machinery/resources/block/deep_copy.generated.go b/pkg/machinery/resources/block/deep_copy.generated.go index 720526e3e23..356a77b0bfa 100644 --- a/pkg/machinery/resources/block/deep_copy.generated.go +++ b/pkg/machinery/resources/block/deep_copy.generated.go @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. -// Code generated by "deep-copy -type DeviceSpec -type DiscoveredVolumeSpec -type DiskSpec -type SystemDiskSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT. +// Code generated by "deep-copy -type DeviceSpec -type DiscoveredVolumeSpec -type DiscoveryRefreshRequestSpec -type DiscoveryRefreshStatusSpec -type DiskSpec -type SystemDiskSpec -type VolumeConfigSpec -type VolumeStatusSpec -header-file ../../../../hack/boilerplate.txt -o deep_copy.generated.go ."; DO NOT EDIT. package block @@ -18,6 +18,18 @@ func (o DiscoveredVolumeSpec) DeepCopy() DiscoveredVolumeSpec { return cp } +// DeepCopy generates a deep copy of DiscoveryRefreshRequestSpec. +func (o DiscoveryRefreshRequestSpec) DeepCopy() DiscoveryRefreshRequestSpec { + var cp DiscoveryRefreshRequestSpec = o + return cp +} + +// DeepCopy generates a deep copy of DiscoveryRefreshStatusSpec. +func (o DiscoveryRefreshStatusSpec) DeepCopy() DiscoveryRefreshStatusSpec { + var cp DiscoveryRefreshStatusSpec = o + return cp +} + // DeepCopy generates a deep copy of DiskSpec. func (o DiskSpec) DeepCopy() DiskSpec { var cp DiskSpec = o @@ -29,3 +41,15 @@ func (o SystemDiskSpec) DeepCopy() SystemDiskSpec { var cp SystemDiskSpec = o return cp } + +// DeepCopy generates a deep copy of VolumeConfigSpec. +func (o VolumeConfigSpec) DeepCopy() VolumeConfigSpec { + var cp VolumeConfigSpec = o + return cp +} + +// DeepCopy generates a deep copy of VolumeStatusSpec. +func (o VolumeStatusSpec) DeepCopy() VolumeStatusSpec { + var cp VolumeStatusSpec = o + return cp +} diff --git a/pkg/machinery/resources/block/discovered_volume.go b/pkg/machinery/resources/block/discovered_volume.go index 43e6804bcaa..9dac1d8e936 100644 --- a/pkg/machinery/resources/block/discovered_volume.go +++ b/pkg/machinery/resources/block/discovered_volume.go @@ -13,7 +13,7 @@ import ( "github.com/siderolabs/talos/pkg/machinery/proto" ) -// DiscoveredVolumeType is type of BlockDiscoveredVolume resource. +// DiscoveredVolumeType is type of DiscoveredVolume resource. const DiscoveredVolumeType = resource.Type("DiscoveredVolumes.block.talos.dev") // DiscoveredVolume resource holds status of hardware DiscoveredVolumes (overall). @@ -23,9 +23,11 @@ type DiscoveredVolume = typed.Resource[DiscoveredVolumeSpec, DiscoveredVolumeExt // //gotagsrewrite:gen type DiscoveredVolumeSpec struct { - Type string `yaml:"type" protobuf:"14"` - DevicePath string `yaml:"devicePath" protobuf:"15"` - Parent string `yaml:"parent,omitempty" protobuf:"16"` + DevPath string `yaml:"devPath" protobuf:"17"` + Type string `yaml:"type" protobuf:"14"` + DevicePath string `yaml:"devicePath" protobuf:"15"` + Parent string `yaml:"parent,omitempty" protobuf:"16"` + ParentDevPath string `yaml:"parentDevPath,omitempty" protobuf:"18"` // Overall size of the probed device (in bytes). Size uint64 `yaml:"size" protobuf:"1"` diff --git a/pkg/machinery/resources/block/discovery_refresh_request.go b/pkg/machinery/resources/block/discovery_refresh_request.go new file mode 100644 index 00000000000..c76ea5c1802 --- /dev/null +++ b/pkg/machinery/resources/block/discovery_refresh_request.go @@ -0,0 +1,65 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package block + +import ( + "github.com/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/resource/meta" + "github.com/cosi-project/runtime/pkg/resource/protobuf" + "github.com/cosi-project/runtime/pkg/resource/typed" + + "github.com/siderolabs/talos/pkg/machinery/proto" +) + +// DiscoveryRefreshRequestType is type of DiscoveryRefreshRequest resource. +const DiscoveryRefreshRequestType = resource.Type("DiscoveryRefreshRequests.block.talos.dev") + +// RefreshID is the ID of the singleton discovery refresh request/statue. +const RefreshID resource.ID = "refresh" + +// DiscoveryRefreshRequest resource holds a request to refresh the discovered volumes. +type DiscoveryRefreshRequest = typed.Resource[DiscoveryRefreshRequestSpec, DiscoveryRefreshRequestExtension] + +// DiscoveryRefreshRequestSpec is the spec for DiscoveryRefreshRequest. +// +//gotagsrewrite:gen +type DiscoveryRefreshRequestSpec struct { + Request int `yaml:"request" protobuf:"1"` +} + +// NewDiscoveryRefreshRequest initializes a DiscoveryRefreshRequest resource. +func NewDiscoveryRefreshRequest(namespace resource.Namespace, id resource.ID) *DiscoveryRefreshRequest { + return typed.NewResource[DiscoveryRefreshRequestSpec, DiscoveryRefreshRequestExtension]( + resource.NewMetadata(namespace, DiscoveryRefreshRequestType, id, resource.VersionUndefined), + DiscoveryRefreshRequestSpec{}, + ) +} + +// DiscoveryRefreshRequestExtension is auxiliary resource data for DiscoveryRefreshRequest. +type DiscoveryRefreshRequestExtension struct{} + +// ResourceDefinition implements meta.ResourceDefinitionProvider interface. +func (DiscoveryRefreshRequestExtension) ResourceDefinition() meta.ResourceDefinitionSpec { + return meta.ResourceDefinitionSpec{ + Type: DiscoveryRefreshRequestType, + Aliases: []resource.Type{}, + DefaultNamespace: NamespaceName, + PrintColumns: []meta.PrintColumn{ + { + Name: "Request", + JSONPath: `{.request}`, + }, + }, + } +} + +func init() { + proto.RegisterDefaultTypes() + + err := protobuf.RegisterDynamic[DiscoveryRefreshRequestSpec](DiscoveryRefreshRequestType, &DiscoveryRefreshRequest{}) + if err != nil { + panic(err) + } +} diff --git a/pkg/machinery/resources/block/discovery_refresh_status.go b/pkg/machinery/resources/block/discovery_refresh_status.go new file mode 100644 index 00000000000..3197cfa9434 --- /dev/null +++ b/pkg/machinery/resources/block/discovery_refresh_status.go @@ -0,0 +1,62 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package block + +import ( + "github.com/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/resource/meta" + "github.com/cosi-project/runtime/pkg/resource/protobuf" + "github.com/cosi-project/runtime/pkg/resource/typed" + + "github.com/siderolabs/talos/pkg/machinery/proto" +) + +// DiscoveryRefreshStatusType is type of DiscoveryRefreshStatus resource. +const DiscoveryRefreshStatusType = resource.Type("DiscoveryRefreshStatuses.block.talos.dev") + +// DiscoveryRefreshStatus resource holds a status of refresh. +type DiscoveryRefreshStatus = typed.Resource[DiscoveryRefreshStatusSpec, DiscoveryRefreshStatusExtension] + +// DiscoveryRefreshStatusSpec is the spec for DiscoveryRefreshStatus status. +// +//gotagsrewrite:gen +type DiscoveryRefreshStatusSpec struct { + Request int `yaml:"request" protobuf:"1"` +} + +// NewDiscoveryRefreshStatus initializes a DiscoveryRefreshStatus resource. +func NewDiscoveryRefreshStatus(namespace resource.Namespace, id resource.ID) *DiscoveryRefreshStatus { + return typed.NewResource[DiscoveryRefreshStatusSpec, DiscoveryRefreshStatusExtension]( + resource.NewMetadata(namespace, DiscoveryRefreshStatusType, id, resource.VersionUndefined), + DiscoveryRefreshStatusSpec{}, + ) +} + +// DiscoveryRefreshStatusExtension is auxiliary resource data for DiscoveryRefreshStatus. +type DiscoveryRefreshStatusExtension struct{} + +// ResourceDefinition implements meta.ResourceDefinitionProvider interface. +func (DiscoveryRefreshStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec { + return meta.ResourceDefinitionSpec{ + Type: DiscoveryRefreshStatusType, + Aliases: []resource.Type{}, + DefaultNamespace: NamespaceName, + PrintColumns: []meta.PrintColumn{ + { + Name: "Request", + JSONPath: `{.request}`, + }, + }, + } +} + +func init() { + proto.RegisterDefaultTypes() + + err := protobuf.RegisterDynamic[DiscoveryRefreshStatusSpec](DiscoveryRefreshStatusType, &DiscoveryRefreshStatus{}) + if err != nil { + panic(err) + } +} diff --git a/pkg/machinery/resources/block/disk.go b/pkg/machinery/resources/block/disk.go index 3c393d307f6..afb0ca03044 100644 --- a/pkg/machinery/resources/block/disk.go +++ b/pkg/machinery/resources/block/disk.go @@ -23,6 +23,8 @@ type Disk = typed.Resource[DiskSpec, DiskExtension] // //gotagsrewrite:gen type DiskSpec struct { + DevPath string `yaml:"devPath" protobuf:"14"` + Size uint64 `yaml:"size" protobuf:"1"` IOSize uint `yaml:"ioSize" protobuf:"2"` SectorSize uint `yaml:"sectorSize" protobuf:"3"` diff --git a/pkg/machinery/resources/block/filesystemtype.go b/pkg/machinery/resources/block/filesystemtype.go new file mode 100644 index 00000000000..f1be375135d --- /dev/null +++ b/pkg/machinery/resources/block/filesystemtype.go @@ -0,0 +1,16 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package block + +// FilesystemType describes filesystem type. +type FilesystemType int + +// Filesystem types. +// +//structprotogen:gen_enum +const ( + FilesystemTypeNone FilesystemType = iota // none + FilesystemTypeXFS // xfs +) diff --git a/pkg/machinery/resources/block/volume_config.go b/pkg/machinery/resources/block/volume_config.go new file mode 100644 index 00000000000..3aedebcc93b --- /dev/null +++ b/pkg/machinery/resources/block/volume_config.go @@ -0,0 +1,135 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package block + +import ( + "github.com/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/resource/meta" + "github.com/cosi-project/runtime/pkg/resource/protobuf" + "github.com/cosi-project/runtime/pkg/resource/typed" + + "github.com/siderolabs/talos/pkg/machinery/cel" + "github.com/siderolabs/talos/pkg/machinery/proto" +) + +// VolumeConfigType is type of VolumeConfig resource. +const VolumeConfigType = resource.Type("VolumeConfigs.block.talos.dev") + +// VolumeConfig resource contains configuration for machine volumes. +type VolumeConfig = typed.Resource[VolumeConfigSpec, VolumeConfigExtension] + +// VolumeConfigSpec is the spec for VolumeConfig resource. +// +//gotagsrewrite:gen +type VolumeConfigSpec struct { + // Parent volume ID, if set no operations on the volume continue until the parent volume is ready. + ParentID string `yaml:"parentId,omitempty" protobuf:"1"` + + // Volume type. + Type VolumeType `yaml:"type" protobuf:"2"` + + // Provisioning configuration (how to provision a volume). + Provisioning ProvisioningSpec `yaml:"provisioning" protobuf:"3"` + + // How to find a volume. + Locator LocatorSpec `yaml:"locator" protobuf:"4"` +} + +// Wave constants. +const ( + WaveSystemDisk = -1 + WaveUserDisks = 0 +) + +// ProvisioningSpec is the spec for volume provisioning. +// +//gotagsrewrite:gen +type ProvisioningSpec struct { + // Provisioning wave for the volume. + // + // Waves are processed sequentially - the volumes in the wave are only provisioned after the previous wave is done. + Wave int `yaml:"wave,omitempty" protobuf:"3"` + + // DiskSelector selects a disk for the volume. + DiskSelector DiskSelector `yaml:"diskSelector,omitempty" protobuf:"1"` + + // PartitionSpec describes how to provision the volume (partition type). + PartitionSpec PartitionSpec `yaml:"partitionSpec,omitempty" protobuf:"2"` + + // FilesystemSpec describes how to provision the volume (filesystem type). + FilesystemSpec FilesystemSpec `yaml:"filesystemSpec,omitempty" protobuf:"4"` +} + +// DiskSelector selects a disk for the volume. +// +//gotagsrewrite:gen +type DiskSelector struct { + Match cel.Expression `yaml:"match,omitempty" protobuf:"1"` +} + +// PartitionSpec is the spec for volume partitioning. +// +//gotagsrewrite:gen +type PartitionSpec struct { + // Partition minimum size in bytes. + MinSize uint64 `yaml:"minSize" protobuf:"1"` + + // Partition maximum size in bytes, if not set, grows to the maximum size. + MaxSize uint64 `yaml:"maxSize,omitempty" protobuf:"2"` + + // Grow the partition automatically to the maximum size. + Grow bool `yaml:"grow" protobuf:"3"` + + // Label for the partition. + Label string `yaml:"label,omitempty" protobuf:"4"` + + // Partition type UUID. + TypeUUID string `yaml:"typeUUID,omitempty" protobuf:"5"` +} + +// LocatorSpec is the spec for volume locator. +// +//gotagsrewrite:gen +type LocatorSpec struct { + Match cel.Expression `yaml:"match,omitempty" protobuf:"1"` +} + +// FilesystemSpec is the spec for volume filesystem. +// +//gotagsrewrite:gen +type FilesystemSpec struct { + // Filesystem type. + Type FilesystemType `yaml:"type" protobuf:"1"` +} + +// NewVolumeConfig initializes a BlockVolumeConfig resource. +func NewVolumeConfig(namespace resource.Namespace, id resource.ID) *VolumeConfig { + return typed.NewResource[VolumeConfigSpec, VolumeConfigExtension]( + resource.NewMetadata(namespace, VolumeConfigType, id, resource.VersionUndefined), + VolumeConfigSpec{}, + ) +} + +// VolumeConfigExtension is auxiliary resource data for BlockVolumeConfig. +type VolumeConfigExtension struct{} + +// ResourceDefinition implements meta.ResourceDefinitionProvider interface. +func (VolumeConfigExtension) ResourceDefinition() meta.ResourceDefinitionSpec { + return meta.ResourceDefinitionSpec{ + Type: VolumeConfigType, + Aliases: []resource.Type{}, + DefaultNamespace: NamespaceName, + PrintColumns: []meta.PrintColumn{}, + } +} + +func init() { + proto.RegisterDefaultTypes() + + err := protobuf.RegisterDynamic[VolumeConfigSpec](VolumeConfigType, &VolumeConfig{}) + if err != nil { + panic(err) + } +} diff --git a/pkg/machinery/resources/block/volume_status.go b/pkg/machinery/resources/block/volume_status.go new file mode 100644 index 00000000000..da062fabb0c --- /dev/null +++ b/pkg/machinery/resources/block/volume_status.go @@ -0,0 +1,76 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package block + +import ( + "github.com/cosi-project/runtime/pkg/resource" + "github.com/cosi-project/runtime/pkg/resource/meta" + "github.com/cosi-project/runtime/pkg/resource/protobuf" + "github.com/cosi-project/runtime/pkg/resource/typed" + + "github.com/siderolabs/talos/pkg/machinery/proto" +) + +// VolumeStatusType is type of VolumeStatus resource. +const VolumeStatusType = resource.Type("VolumeStatuses.block.talos.dev") + +// VolumeStatus resource contains information about the volume status. +type VolumeStatus = typed.Resource[VolumeStatusSpec, VolumeStatusExtension] + +// VolumeStatusSpec is the spec for VolumeStatus resource. +// +//gotagsrewrite:gen +type VolumeStatusSpec struct { + Phase VolumePhase `yaml:"phase" protobuf:"1"` + PreFailPhase VolumePhase `yaml:"preFailPhase,omitempty" protobuf:"6"` + + Location string `yaml:"location,omitempty" protobuf:"2"` + PartitionIndex int `yaml:"partitionIndex,omitempty" protobuf:"8"` + ParentLocation string `yaml:"parentLocation,omitempty" protobuf:"7"` + UUID string `yaml:"uuid,omitempty" protobuf:"4"` + PartitionUUID string `yaml:"partitionUUID,omitempty" protobuf:"5"` + Size uint64 `yaml:"size,omitempty" protobuf:"9"` + + ErrorMessage string `yaml:"errorMessage,omitempty" protobuf:"3"` +} + +// NewVolumeStatus initializes a BlockVolumeStatus resource. +func NewVolumeStatus(namespace resource.Namespace, id resource.ID) *VolumeStatus { + return typed.NewResource[VolumeStatusSpec, VolumeStatusExtension]( + resource.NewMetadata(namespace, VolumeStatusType, id, resource.VersionUndefined), + VolumeStatusSpec{}, + ) +} + +// VolumeStatusExtension is auxiliary resource data for BlockVolumeStatus. +type VolumeStatusExtension struct{} + +// ResourceDefinition implements meta.ResourceDefinitionProvider interface. +func (VolumeStatusExtension) ResourceDefinition() meta.ResourceDefinitionSpec { + return meta.ResourceDefinitionSpec{ + Type: VolumeStatusType, + Aliases: []resource.Type{}, + DefaultNamespace: NamespaceName, + PrintColumns: []meta.PrintColumn{ + { + Name: "Phase", + JSONPath: `{.phase}`, + }, + { + Name: "Location", + JSONPath: `{.location}`, + }, + }, + } +} + +func init() { + proto.RegisterDefaultTypes() + + err := protobuf.RegisterDynamic[VolumeStatusSpec](VolumeStatusType, &VolumeStatus{}) + if err != nil { + panic(err) + } +} diff --git a/pkg/machinery/resources/block/volumephase.go b/pkg/machinery/resources/block/volumephase.go new file mode 100644 index 00000000000..8b10dc25499 --- /dev/null +++ b/pkg/machinery/resources/block/volumephase.go @@ -0,0 +1,20 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package block + +// VolumePhase describes volume phase. +type VolumePhase int + +// Volume phases. +// +//structprotogen:gen_enum +const ( + VolumePhaseWaiting VolumePhase = iota // waiting + VolumePhaseReady // ready + VolumePhaseFailed // failed + VolumePhaseMissing // missing + VolumePhaseLocated // located + VolumePhaseProvisioned // provisioned +) diff --git a/pkg/machinery/resources/block/volumetype.go b/pkg/machinery/resources/block/volumetype.go new file mode 100644 index 00000000000..6e8f665f1f1 --- /dev/null +++ b/pkg/machinery/resources/block/volumetype.go @@ -0,0 +1,17 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package block + +// VolumeType describes volume type. +type VolumeType int + +// Volume types. +// +//structprotogen:gen_enum +const ( + VolumeTypePartition VolumeType = iota // partition + VolumeTypeDisk // disk + VolumeTypeTmpfs // tmpfs +) diff --git a/pkg/machinery/resources/block/volumetype_enumer.go b/pkg/machinery/resources/block/volumetype_enumer.go new file mode 100644 index 00000000000..21fa3c1677b --- /dev/null +++ b/pkg/machinery/resources/block/volumetype_enumer.go @@ -0,0 +1,274 @@ +// Code generated by "enumer -type=VolumeType,VolumePhase,FilesystemType -linecomment -text"; DO NOT EDIT. + +package block + +import ( + "fmt" + "strings" +) + +const _VolumeTypeName = "partitiondisktmpfs" + +var _VolumeTypeIndex = [...]uint8{0, 9, 13, 18} + +const _VolumeTypeLowerName = "partitiondisktmpfs" + +func (i VolumeType) String() string { + if i < 0 || i >= VolumeType(len(_VolumeTypeIndex)-1) { + return fmt.Sprintf("VolumeType(%d)", i) + } + return _VolumeTypeName[_VolumeTypeIndex[i]:_VolumeTypeIndex[i+1]] +} + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the stringer command to generate them again. +func _VolumeTypeNoOp() { + var x [1]struct{} + _ = x[VolumeTypePartition-(0)] + _ = x[VolumeTypeDisk-(1)] + _ = x[VolumeTypeTmpfs-(2)] +} + +var _VolumeTypeValues = []VolumeType{VolumeTypePartition, VolumeTypeDisk, VolumeTypeTmpfs} + +var _VolumeTypeNameToValueMap = map[string]VolumeType{ + _VolumeTypeName[0:9]: VolumeTypePartition, + _VolumeTypeLowerName[0:9]: VolumeTypePartition, + _VolumeTypeName[9:13]: VolumeTypeDisk, + _VolumeTypeLowerName[9:13]: VolumeTypeDisk, + _VolumeTypeName[13:18]: VolumeTypeTmpfs, + _VolumeTypeLowerName[13:18]: VolumeTypeTmpfs, +} + +var _VolumeTypeNames = []string{ + _VolumeTypeName[0:9], + _VolumeTypeName[9:13], + _VolumeTypeName[13:18], +} + +// VolumeTypeString retrieves an enum value from the enum constants string name. +// Throws an error if the param is not part of the enum. +func VolumeTypeString(s string) (VolumeType, error) { + if val, ok := _VolumeTypeNameToValueMap[s]; ok { + return val, nil + } + + if val, ok := _VolumeTypeNameToValueMap[strings.ToLower(s)]; ok { + return val, nil + } + return 0, fmt.Errorf("%s does not belong to VolumeType values", s) +} + +// VolumeTypeValues returns all values of the enum +func VolumeTypeValues() []VolumeType { + return _VolumeTypeValues +} + +// VolumeTypeStrings returns a slice of all String values of the enum +func VolumeTypeStrings() []string { + strs := make([]string, len(_VolumeTypeNames)) + copy(strs, _VolumeTypeNames) + return strs +} + +// IsAVolumeType returns "true" if the value is listed in the enum definition. "false" otherwise +func (i VolumeType) IsAVolumeType() bool { + for _, v := range _VolumeTypeValues { + if i == v { + return true + } + } + return false +} + +// MarshalText implements the encoding.TextMarshaler interface for VolumeType +func (i VolumeType) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface for VolumeType +func (i *VolumeType) UnmarshalText(text []byte) error { + var err error + *i, err = VolumeTypeString(string(text)) + return err +} + +const _VolumePhaseName = "waitingreadyfailedmissinglocatedprovisioned" + +var _VolumePhaseIndex = [...]uint8{0, 7, 12, 18, 25, 32, 43} + +const _VolumePhaseLowerName = "waitingreadyfailedmissinglocatedprovisioned" + +func (i VolumePhase) String() string { + if i < 0 || i >= VolumePhase(len(_VolumePhaseIndex)-1) { + return fmt.Sprintf("VolumePhase(%d)", i) + } + return _VolumePhaseName[_VolumePhaseIndex[i]:_VolumePhaseIndex[i+1]] +} + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the stringer command to generate them again. +func _VolumePhaseNoOp() { + var x [1]struct{} + _ = x[VolumePhaseWaiting-(0)] + _ = x[VolumePhaseReady-(1)] + _ = x[VolumePhaseFailed-(2)] + _ = x[VolumePhaseMissing-(3)] + _ = x[VolumePhaseLocated-(4)] + _ = x[VolumePhaseProvisioned-(5)] +} + +var _VolumePhaseValues = []VolumePhase{VolumePhaseWaiting, VolumePhaseReady, VolumePhaseFailed, VolumePhaseMissing, VolumePhaseLocated, VolumePhaseProvisioned} + +var _VolumePhaseNameToValueMap = map[string]VolumePhase{ + _VolumePhaseName[0:7]: VolumePhaseWaiting, + _VolumePhaseLowerName[0:7]: VolumePhaseWaiting, + _VolumePhaseName[7:12]: VolumePhaseReady, + _VolumePhaseLowerName[7:12]: VolumePhaseReady, + _VolumePhaseName[12:18]: VolumePhaseFailed, + _VolumePhaseLowerName[12:18]: VolumePhaseFailed, + _VolumePhaseName[18:25]: VolumePhaseMissing, + _VolumePhaseLowerName[18:25]: VolumePhaseMissing, + _VolumePhaseName[25:32]: VolumePhaseLocated, + _VolumePhaseLowerName[25:32]: VolumePhaseLocated, + _VolumePhaseName[32:43]: VolumePhaseProvisioned, + _VolumePhaseLowerName[32:43]: VolumePhaseProvisioned, +} + +var _VolumePhaseNames = []string{ + _VolumePhaseName[0:7], + _VolumePhaseName[7:12], + _VolumePhaseName[12:18], + _VolumePhaseName[18:25], + _VolumePhaseName[25:32], + _VolumePhaseName[32:43], +} + +// VolumePhaseString retrieves an enum value from the enum constants string name. +// Throws an error if the param is not part of the enum. +func VolumePhaseString(s string) (VolumePhase, error) { + if val, ok := _VolumePhaseNameToValueMap[s]; ok { + return val, nil + } + + if val, ok := _VolumePhaseNameToValueMap[strings.ToLower(s)]; ok { + return val, nil + } + return 0, fmt.Errorf("%s does not belong to VolumePhase values", s) +} + +// VolumePhaseValues returns all values of the enum +func VolumePhaseValues() []VolumePhase { + return _VolumePhaseValues +} + +// VolumePhaseStrings returns a slice of all String values of the enum +func VolumePhaseStrings() []string { + strs := make([]string, len(_VolumePhaseNames)) + copy(strs, _VolumePhaseNames) + return strs +} + +// IsAVolumePhase returns "true" if the value is listed in the enum definition. "false" otherwise +func (i VolumePhase) IsAVolumePhase() bool { + for _, v := range _VolumePhaseValues { + if i == v { + return true + } + } + return false +} + +// MarshalText implements the encoding.TextMarshaler interface for VolumePhase +func (i VolumePhase) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface for VolumePhase +func (i *VolumePhase) UnmarshalText(text []byte) error { + var err error + *i, err = VolumePhaseString(string(text)) + return err +} + +const _FilesystemTypeName = "nonexfs" + +var _FilesystemTypeIndex = [...]uint8{0, 4, 7} + +const _FilesystemTypeLowerName = "nonexfs" + +func (i FilesystemType) String() string { + if i < 0 || i >= FilesystemType(len(_FilesystemTypeIndex)-1) { + return fmt.Sprintf("FilesystemType(%d)", i) + } + return _FilesystemTypeName[_FilesystemTypeIndex[i]:_FilesystemTypeIndex[i+1]] +} + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the stringer command to generate them again. +func _FilesystemTypeNoOp() { + var x [1]struct{} + _ = x[FilesystemTypeNone-(0)] + _ = x[FilesystemTypeXFS-(1)] +} + +var _FilesystemTypeValues = []FilesystemType{FilesystemTypeNone, FilesystemTypeXFS} + +var _FilesystemTypeNameToValueMap = map[string]FilesystemType{ + _FilesystemTypeName[0:4]: FilesystemTypeNone, + _FilesystemTypeLowerName[0:4]: FilesystemTypeNone, + _FilesystemTypeName[4:7]: FilesystemTypeXFS, + _FilesystemTypeLowerName[4:7]: FilesystemTypeXFS, +} + +var _FilesystemTypeNames = []string{ + _FilesystemTypeName[0:4], + _FilesystemTypeName[4:7], +} + +// FilesystemTypeString retrieves an enum value from the enum constants string name. +// Throws an error if the param is not part of the enum. +func FilesystemTypeString(s string) (FilesystemType, error) { + if val, ok := _FilesystemTypeNameToValueMap[s]; ok { + return val, nil + } + + if val, ok := _FilesystemTypeNameToValueMap[strings.ToLower(s)]; ok { + return val, nil + } + return 0, fmt.Errorf("%s does not belong to FilesystemType values", s) +} + +// FilesystemTypeValues returns all values of the enum +func FilesystemTypeValues() []FilesystemType { + return _FilesystemTypeValues +} + +// FilesystemTypeStrings returns a slice of all String values of the enum +func FilesystemTypeStrings() []string { + strs := make([]string, len(_FilesystemTypeNames)) + copy(strs, _FilesystemTypeNames) + return strs +} + +// IsAFilesystemType returns "true" if the value is listed in the enum definition. "false" otherwise +func (i FilesystemType) IsAFilesystemType() bool { + for _, v := range _FilesystemTypeValues { + if i == v { + return true + } + } + return false +} + +// MarshalText implements the encoding.TextMarshaler interface for FilesystemType +func (i FilesystemType) MarshalText() ([]byte, error) { + return []byte(i.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface for FilesystemType +func (i *FilesystemType) UnmarshalText(text []byte) error { + var err error + *i, err = FilesystemTypeString(string(text)) + return err +} diff --git a/website/content/v1.8/reference/api.md b/website/content/v1.8/reference/api.md index af9c588ea70..1a0f09ade26 100644 --- a/website/content/v1.8/reference/api.md +++ b/website/content/v1.8/reference/api.md @@ -29,8 +29,17 @@ description: Talos gRPC API reference. - [resource/definitions/block/block.proto](#resource/definitions/block/block.proto) - [DeviceSpec](#talos.resource.definitions.block.DeviceSpec) - [DiscoveredVolumeSpec](#talos.resource.definitions.block.DiscoveredVolumeSpec) + - [DiscoveryRefreshRequestSpec](#talos.resource.definitions.block.DiscoveryRefreshRequestSpec) + - [DiscoveryRefreshStatusSpec](#talos.resource.definitions.block.DiscoveryRefreshStatusSpec) + - [DiskSelector](#talos.resource.definitions.block.DiskSelector) - [DiskSpec](#talos.resource.definitions.block.DiskSpec) + - [FilesystemSpec](#talos.resource.definitions.block.FilesystemSpec) + - [LocatorSpec](#talos.resource.definitions.block.LocatorSpec) + - [PartitionSpec](#talos.resource.definitions.block.PartitionSpec) + - [ProvisioningSpec](#talos.resource.definitions.block.ProvisioningSpec) - [SystemDiskSpec](#talos.resource.definitions.block.SystemDiskSpec) + - [VolumeConfigSpec](#talos.resource.definitions.block.VolumeConfigSpec) + - [VolumeStatusSpec](#talos.resource.definitions.block.VolumeStatusSpec) - [resource/definitions/cluster/cluster.proto](#resource/definitions/cluster/cluster.proto) - [AffiliateSpec](#talos.resource.definitions.cluster.AffiliateSpec) @@ -45,6 +54,9 @@ description: Talos gRPC API reference. - [SeccompProfileSpec](#talos.resource.definitions.cri.SeccompProfileSpec) - [resource/definitions/enums/enums.proto](#resource/definitions/enums/enums.proto) + - [BlockFilesystemType](#talos.resource.definitions.enums.BlockFilesystemType) + - [BlockVolumePhase](#talos.resource.definitions.enums.BlockVolumePhase) + - [BlockVolumeType](#talos.resource.definitions.enums.BlockVolumeType) - [KubespanPeerState](#talos.resource.definitions.enums.KubespanPeerState) - [MachineType](#talos.resource.definitions.enums.MachineType) - [NethelpersADSelect](#talos.resource.definitions.enums.NethelpersADSelect) @@ -813,6 +825,53 @@ DiscoveredVolumeSpec is the spec for DiscoveredVolumes status. | type | [string](#string) | | | | device_path | [string](#string) | | | | parent | [string](#string) | | | +| dev_path | [string](#string) | | | +| parent_dev_path | [string](#string) | | | + + + + + + + + +### DiscoveryRefreshRequestSpec +DiscoveryRefreshRequestSpec is the spec for DiscoveryRefreshRequest. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| request | [int64](#int64) | | | + + + + + + + + +### DiscoveryRefreshStatusSpec +DiscoveryRefreshStatusSpec is the spec for DiscoveryRefreshStatus status. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| request | [int64](#int64) | | | + + + + + + + + +### DiskSelector +DiskSelector selects a disk for the volume. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| match | [google.api.expr.v1alpha1.CheckedExpr](#google.api.expr.v1alpha1.CheckedExpr) | | | @@ -840,6 +899,74 @@ DiskSpec is the spec for Disks status. | transport | [string](#string) | | | | rotational | [bool](#bool) | | | | cdrom | [bool](#bool) | | | +| dev_path | [string](#string) | | | + + + + + + + + +### FilesystemSpec +FilesystemSpec is the spec for volume filesystem. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| type | [talos.resource.definitions.enums.BlockFilesystemType](#talos.resource.definitions.enums.BlockFilesystemType) | | | + + + + + + + + +### LocatorSpec +LocatorSpec is the spec for volume locator. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| match | [google.api.expr.v1alpha1.CheckedExpr](#google.api.expr.v1alpha1.CheckedExpr) | | | + + + + + + + + +### PartitionSpec +PartitionSpec is the spec for volume partitioning. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| min_size | [uint64](#uint64) | | | +| max_size | [uint64](#uint64) | | | +| grow | [bool](#bool) | | | +| label | [string](#string) | | | +| type_uuid | [string](#string) | | | + + + + + + + + +### ProvisioningSpec +ProvisioningSpec is the spec for volume provisioning. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| disk_selector | [DiskSelector](#talos.resource.definitions.block.DiskSelector) | | | +| partition_spec | [PartitionSpec](#talos.resource.definitions.block.PartitionSpec) | | | +| wave | [int64](#int64) | | | +| filesystem_spec | [FilesystemSpec](#talos.resource.definitions.block.FilesystemSpec) | | | @@ -860,6 +987,47 @@ SystemDiskSpec is the spec for SystemDisks status. + + + +### VolumeConfigSpec +VolumeConfigSpec is the spec for VolumeConfig resource. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| parent_id | [string](#string) | | | +| type | [talos.resource.definitions.enums.BlockVolumeType](#talos.resource.definitions.enums.BlockVolumeType) | | | +| provisioning | [ProvisioningSpec](#talos.resource.definitions.block.ProvisioningSpec) | | | +| locator | [LocatorSpec](#talos.resource.definitions.block.LocatorSpec) | | | + + + + + + + + +### VolumeStatusSpec +VolumeStatusSpec is the spec for VolumeStatus resource. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| phase | [talos.resource.definitions.enums.BlockVolumePhase](#talos.resource.definitions.enums.BlockVolumePhase) | | | +| location | [string](#string) | | | +| error_message | [string](#string) | | | +| uuid | [string](#string) | | | +| partition_uuid | [string](#string) | | | +| pre_fail_phase | [talos.resource.definitions.enums.BlockVolumePhase](#talos.resource.definitions.enums.BlockVolumePhase) | | | +| parent_location | [string](#string) | | | +| partition_index | [int64](#int64) | | | +| size | [uint64](#uint64) | | | + + + + + @@ -1057,6 +1225,47 @@ SeccompProfileSpec represents the SeccompProfile. + + +### BlockFilesystemType +BlockFilesystemType describes filesystem type. + +| Name | Number | Description | +| ---- | ------ | ----------- | +| FILESYSTEM_TYPE_NONE | 0 | | +| FILESYSTEM_TYPE_XFS | 1 | | + + + + + +### BlockVolumePhase +BlockVolumePhase describes volume phase. + +| Name | Number | Description | +| ---- | ------ | ----------- | +| VOLUME_PHASE_WAITING | 0 | | +| VOLUME_PHASE_READY | 1 | | +| VOLUME_PHASE_FAILED | 2 | | +| VOLUME_PHASE_MISSING | 3 | | +| VOLUME_PHASE_LOCATED | 4 | | +| VOLUME_PHASE_PROVISIONED | 5 | | + + + + + +### BlockVolumeType +BlockVolumeType describes volume type. + +| Name | Number | Description | +| ---- | ------ | ----------- | +| VOLUME_TYPE_PARTITION | 0 | | +| VOLUME_TYPE_DISK | 1 | | +| VOLUME_TYPE_TMPFS | 2 | | + + + ### KubespanPeerState