Merge "Enhance baremetal subcommand to list hosts"
This commit is contained in:
commit
4c82510977
@ -85,6 +85,7 @@ func NewBaremetalCommand(cfgFactory config.Factory) *cobra.Command {
|
|||||||
baremetalRootCmd.AddCommand(NewPowerStatusCommand(cfgFactory, options))
|
baremetalRootCmd.AddCommand(NewPowerStatusCommand(cfgFactory, options))
|
||||||
baremetalRootCmd.AddCommand(NewRebootCommand(cfgFactory, options))
|
baremetalRootCmd.AddCommand(NewRebootCommand(cfgFactory, options))
|
||||||
baremetalRootCmd.AddCommand(NewRemoteDirectCommand(cfgFactory, options))
|
baremetalRootCmd.AddCommand(NewRemoteDirectCommand(cfgFactory, options))
|
||||||
|
baremetalRootCmd.AddCommand(NewListHostsCommand(cfgFactory, options))
|
||||||
|
|
||||||
return baremetalRootCmd
|
return baremetalRootCmd
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,11 @@ func TestBaremetal(t *testing.T) {
|
|||||||
CmdLine: "-h",
|
CmdLine: "-h",
|
||||||
Cmd: baremetal.NewRemoteDirectCommand(nil, &inventory.CommandOptions{}),
|
Cmd: baremetal.NewRemoteDirectCommand(nil, &inventory.CommandOptions{}),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "baremetal-list-hosts-with-help",
|
||||||
|
CmdLine: "-h",
|
||||||
|
Cmd: baremetal.NewListHostsCommand(nil, &inventory.CommandOptions{}),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
58
cmd/baremetal/listhosts.go
Normal file
58
cmd/baremetal/listhosts.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baremetal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"opendev.org/airship/airshipctl/pkg/config"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/inventory"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
listHostsCommand = "list-hosts"
|
||||||
|
listLong = "List bare metal host(s)."
|
||||||
|
listExample = `
|
||||||
|
Retrieve list of baremetal hosts, default output option is 'table'
|
||||||
|
# airshipctl baremetal list-hosts
|
||||||
|
# airshipctl baremetal list-hosts --namespace default
|
||||||
|
# airshipctl baremetal list-hosts --namespace default --output table
|
||||||
|
# airshipctl baremetal list-hosts --output yaml
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewListHostsCommand provides a command to list a remote host.
|
||||||
|
func NewListHostsCommand(cfgFactory config.Factory, options *inventory.CommandOptions) *cobra.Command {
|
||||||
|
l := &inventory.ListHostsCommand{Options: options}
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: listHostsCommand,
|
||||||
|
Short: "Airshipctl command to list bare metal host(s)",
|
||||||
|
Long: listLong,
|
||||||
|
Example: listExample,
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
l.Writer = cmd.OutOrStdout()
|
||||||
|
return l.RunE()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
flags := cmd.Flags()
|
||||||
|
flags.StringVarP(&l.OutputFormat, "output", "o", "table", "output formats. Supported options are 'table' and 'yaml'")
|
||||||
|
flags.StringVarP(&options.Namespace, flagNamespace, flagNamespaceSort, "", flagNamespaceDescription)
|
||||||
|
flags.StringVarP(&options.Labels, flagLabel, flagLabelShort, "", flagLabelDescription)
|
||||||
|
flags.DurationVar(&options.Timeout, flagTimeout, 10*time.Minute, flagTimeoutDescription)
|
||||||
|
return cmd
|
||||||
|
}
|
20
cmd/baremetal/testdata/TestBaremetalGoldenOutput/baremetal-list-hosts-with-help.golden
vendored
Normal file
20
cmd/baremetal/testdata/TestBaremetalGoldenOutput/baremetal-list-hosts-with-help.golden
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
List bare metal host(s).
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
list-hosts [flags]
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
Retrieve list of baremetal hosts, default output option is 'table'
|
||||||
|
# airshipctl baremetal list-hosts
|
||||||
|
# airshipctl baremetal list-hosts --namespace default
|
||||||
|
# airshipctl baremetal list-hosts --namespace default --output table
|
||||||
|
# airshipctl baremetal list-hosts --output yaml
|
||||||
|
|
||||||
|
|
||||||
|
Flags:
|
||||||
|
-h, --help help for list-hosts
|
||||||
|
-l, --labels string label(s) to filter desired bare metal host from site manifest documents
|
||||||
|
-n, --namespace string airshipctl phase that contains the desired bare metal host from site manifest document(s)
|
||||||
|
-o, --output string output formats. Supported options are 'table' and 'yaml' (default "table")
|
||||||
|
--timeout duration timeout on bare metal action (default 10m0s)
|
@ -7,6 +7,7 @@ Usage:
|
|||||||
Available Commands:
|
Available Commands:
|
||||||
ejectmedia Airshipctl command to eject virtual media attached to a bare metal host
|
ejectmedia Airshipctl command to eject virtual media attached to a bare metal host
|
||||||
help Help about any command
|
help Help about any command
|
||||||
|
list-hosts Airshipctl command to list bare metal host(s)
|
||||||
poweroff Airshipctl command to shutdown bare metal host(s)
|
poweroff Airshipctl command to shutdown bare metal host(s)
|
||||||
poweron Airshipctl command to power on host(s)
|
poweron Airshipctl command to power on host(s)
|
||||||
powerstatus Airshipctl command to retrieve the power status of a bare metal host
|
powerstatus Airshipctl command to retrieve the power status of a bare metal host
|
||||||
|
@ -33,6 +33,7 @@ SEE ALSO
|
|||||||
|
|
||||||
* :ref:`airshipctl <airshipctl>` - A unified command line tool for management of end-to-end kubernetes cluster deployment on cloud infrastructure environments.
|
* :ref:`airshipctl <airshipctl>` - A unified command line tool for management of end-to-end kubernetes cluster deployment on cloud infrastructure environments.
|
||||||
* :ref:`airshipctl baremetal ejectmedia <airshipctl_baremetal_ejectmedia>` - Airshipctl command to eject virtual media attached to a bare metal host
|
* :ref:`airshipctl baremetal ejectmedia <airshipctl_baremetal_ejectmedia>` - Airshipctl command to eject virtual media attached to a bare metal host
|
||||||
|
* :ref:`airshipctl baremetal list-hosts <airshipctl_baremetal_list-hosts>` - Airshipctl command to list bare metal host(s)
|
||||||
* :ref:`airshipctl baremetal poweroff <airshipctl_baremetal_poweroff>` - Airshipctl command to shutdown bare metal host(s)
|
* :ref:`airshipctl baremetal poweroff <airshipctl_baremetal_poweroff>` - Airshipctl command to shutdown bare metal host(s)
|
||||||
* :ref:`airshipctl baremetal poweron <airshipctl_baremetal_poweron>` - Airshipctl command to power on host(s)
|
* :ref:`airshipctl baremetal poweron <airshipctl_baremetal_poweron>` - Airshipctl command to power on host(s)
|
||||||
* :ref:`airshipctl baremetal powerstatus <airshipctl_baremetal_powerstatus>` - Airshipctl command to retrieve the power status of a bare metal host
|
* :ref:`airshipctl baremetal powerstatus <airshipctl_baremetal_powerstatus>` - Airshipctl command to retrieve the power status of a bare metal host
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
.. _airshipctl_baremetal_list-hosts:
|
||||||
|
|
||||||
|
airshipctl baremetal list-hosts
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
Airshipctl command to list bare metal host(s)
|
||||||
|
|
||||||
|
Synopsis
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
List bare metal host(s).
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
airshipctl baremetal list-hosts [flags]
|
||||||
|
|
||||||
|
Examples
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
|
||||||
|
Retrieve list of baremetal hosts, default output option is 'table'
|
||||||
|
# airshipctl baremetal list-hosts
|
||||||
|
# airshipctl baremetal list-hosts --namespace default
|
||||||
|
# airshipctl baremetal list-hosts --namespace default --output table
|
||||||
|
# airshipctl baremetal list-hosts --output yaml
|
||||||
|
|
||||||
|
|
||||||
|
Options
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-h, --help help for list-hosts
|
||||||
|
-l, --labels string label(s) to filter desired bare metal host from site manifest documents
|
||||||
|
-n, --namespace string airshipctl phase that contains the desired bare metal host from site manifest document(s)
|
||||||
|
-o, --output string output formats. Supported options are 'table' and 'yaml' (default "table")
|
||||||
|
--timeout duration timeout on bare metal action (default 10m0s)
|
||||||
|
|
||||||
|
Options inherited from parent commands
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
--airshipconf string path to the airshipctl configuration file. Defaults to "$HOME/.airship/config"
|
||||||
|
--debug enable verbose output
|
||||||
|
|
||||||
|
SEE ALSO
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
* :ref:`airshipctl baremetal <airshipctl_baremetal>` - Airshipctl command to manage bare metal host(s)
|
||||||
|
|
@ -7,6 +7,7 @@ baremetal
|
|||||||
|
|
||||||
airshipctl_baremetal
|
airshipctl_baremetal
|
||||||
airshipctl_baremetal_ejectmedia
|
airshipctl_baremetal_ejectmedia
|
||||||
|
airshipctl_baremetal_list-hosts
|
||||||
airshipctl_baremetal_poweroff
|
airshipctl_baremetal_poweroff
|
||||||
airshipctl_baremetal_poweron
|
airshipctl_baremetal_poweron
|
||||||
airshipctl_baremetal_powerstatus
|
airshipctl_baremetal_powerstatus
|
||||||
|
@ -68,6 +68,8 @@ spec:
|
|||||||
required:
|
required:
|
||||||
- isoURL
|
- isoURL
|
||||||
type: object
|
type: object
|
||||||
|
required:
|
||||||
|
- remoteDirect
|
||||||
type: object
|
type: object
|
||||||
timeout:
|
timeout:
|
||||||
description: Timeout in seconds
|
description: Timeout in seconds
|
||||||
|
@ -35,10 +35,6 @@ spec:
|
|||||||
of an object. Servers should convert recognized schemas to the latest
|
of an object. Servers should convert recognized schemas to the latest
|
||||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||||
type: string
|
type: string
|
||||||
env-vars:
|
|
||||||
description: EnvVars if set to true, allows to source variables for cluster-api
|
|
||||||
components for environment variables.
|
|
||||||
type: boolean
|
|
||||||
images:
|
images:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
description: ImageMeta is part of clusterctl config
|
description: ImageMeta is part of clusterctl config
|
||||||
@ -53,66 +49,24 @@ spec:
|
|||||||
description: InitOptions container with exposed clusterctl InitOptions
|
description: InitOptions container with exposed clusterctl InitOptions
|
||||||
properties:
|
properties:
|
||||||
bootstrap-providers:
|
bootstrap-providers:
|
||||||
description: BootstrapProviders and versions (e.g. kubeadm:v0.3.0)
|
description: BootstrapProviders and versions (comma separated, e.g.
|
||||||
to add to the management cluster. If unspecified, the kubeadm bootstrap
|
kubeadm:v0.3.0) to add to the management cluster. If unspecified,
|
||||||
provider's latest release is used.
|
the kubeadm bootstrap provider's latest release is used.
|
||||||
items:
|
type: string
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
control-plane-providers:
|
control-plane-providers:
|
||||||
description: ControlPlaneProviders and versions (e.g. kubeadm:v0.3.0)
|
description: ControlPlaneProviders and versions (comma separated,
|
||||||
to add to the management cluster. If unspecified, the kubeadm control
|
e.g. kubeadm:v0.3.0) to add to the management cluster. If unspecified,
|
||||||
plane provider latest release is used.
|
the kubeadm control plane provider latest release is used.
|
||||||
items:
|
type: string
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
core-provider:
|
core-provider:
|
||||||
description: CoreProvider version (e.g. cluster-api:v0.3.0) to add
|
description: CoreProvider version (e.g. cluster-api:v0.3.0) to add
|
||||||
to the management cluster. If unspecified, the cluster-api core
|
to the management cluster. If unspecified, the cluster-api core
|
||||||
provider's latest release is used.
|
provider's latest release is used.
|
||||||
type: string
|
type: string
|
||||||
infrastructure-providers:
|
infrastructure-providers:
|
||||||
description: InfrastructureProviders and versions (e.g. aws:v0.5.0)
|
description: InfrastructureProviders and versions (comma separated,
|
||||||
to add to the management cluster.
|
e.g. aws:v0.5.0,metal3:v0.4.0) to add to the management cluster.
|
||||||
items:
|
type: string
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
kubeConfigRef:
|
|
||||||
description: KubeConfigRef reference to KubeConfig document
|
|
||||||
properties:
|
|
||||||
apiVersion:
|
|
||||||
description: API version of the referent.
|
|
||||||
type: string
|
|
||||||
fieldPath:
|
|
||||||
description: 'If referring to a piece of an object instead of
|
|
||||||
an entire object, this string should contain a valid JSON/Go
|
|
||||||
field access statement, such as desiredState.manifest.containers[2].
|
|
||||||
For example, if the object reference is to a container within
|
|
||||||
a pod, this would take on a value like: "spec.containers{name}"
|
|
||||||
(where "name" refers to the name of the container that triggered
|
|
||||||
the event) or if no container name is specified "spec.containers[2]"
|
|
||||||
(container with index 2 in this pod). This syntax is chosen
|
|
||||||
only to have some well-defined way of referencing a part of
|
|
||||||
an object. TODO: this design is not final and this field is
|
|
||||||
subject to change in the future.'
|
|
||||||
type: string
|
|
||||||
kind:
|
|
||||||
description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
|
||||||
type: string
|
|
||||||
name:
|
|
||||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
|
|
||||||
type: string
|
|
||||||
namespace:
|
|
||||||
description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
|
|
||||||
type: string
|
|
||||||
resourceVersion:
|
|
||||||
description: 'Specific resourceVersion to which this reference
|
|
||||||
is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
|
|
||||||
type: string
|
|
||||||
uid:
|
|
||||||
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
type: object
|
type: object
|
||||||
kind:
|
kind:
|
||||||
description: 'Kind is a string value representing the REST resource this
|
description: 'Kind is a string value representing the REST resource this
|
||||||
@ -125,39 +79,22 @@ spec:
|
|||||||
description: MoveOptions carries the options supported by move.
|
description: MoveOptions carries the options supported by move.
|
||||||
properties:
|
properties:
|
||||||
namespace:
|
namespace:
|
||||||
description: The namespace where the workload cluster is hosted. If
|
description: Namespace where the objects describing the workload cluster
|
||||||
unspecified, the target context's namespace is used.
|
exists. If unspecified, the current namespace will be used.
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
providers:
|
providers:
|
||||||
items:
|
items:
|
||||||
description: Provider is part of clusterctl config
|
description: Provider is part of clusterctl config
|
||||||
properties:
|
properties:
|
||||||
clusterctl-repository:
|
|
||||||
description: IsClusterctlRepository if set to true, clusterctl provider's
|
|
||||||
repository implementation will be used if omitted or set to false,
|
|
||||||
airshipctl repository implementation will be used.
|
|
||||||
type: boolean
|
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
type:
|
type:
|
||||||
type: string
|
type: string
|
||||||
url:
|
url:
|
||||||
|
description: URL can contain remote URL of upstream Provider or
|
||||||
|
relative to target path of the manifest
|
||||||
type: string
|
type: string
|
||||||
variable-substitution:
|
|
||||||
description: VariableSubstitution indicates weather you want to
|
|
||||||
substitute variables in the cluster-api manifests if set to true,
|
|
||||||
variables will be substituted only if they are defined either
|
|
||||||
in Environment or in AdditionalComponentVariables, if not they
|
|
||||||
will be left as is.
|
|
||||||
type: boolean
|
|
||||||
versions:
|
|
||||||
additionalProperties:
|
|
||||||
type: string
|
|
||||||
description: Map of versions where each key is a version and value
|
|
||||||
is path relative to target path of the manifest ignored if IsClusterctlRepository
|
|
||||||
is set to true
|
|
||||||
type: object
|
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
- type
|
- type
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.6.1
|
||||||
|
creationTimestamp: null
|
||||||
|
name: hosts.airshipit.org
|
||||||
|
spec:
|
||||||
|
group: airshipit.org
|
||||||
|
names:
|
||||||
|
kind: Host
|
||||||
|
listKind: HostList
|
||||||
|
plural: hosts
|
||||||
|
singular: host
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
description: Host object to represent baremetal host
|
||||||
|
properties:
|
||||||
|
apiVersion:
|
||||||
|
description: 'APIVersion defines the versioned schema of this representation
|
||||||
|
of an object. Servers should convert recognized schemas to the latest
|
||||||
|
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: 'Kind is a string value representing the REST resource this
|
||||||
|
object represents. Servers may infer this from the endpoint the client
|
||||||
|
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||||
|
type: string
|
||||||
|
metadata:
|
||||||
|
type: object
|
||||||
|
nodeid:
|
||||||
|
type: string
|
||||||
|
nodename:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- nodeid
|
||||||
|
- nodename
|
||||||
|
type: object
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
status:
|
||||||
|
acceptedNames:
|
||||||
|
kind: ""
|
||||||
|
plural: ""
|
||||||
|
conditions: []
|
||||||
|
storedVersions: []
|
@ -51,6 +51,11 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
group:
|
group:
|
||||||
type: string
|
type: string
|
||||||
|
isClusterScoped:
|
||||||
|
description: isClusterScoped is true if the object is known,
|
||||||
|
per the openapi data in use, to be cluster scoped, and false
|
||||||
|
otherwise.
|
||||||
|
type: boolean
|
||||||
kind:
|
kind:
|
||||||
type: string
|
type: string
|
||||||
labelSelector:
|
labelSelector:
|
||||||
@ -59,8 +64,11 @@ spec:
|
|||||||
It matches with the resource labels.
|
It matches with the resource labels.
|
||||||
type: string
|
type: string
|
||||||
name:
|
name:
|
||||||
|
description: Name of the resource.
|
||||||
type: string
|
type: string
|
||||||
namespace:
|
namespace:
|
||||||
|
description: Namespace the resource belongs to, if it can
|
||||||
|
belong to a namespace.
|
||||||
type: string
|
type: string
|
||||||
version:
|
version:
|
||||||
type: string
|
type: string
|
||||||
@ -90,6 +98,11 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
group:
|
group:
|
||||||
type: string
|
type: string
|
||||||
|
isClusterScoped:
|
||||||
|
description: isClusterScoped is true if the object is known,
|
||||||
|
per the openapi data in use, to be cluster scoped, and false
|
||||||
|
otherwise.
|
||||||
|
type: boolean
|
||||||
kind:
|
kind:
|
||||||
type: string
|
type: string
|
||||||
labelSelector:
|
labelSelector:
|
||||||
@ -98,8 +111,11 @@ spec:
|
|||||||
It matches with the resource labels.
|
It matches with the resource labels.
|
||||||
type: string
|
type: string
|
||||||
name:
|
name:
|
||||||
|
description: Name of the resource.
|
||||||
type: string
|
type: string
|
||||||
namespace:
|
namespace:
|
||||||
|
description: Namespace the resource belongs to, if it can
|
||||||
|
belong to a namespace.
|
||||||
type: string
|
type: string
|
||||||
version:
|
version:
|
||||||
type: string
|
type: string
|
||||||
|
@ -75,10 +75,27 @@ spec:
|
|||||||
for the server's certificate. This will make your HTTPS
|
for the server's certificate. This will make your HTTPS
|
||||||
connections insecure.
|
connections insecure.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
proxy-url:
|
||||||
|
description: "ProxyURL is the URL to the proxy to be used
|
||||||
|
for all requests made by this client. URLs with \"http\",
|
||||||
|
\"https\", and \"socks5\" schemes are supported. If this
|
||||||
|
configuration is not provided or the empty string, the
|
||||||
|
client attempts to construct a proxy configuration from
|
||||||
|
http_proxy and https_proxy environment variables. If these
|
||||||
|
environment variables are not set, the client does not
|
||||||
|
attempt to proxy requests. \n socks5 proxying does not
|
||||||
|
currently support spdy streaming endpoints (exec, attach,
|
||||||
|
port forward)."
|
||||||
|
type: string
|
||||||
server:
|
server:
|
||||||
description: Server is the address of the kubernetes cluster
|
description: Server is the address of the kubernetes cluster
|
||||||
(https://hostname:port).
|
(https://hostname:port).
|
||||||
type: string
|
type: string
|
||||||
|
tls-server-name:
|
||||||
|
description: TLSServerName is used to check server certificate.
|
||||||
|
If TLSServerName is empty, the hostname used to contact
|
||||||
|
the server is used.
|
||||||
|
type: string
|
||||||
required:
|
required:
|
||||||
- server
|
- server
|
||||||
type: object
|
type: object
|
||||||
@ -288,8 +305,24 @@ spec:
|
|||||||
- value
|
- value
|
||||||
type: object
|
type: object
|
||||||
type: array
|
type: array
|
||||||
|
installHint:
|
||||||
|
description: This text is shown to the user when the
|
||||||
|
executable doesn't seem to be present. For example,
|
||||||
|
`brew install foo-cli` might be a good InstallHint
|
||||||
|
for foo-cli on Mac OS systems.
|
||||||
|
type: string
|
||||||
|
provideClusterInfo:
|
||||||
|
description: ProvideClusterInfo determines whether or
|
||||||
|
not to provide cluster information, which could potentially
|
||||||
|
contain very large CA data, to this exec plugin as
|
||||||
|
a part of the KUBERNETES_EXEC_INFO environment variable.
|
||||||
|
By default, it is set to false. Package k8s.io/client-go/tools/auth/exec
|
||||||
|
provides helper methods for reading this environment
|
||||||
|
variable.
|
||||||
|
type: boolean
|
||||||
required:
|
required:
|
||||||
- command
|
- command
|
||||||
|
- provideClusterInfo
|
||||||
type: object
|
type: object
|
||||||
extensions:
|
extensions:
|
||||||
description: Extensions holds additional information. This
|
description: Extensions holds additional information. This
|
||||||
|
@ -31,6 +31,16 @@ spec:
|
|||||||
description: ApplyConfig provides instructions on how to apply resources
|
description: ApplyConfig provides instructions on how to apply resources
|
||||||
to kubernetes cluster
|
to kubernetes cluster
|
||||||
properties:
|
properties:
|
||||||
|
context:
|
||||||
|
type: string
|
||||||
|
debug:
|
||||||
|
type: boolean
|
||||||
|
druRun:
|
||||||
|
type: boolean
|
||||||
|
kubeconfig:
|
||||||
|
type: string
|
||||||
|
phaseName:
|
||||||
|
type: string
|
||||||
pruneOptions:
|
pruneOptions:
|
||||||
description: ApplyPruneOptions provides instructions how to prune
|
description: ApplyPruneOptions provides instructions how to prune
|
||||||
for kubernetes resources
|
for kubernetes resources
|
||||||
@ -42,6 +52,35 @@ spec:
|
|||||||
description: ApplyWaitOptions provides instructions how to wait for
|
description: ApplyWaitOptions provides instructions how to wait for
|
||||||
kubernetes resources
|
kubernetes resources
|
||||||
properties:
|
properties:
|
||||||
|
conditions:
|
||||||
|
items:
|
||||||
|
description: Condition is a jsonpath for particular TypeMeta
|
||||||
|
which indicates what state to wait
|
||||||
|
properties:
|
||||||
|
apiVersion:
|
||||||
|
description: 'APIVersion defines the versioned schema of
|
||||||
|
this representation of an object. Servers should convert
|
||||||
|
recognized schemas to the latest internal value, and may
|
||||||
|
reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||||
|
type: string
|
||||||
|
jsonPath:
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: 'Kind is a string value representing the REST
|
||||||
|
resource this object represents. Servers may infer this
|
||||||
|
from the endpoint the client submits requests to. Cannot
|
||||||
|
be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||||
|
type: string
|
||||||
|
value:
|
||||||
|
description: Value is desired state to wait for, if no value
|
||||||
|
specified - just existence of provided jsonPath will be
|
||||||
|
checked
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
pollInterval:
|
||||||
|
description: PollInterval in seconds
|
||||||
|
type: integer
|
||||||
timeout:
|
timeout:
|
||||||
description: Timeout in seconds
|
description: Timeout in seconds
|
||||||
type: integer
|
type: integer
|
||||||
|
@ -34,8 +34,30 @@ spec:
|
|||||||
documentEntryPoint:
|
documentEntryPoint:
|
||||||
type: string
|
type: string
|
||||||
executorRef:
|
executorRef:
|
||||||
description: ObjectReference contains enough information to let you
|
description: 'ObjectReference contains enough information to let you
|
||||||
inspect or modify the referred object.
|
inspect or modify the referred object. --- New uses of this type
|
||||||
|
are discouraged because of difficulty describing its usage when
|
||||||
|
embedded in APIs. 1. Ignored fields. It includes many fields which
|
||||||
|
are not generally honored. For instance, ResourceVersion and FieldPath
|
||||||
|
are both very rarely valid in actual usage. 2. Invalid usage help. It
|
||||||
|
is impossible to add specific help for individual usage. In most
|
||||||
|
embedded usages, there are particular restrictions like, "must
|
||||||
|
refer only to types A and B" or "UID not honored" or "name must
|
||||||
|
be restricted". Those cannot be well described when embedded. 3.
|
||||||
|
Inconsistent validation. Because the usages are different, the
|
||||||
|
validation rules are different by usage, which makes it hard for
|
||||||
|
users to predict what will happen. 4. The fields are both imprecise
|
||||||
|
and overly precise. Kind is not a precise mapping to a URL. This
|
||||||
|
can produce ambiguity during interpretation and require a REST
|
||||||
|
mapping. In most cases, the dependency is on the group,resource
|
||||||
|
tuple and the version of the actual struct is irrelevant. 5.
|
||||||
|
We cannot easily change it. Because this type is embedded in many
|
||||||
|
locations, updates to this type will affect numerous schemas. Don''t
|
||||||
|
make new APIs embed an underspecified API type they do not control.
|
||||||
|
Instead of using this type, create a locally provided and used type
|
||||||
|
that is well-focused on your reference. For example, ServiceReferences
|
||||||
|
for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533
|
||||||
|
.'
|
||||||
properties:
|
properties:
|
||||||
apiVersion:
|
apiVersion:
|
||||||
description: API version of the referent.
|
description: API version of the referent.
|
||||||
|
@ -98,8 +98,11 @@ spec:
|
|||||||
It matches with the resource labels.
|
It matches with the resource labels.
|
||||||
type: string
|
type: string
|
||||||
name:
|
name:
|
||||||
|
description: Name of the resource.
|
||||||
type: string
|
type: string
|
||||||
namespace:
|
namespace:
|
||||||
|
description: Namespace the resource belongs to, if it can
|
||||||
|
belong to a namespace.
|
||||||
type: string
|
type: string
|
||||||
version:
|
version:
|
||||||
type: string
|
type: string
|
||||||
@ -133,8 +136,11 @@ spec:
|
|||||||
It matches with the resource labels.
|
It matches with the resource labels.
|
||||||
type: string
|
type: string
|
||||||
name:
|
name:
|
||||||
|
description: Name of the resource.
|
||||||
type: string
|
type: string
|
||||||
namespace:
|
namespace:
|
||||||
|
description: Namespace the resource belongs to, if it
|
||||||
|
can belong to a namespace.
|
||||||
type: string
|
type: string
|
||||||
version:
|
version:
|
||||||
type: string
|
type: string
|
||||||
|
@ -83,9 +83,9 @@ spec:
|
|||||||
description: capi_images defines collections of images used by cluster
|
description: capi_images defines collections of images used by cluster
|
||||||
API. The name of each key in this section should correspond to the
|
API. The name of each key in this section should correspond to the
|
||||||
airshipctl function in which the images will be used, such as "capm3".
|
airshipctl function in which the images will be used, such as "capm3".
|
||||||
Each capi_image object must have a "manager" object, which must have
|
Each capi_image object must have a "manager" object, which must
|
||||||
"repository" and "tag" properties defined. capi_images may also include
|
have "repository" and "tag" properties defined. capi_images may
|
||||||
an optional "ipam-manager" or "auth_proxy" object,
|
also include an optional "ipam-manager" or "auth_proxy" object,
|
||||||
which must also have "repository" and "tag" properties defined.
|
which must also have "repository" and "tag" properties defined.
|
||||||
type: object
|
type: object
|
||||||
charts:
|
charts:
|
||||||
|
37
pkg/api/v1alpha1/host_types.go
Normal file
37
pkg/api/v1alpha1/host_types.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package v1alpha1
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
|
// Host object to represent baremetal host
|
||||||
|
type Host struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
NodeName string `json:"nodename"`
|
||||||
|
NodeID string `json:"nodeid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultHost can be used to safely unmarshal phase object without nil pointers
|
||||||
|
func DefaultHost() *Host {
|
||||||
|
return &Host{
|
||||||
|
NodeName: "defaultName",
|
||||||
|
NodeID: "defaultID",
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
//go:build !ignore_autogenerated
|
||||||
// +build !ignore_autogenerated
|
// +build !ignore_autogenerated
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -708,6 +709,31 @@ func (in *Gvk) DeepCopy() *Gvk {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *Host) DeepCopyInto(out *Host) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Host.
|
||||||
|
func (in *Host) DeepCopy() *Host {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(Host)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *Host) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *HostNetworkingSpec) DeepCopyInto(out *HostNetworkingSpec) {
|
func (in *HostNetworkingSpec) DeepCopyInto(out *HostNetworkingSpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -149,7 +149,9 @@ func (i Inventory) newHost(doc document.Document) (Host, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := clientFactory(
|
nodeName := doc.GetName()
|
||||||
|
|
||||||
|
client, err := clientFactory(nodeName,
|
||||||
address,
|
address,
|
||||||
i.mgmtCfg.Insecure,
|
i.mgmtCfg.Insecure,
|
||||||
i.mgmtCfg.UseProxy,
|
i.mgmtCfg.UseProxy,
|
||||||
|
@ -20,8 +20,18 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||||
"opendev.org/airship/airshipctl/pkg/inventory/ifc"
|
"opendev.org/airship/airshipctl/pkg/inventory/ifc"
|
||||||
remoteifc "opendev.org/airship/airshipctl/pkg/remote/ifc"
|
remoteifc "opendev.org/airship/airshipctl/pkg/remote/ifc"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/util"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/util/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TableOutputFormat table
|
||||||
|
TableOutputFormat = "table"
|
||||||
|
// YamlOutputFormat yaml
|
||||||
|
YamlOutputFormat = "yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CommandOptions is used to store common variables from cmd flags for baremetal command group
|
// CommandOptions is used to store common variables from cmd flags for baremetal command group
|
||||||
@ -37,6 +47,18 @@ type CommandOptions struct {
|
|||||||
Inventory ifc.Inventory
|
Inventory ifc.Inventory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListHostsCommand is used to store common variables from cmd flags for list-hots command
|
||||||
|
type ListHostsCommand struct {
|
||||||
|
Writer io.Writer
|
||||||
|
Options *CommandOptions
|
||||||
|
OutputFormat string
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewListHostsCommand ListHostsCommand constructor
|
||||||
|
func NewListHostsCommand(options *CommandOptions) *ListHostsCommand {
|
||||||
|
return &ListHostsCommand{Options: options}
|
||||||
|
}
|
||||||
|
|
||||||
// NewOptions options constructor
|
// NewOptions options constructor
|
||||||
func NewOptions(i ifc.Inventory) *CommandOptions {
|
func NewOptions(i ifc.Inventory) *CommandOptions {
|
||||||
return &CommandOptions{
|
return &CommandOptions{
|
||||||
@ -61,6 +83,22 @@ func (o *CommandOptions) validateSingleHostAction() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//RunE method returns list of hots from BaremetalInventory
|
||||||
|
func (l *ListHostsCommand) RunE() error {
|
||||||
|
if l.OutputFormat != TableOutputFormat && l.OutputFormat != YamlOutputFormat {
|
||||||
|
return ErrInvalidOptions{Message: "output formats. Supported options are 'table' and 'yaml'"}
|
||||||
|
}
|
||||||
|
|
||||||
|
hostClients, err := l.Options.getAllHost()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(hostClients) == 0 {
|
||||||
|
return fmt.Errorf("No hosts present in the hostInventory")
|
||||||
|
}
|
||||||
|
return l.Write(hostClients)
|
||||||
|
}
|
||||||
|
|
||||||
// BMHAction performs an action against BaremetalHost objects
|
// BMHAction performs an action against BaremetalHost objects
|
||||||
func (o *CommandOptions) BMHAction(op ifc.BaremetalOperation) error {
|
func (o *CommandOptions) BMHAction(op ifc.BaremetalOperation) error {
|
||||||
if err := o.validateBMHAction(); err != nil {
|
if err := o.validateBMHAction(); err != nil {
|
||||||
@ -124,9 +162,32 @@ func (o *CommandOptions) getHost() (remoteifc.Client, error) {
|
|||||||
return bmhInventory.SelectOne(o.selector())
|
return bmhInventory.SelectOne(o.selector())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *CommandOptions) getAllHost() ([]remoteifc.Client, error) {
|
||||||
|
bmhInventory, err := o.Inventory.BaremetalInventory()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return bmhInventory.Select(o.selector())
|
||||||
|
}
|
||||||
|
|
||||||
func (o *CommandOptions) selector() ifc.BaremetalHostSelector {
|
func (o *CommandOptions) selector() ifc.BaremetalHostSelector {
|
||||||
return (ifc.BaremetalHostSelector{}).
|
return (ifc.BaremetalHostSelector{}).
|
||||||
ByLabel(o.Labels).
|
ByLabel(o.Labels).
|
||||||
ByName(o.Name).
|
ByName(o.Name).
|
||||||
ByNamespace(o.Namespace)
|
ByNamespace(o.Namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *ListHostsCommand) Write(clients []remoteifc.Client) error {
|
||||||
|
hostList := []*v1alpha1.Host{}
|
||||||
|
for _, client := range clients {
|
||||||
|
host := v1alpha1.DefaultHost()
|
||||||
|
host.NodeID = client.NodeID()
|
||||||
|
host.NodeName = client.NodeName()
|
||||||
|
hostList = append(hostList, host)
|
||||||
|
}
|
||||||
|
if l.OutputFormat == YamlOutputFormat {
|
||||||
|
return yaml.WriteOut(l.Writer, hostList)
|
||||||
|
}
|
||||||
|
return util.PrintObjects(hostList, util.HostListFormat, l.Writer, false)
|
||||||
|
}
|
||||||
|
@ -24,13 +24,68 @@ import (
|
|||||||
|
|
||||||
"opendev.org/airship/airshipctl/pkg/inventory"
|
"opendev.org/airship/airshipctl/pkg/inventory"
|
||||||
"opendev.org/airship/airshipctl/pkg/inventory/ifc"
|
"opendev.org/airship/airshipctl/pkg/inventory/ifc"
|
||||||
|
remoteifc "opendev.org/airship/airshipctl/pkg/remote/ifc"
|
||||||
"opendev.org/airship/airshipctl/pkg/remote/power"
|
"opendev.org/airship/airshipctl/pkg/remote/power"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/remote/redfish"
|
||||||
mockinventory "opendev.org/airship/airshipctl/testutil/inventory"
|
mockinventory "opendev.org/airship/airshipctl/testutil/inventory"
|
||||||
"opendev.org/airship/airshipctl/testutil/redfishutils"
|
"opendev.org/airship/airshipctl/testutil/redfishutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const testNode = "node-0"
|
const testNode = "node-0"
|
||||||
|
|
||||||
|
func TestListHostsCommand(t *testing.T) {
|
||||||
|
t.Run("success ListHosts", func(t *testing.T) {
|
||||||
|
var hosts []remoteifc.Client
|
||||||
|
|
||||||
|
c1, err := redfish.ClientFactory("node-0", "redfish+http://nolocalhost:32201/redfish/v1/Systems/node00",
|
||||||
|
true, true, "username", "password", 6, 300)
|
||||||
|
if err != nil {
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
}
|
||||||
|
c2, err := redfish.ClientFactory("node-1", "redfish+http://nolocalhost:32201/redfish/v1/Systems/node01",
|
||||||
|
true, true, "username", "password", 6, 300)
|
||||||
|
if err != nil {
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hosts = append(hosts, c1, c2)
|
||||||
|
|
||||||
|
bmhInv := &mockinventory.MockBMHInventory{}
|
||||||
|
bmhInv.On("Select").Return(hosts, nil)
|
||||||
|
|
||||||
|
inv := &mockinventory.MockInventory{}
|
||||||
|
inv.On("BaremetalInventory").Once().Return(bmhInv, nil)
|
||||||
|
|
||||||
|
co := inventory.NewOptions(inv)
|
||||||
|
l := inventory.NewListHostsCommand(co)
|
||||||
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
l.Writer = buf
|
||||||
|
l.OutputFormat = "yaml"
|
||||||
|
actualErr := l.RunE()
|
||||||
|
assert.Equal(t, nil, actualErr)
|
||||||
|
assert.Contains(t, buf.String(), "node-0")
|
||||||
|
assert.Contains(t, buf.String(), "node-1")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("error ListHosts", func(t *testing.T) {
|
||||||
|
expectedErr := fmt.Errorf("No hosts present in the hostInventory")
|
||||||
|
var hosts []remoteifc.Client
|
||||||
|
|
||||||
|
bmhInv := &mockinventory.MockBMHInventory{}
|
||||||
|
bmhInv.On("Select").Return(hosts, nil)
|
||||||
|
|
||||||
|
inv := &mockinventory.MockInventory{}
|
||||||
|
inv.On("BaremetalInventory").Once().Return(bmhInv, nil)
|
||||||
|
|
||||||
|
co := inventory.NewOptions(inv)
|
||||||
|
l := inventory.NewListHostsCommand(co)
|
||||||
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
l.Writer = buf
|
||||||
|
l.OutputFormat = "yaml"
|
||||||
|
actualErr := l.RunE()
|
||||||
|
assert.Equal(t, expectedErr, actualErr)
|
||||||
|
})
|
||||||
|
}
|
||||||
func TestCommandOptions(t *testing.T) {
|
func TestCommandOptions(t *testing.T) {
|
||||||
t.Run("error BMHAction bmh inventory", func(t *testing.T) {
|
t.Run("error BMHAction bmh inventory", func(t *testing.T) {
|
||||||
inv := &mockinventory.MockInventory{}
|
inv := &mockinventory.MockInventory{}
|
||||||
|
@ -44,6 +44,8 @@ const (
|
|||||||
BaremetalOperationPowerOn BaremetalOperation = "power-on"
|
BaremetalOperationPowerOn BaremetalOperation = "power-on"
|
||||||
// BaremetalOperationEjectVirtualMedia eject virtual media
|
// BaremetalOperationEjectVirtualMedia eject virtual media
|
||||||
BaremetalOperationEjectVirtualMedia BaremetalOperation = "eject-virtual-media"
|
BaremetalOperationEjectVirtualMedia BaremetalOperation = "eject-virtual-media"
|
||||||
|
// BaremetalOperationListHosts list hosts
|
||||||
|
BaremetalOperationListHosts BaremetalOperation = "list-hosts"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BaremetalBatchRunOptions are options to be passed to RunOperation, this is to be
|
// BaremetalBatchRunOptions are options to be passed to RunOperation, this is to be
|
||||||
|
3
pkg/inventory/testdata/hosts.yaml
vendored
3
pkg/inventory/testdata/hosts.yaml
vendored
@ -10,4 +10,5 @@ spec:
|
|||||||
bootMACAddress: 00:3b:8b:0c:ec:8b
|
bootMACAddress: 00:3b:8b:0c:ec:8b
|
||||||
bmc:
|
bmc:
|
||||||
address: redfish+http://nolocalhost:32201/redfish/v1/Systems/ephemeral
|
address: redfish+http://nolocalhost:32201/redfish/v1/Systems/ephemeral
|
||||||
credentialsName: node-0-bmc-secret
|
credentialsName: node-0-bmc-secret
|
||||||
|
---
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
type Client interface {
|
type Client interface {
|
||||||
EjectVirtualMedia(context.Context) error
|
EjectVirtualMedia(context.Context) error
|
||||||
NodeID() string
|
NodeID() string
|
||||||
|
NodeName() string
|
||||||
RebootSystem(context.Context) error
|
RebootSystem(context.Context) error
|
||||||
SetBootSourceByType(context.Context) error
|
SetBootSourceByType(context.Context) error
|
||||||
SystemPowerOff(context.Context) error
|
SystemPowerOff(context.Context) error
|
||||||
@ -38,7 +39,7 @@ type Client interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ClientFactory is a function to be used
|
// ClientFactory is a function to be used
|
||||||
type ClientFactory func(
|
type ClientFactory func(name string,
|
||||||
redfishURL string,
|
redfishURL string,
|
||||||
insecure bool, useProxy bool,
|
insecure bool, useProxy bool,
|
||||||
username string, password string,
|
username string, password string,
|
||||||
|
@ -36,6 +36,7 @@ const (
|
|||||||
// Client holds details about a Redfish out-of-band system required for out-of-band management.
|
// Client holds details about a Redfish out-of-band system required for out-of-band management.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
nodeID string
|
nodeID string
|
||||||
|
nodeName string
|
||||||
username string
|
username string
|
||||||
password string
|
password string
|
||||||
redfishURL string
|
redfishURL string
|
||||||
@ -53,6 +54,11 @@ func (c *Client) NodeID() string {
|
|||||||
return c.nodeID
|
return c.nodeID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NodeName retrieves the ephemeral node ID.
|
||||||
|
func (c *Client) NodeName() string {
|
||||||
|
return c.nodeName
|
||||||
|
}
|
||||||
|
|
||||||
// SystemActionRetries returns number of attempts to reach host during reboot process and ejecting virtual media
|
// SystemActionRetries returns number of attempts to reach host during reboot process and ejecting virtual media
|
||||||
func (c *Client) SystemActionRetries() int {
|
func (c *Client) SystemActionRetries() int {
|
||||||
return c.systemActionRetries
|
return c.systemActionRetries
|
||||||
@ -355,7 +361,7 @@ func RemoteDirect(ctx context.Context, isoURL, redfishURL string, c ifc.Client)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewClient returns a client with the capability to make Redfish requests.
|
// NewClient returns a client with the capability to make Redfish requests.
|
||||||
func NewClient(redfishURL string,
|
func NewClient(nodeName string, redfishURL string,
|
||||||
insecure bool,
|
insecure bool,
|
||||||
useProxy bool,
|
useProxy bool,
|
||||||
username string,
|
username string,
|
||||||
@ -410,6 +416,7 @@ func NewClient(redfishURL string,
|
|||||||
|
|
||||||
c := &Client{
|
c := &Client{
|
||||||
nodeID: systemID,
|
nodeID: systemID,
|
||||||
|
nodeName: nodeName,
|
||||||
RedfishAPI: redfishClient.NewAPIClient(cfg).DefaultApi,
|
RedfishAPI: redfishClient.NewAPIClient(cfg).DefaultApi,
|
||||||
RedfishCFG: cfg,
|
RedfishCFG: cfg,
|
||||||
systemActionRetries: systemActionRetries,
|
systemActionRetries: systemActionRetries,
|
||||||
@ -427,13 +434,13 @@ func NewClient(redfishURL string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ClientFactory is a constructor for redfish ifc.Client implementation
|
// ClientFactory is a constructor for redfish ifc.Client implementation
|
||||||
var ClientFactory ifc.ClientFactory = func(redfishURL string,
|
var ClientFactory ifc.ClientFactory = func(nodeName string, redfishURL string,
|
||||||
insecure bool,
|
insecure bool,
|
||||||
useProxy bool,
|
useProxy bool,
|
||||||
username string,
|
username string,
|
||||||
password string,
|
password string,
|
||||||
systemActionRetries int,
|
systemActionRetries int,
|
||||||
systemRebootDelay int) (ifc.Client, error) {
|
systemRebootDelay int) (ifc.Client, error) {
|
||||||
return NewClient(redfishURL, insecure, useProxy,
|
return NewClient(nodeName, redfishURL, insecure, useProxy,
|
||||||
username, password, systemActionRetries, systemRebootDelay)
|
username, password, systemActionRetries, systemRebootDelay)
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
nodeName = "node-0"
|
||||||
nodeID = "System.Embedded.1"
|
nodeID = "System.Embedded.1"
|
||||||
isoPath = "http://localhost:8099/ubuntu-focal.iso"
|
isoPath = "http://localhost:8099/ubuntu-focal.iso"
|
||||||
redfishURL = "redfish+https://localhost:2224/Systems/System.Embedded.1"
|
redfishURL = "redfish+https://localhost:2224/Systems/System.Embedded.1"
|
||||||
@ -39,13 +40,13 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestNewClient(t *testing.T) {
|
func TestNewClient(t *testing.T) {
|
||||||
c, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
c, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, c)
|
assert.NotNil(t, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewClientInterface(t *testing.T) {
|
func TestNewClientInterface(t *testing.T) {
|
||||||
c, err := ClientFactory(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
c, err := ClientFactory(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, c)
|
assert.NotNil(t, c)
|
||||||
}
|
}
|
||||||
@ -53,7 +54,7 @@ func TestNewClientInterface(t *testing.T) {
|
|||||||
func TestNewClientDefaultValues(t *testing.T) {
|
func TestNewClientDefaultValues(t *testing.T) {
|
||||||
sysActRetr := 111
|
sysActRetr := 111
|
||||||
sysRebDel := 999
|
sysRebDel := 999
|
||||||
c, err := NewClient(redfishURL, false, false, "", "", sysActRetr, sysRebDel)
|
c, err := NewClient(nodeName, redfishURL, false, false, "", "", sysActRetr, sysRebDel)
|
||||||
assert.Equal(t, c.systemActionRetries, sysActRetr)
|
assert.Equal(t, c.systemActionRetries, sysActRetr)
|
||||||
assert.Equal(t, c.systemRebootDelay, sysRebDel)
|
assert.Equal(t, c.systemRebootDelay, sysRebDel)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@ -62,7 +63,7 @@ func TestNewClientDefaultValues(t *testing.T) {
|
|||||||
func TestNewClientMissingSystemID(t *testing.T) {
|
func TestNewClientMissingSystemID(t *testing.T) {
|
||||||
badURL := "redfish+https://localhost:2224"
|
badURL := "redfish+https://localhost:2224"
|
||||||
|
|
||||||
_, err := NewClient(badURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
_, err := NewClient(nodeName, badURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
_, ok := err.(ErrRedfishMissingConfig)
|
_, ok := err.(ErrRedfishMissingConfig)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
}
|
}
|
||||||
@ -70,20 +71,20 @@ func TestNewClientMissingSystemID(t *testing.T) {
|
|||||||
func TestNewClientNoRedfishMarking(t *testing.T) {
|
func TestNewClientNoRedfishMarking(t *testing.T) {
|
||||||
url := "https://localhost:2224/Systems/System.Embedded.1"
|
url := "https://localhost:2224/Systems/System.Embedded.1"
|
||||||
|
|
||||||
_, err := NewClient(url, false, false, "", "", systemActionRetries, systemRebootDelay)
|
_, err := NewClient(nodeName, url, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewClientEmptyRedfishURL(t *testing.T) {
|
func TestNewClientEmptyRedfishURL(t *testing.T) {
|
||||||
// Redfish URL cannot be empty when creating a client.
|
// Redfish URL cannot be empty when creating a client.
|
||||||
_, err := NewClient("", false, false, "", "", systemActionRetries, systemRebootDelay)
|
_, err := NewClient(nodeName, "", false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
func TestEjectVirtualMedia(t *testing.T) {
|
func TestEjectVirtualMedia(t *testing.T) {
|
||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries+1, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries+1, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -140,7 +141,7 @@ func TestEjectVirtualMediaRetriesExceeded(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -179,7 +180,7 @@ func TestRebootSystem(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -215,7 +216,7 @@ func TestRebootSystemShutdownError(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -242,7 +243,7 @@ func TestRebootSystemStartupError(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -282,7 +283,7 @@ func TestRebootSystemTimeout(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -310,7 +311,7 @@ func TestSetBootSourceByTypeGetSystemError(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -333,7 +334,7 @@ func TestSetBootSourceByTypeSetSystemError(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -366,7 +367,7 @@ func TestSetBootSourceByTypeBootSourceUnavailable(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
ctx := SetAuth(context.Background(), "", "")
|
ctx := SetAuth(context.Background(), "", "")
|
||||||
@ -404,7 +405,7 @@ func TestSetVirtualMediaEjectExistingMedia(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -450,7 +451,7 @@ func TestSetVirtualMediaEjectExistingMediaFailure(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -486,7 +487,7 @@ func TestSetVirtualMediaGetSystemError(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
ctx := SetAuth(context.Background(), "", "")
|
ctx := SetAuth(context.Background(), "", "")
|
||||||
@ -509,7 +510,7 @@ func TestSetVirtualMediaInsertVirtualMediaError(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
ctx := SetAuth(context.Background(), "", "")
|
ctx := SetAuth(context.Background(), "", "")
|
||||||
@ -545,7 +546,7 @@ func TestSystemPowerOff(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -577,7 +578,7 @@ func TestSystemPowerOffResetSystemError(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -600,7 +601,7 @@ func TestSystemPowerOn(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -633,7 +634,7 @@ func TestSystemPowerOnResetSystemError(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -656,7 +657,7 @@ func TestSystemPowerStatusUnknown(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -678,7 +679,7 @@ func TestSystemPowerStatusOn(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ctx := SetAuth(context.Background(), "", "")
|
ctx := SetAuth(context.Background(), "", "")
|
||||||
@ -701,7 +702,7 @@ func TestSystemPowerStatusOff(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -724,7 +725,7 @@ func TestSystemPowerStatusPoweringOn(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -747,7 +748,7 @@ func TestSystemPowerStatusPoweringOff(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -770,7 +771,7 @@ func TestSystemPowerStatusGetSystemError(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
client.nodeID = nodeID
|
client.nodeID = nodeID
|
||||||
@ -788,7 +789,7 @@ func TestWaitForPowerStateGetSystemFailed(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
ctx := SetAuth(context.Background(), "", "")
|
ctx := SetAuth(context.Background(), "", "")
|
||||||
@ -811,7 +812,7 @@ func TestWaitForPowerStateNoRetries(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
ctx := SetAuth(context.Background(), "", "")
|
ctx := SetAuth(context.Background(), "", "")
|
||||||
@ -837,7 +838,7 @@ func TestWaitForPowerStateWithRetries(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
ctx := SetAuth(context.Background(), "", "")
|
ctx := SetAuth(context.Background(), "", "")
|
||||||
@ -867,7 +868,7 @@ func TestWaitForPowerStateRetriesExceeded(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
ctx := SetAuth(context.Background(), "", "")
|
ctx := SetAuth(context.Background(), "", "")
|
||||||
@ -898,7 +899,7 @@ func TestWaitForPowerStateDifferentPowerState(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
ctx := SetAuth(context.Background(), "", "")
|
ctx := SetAuth(context.Background(), "", "")
|
||||||
@ -923,7 +924,7 @@ func TestWaitForPowerStateDifferentPowerState(t *testing.T) {
|
|||||||
func TestRemoteDirect(t *testing.T) {
|
func TestRemoteDirect(t *testing.T) {
|
||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
|
|
||||||
client, err := NewClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := NewClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
client.RedfishAPI = m
|
client.RedfishAPI = m
|
||||||
|
8
pkg/remote/redfish/vendors/dell/client.go
vendored
8
pkg/remote/redfish/vendors/dell/client.go
vendored
@ -135,14 +135,14 @@ func (c *Client) RemoteDirect(ctx context.Context, isoURL string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newClient returns a client with the capability to make Redfish requests.
|
// newClient returns a client with the capability to make Redfish requests.
|
||||||
func newClient(redfishURL string,
|
func newClient(nodeName string, redfishURL string,
|
||||||
insecure bool,
|
insecure bool,
|
||||||
useProxy bool,
|
useProxy bool,
|
||||||
username string,
|
username string,
|
||||||
password string,
|
password string,
|
||||||
systemActionRetries int,
|
systemActionRetries int,
|
||||||
systemRebootDelay int) (*Client, error) {
|
systemRebootDelay int) (*Client, error) {
|
||||||
genericClient, err := redfish.NewClient(redfishURL, insecure, useProxy, username, password,
|
genericClient, err := redfish.NewClient(nodeName, redfishURL, insecure, useProxy, username, password,
|
||||||
systemActionRetries, systemRebootDelay)
|
systemActionRetries, systemRebootDelay)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -154,13 +154,13 @@ func newClient(redfishURL string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ClientFactory is a constructor for redfish ifc.Client implementation
|
// ClientFactory is a constructor for redfish ifc.Client implementation
|
||||||
var ClientFactory ifc.ClientFactory = func(redfishURL string,
|
var ClientFactory ifc.ClientFactory = func(nodeName, redfishURL string,
|
||||||
insecure bool,
|
insecure bool,
|
||||||
useProxy bool,
|
useProxy bool,
|
||||||
username string,
|
username string,
|
||||||
password string,
|
password string,
|
||||||
systemActionRetries int,
|
systemActionRetries int,
|
||||||
systemRebootDelay int) (ifc.Client, error) {
|
systemRebootDelay int) (ifc.Client, error) {
|
||||||
return newClient(redfishURL, insecure, useProxy,
|
return newClient(nodeName, redfishURL, insecure, useProxy,
|
||||||
username, password, systemActionRetries, systemRebootDelay)
|
username, password, systemActionRetries, systemRebootDelay)
|
||||||
}
|
}
|
||||||
|
@ -28,18 +28,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
nodeName = "node-0"
|
||||||
redfishURL = "redfish+https://localhost/Systems/System.Embedded.1"
|
redfishURL = "redfish+https://localhost/Systems/System.Embedded.1"
|
||||||
systemActionRetries = 0
|
systemActionRetries = 0
|
||||||
systemRebootDelay = 0
|
systemRebootDelay = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewClient(t *testing.T) {
|
func TestNewClient(t *testing.T) {
|
||||||
_, err := newClient(redfishURL, false, false, "username", "password", systemActionRetries, systemRebootDelay)
|
_, err := newClient(nodeName, redfishURL, false, false, "username", "password", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewClientInterface(t *testing.T) {
|
func TestNewClientInterface(t *testing.T) {
|
||||||
c, err := ClientFactory(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
c, err := ClientFactory(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, c)
|
assert.NotNil(t, c)
|
||||||
}
|
}
|
||||||
@ -47,7 +48,7 @@ func TestNewClientInterface(t *testing.T) {
|
|||||||
func TestNewClientDefaultValues(t *testing.T) {
|
func TestNewClientDefaultValues(t *testing.T) {
|
||||||
sysActRetr := 222
|
sysActRetr := 222
|
||||||
sysRebDel := 555
|
sysRebDel := 555
|
||||||
c, err := newClient(redfishURL, false, false, "", "", sysActRetr, sysRebDel)
|
c, err := newClient(nodeName, redfishURL, false, false, "", "", sysActRetr, sysRebDel)
|
||||||
assert.Equal(t, c.SystemActionRetries(), sysActRetr)
|
assert.Equal(t, c.SystemActionRetries(), sysActRetr)
|
||||||
assert.Equal(t, c.SystemRebootDelay(), sysRebDel)
|
assert.Equal(t, c.SystemRebootDelay(), sysRebDel)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@ -56,7 +57,7 @@ func TestSetBootSourceByTypeGetSystemError(t *testing.T) {
|
|||||||
m := &redfishMocks.RedfishAPI{}
|
m := &redfishMocks.RedfishAPI{}
|
||||||
defer m.AssertExpectations(t)
|
defer m.AssertExpectations(t)
|
||||||
|
|
||||||
client, err := newClient(redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
client, err := newClient(nodeName, redfishURL, false, false, "", "", systemActionRetries, systemRebootDelay)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
ctx := redfish.SetAuth(context.Background(), "", "")
|
ctx := redfish.SetAuth(context.Background(), "", "")
|
||||||
|
@ -31,6 +31,8 @@ const (
|
|||||||
"EXECUTOR:config.executorRef.kind,DOC ENTRYPOINT:config.documentEntryPoint"
|
"EXECUTOR:config.executorRef.kind,DOC ENTRYPOINT:config.documentEntryPoint"
|
||||||
// PlanListFormat is used to print tables with plan list
|
// PlanListFormat is used to print tables with plan list
|
||||||
PlanListFormat = "NAMESPACE:metadata.namespace,NAME:metadata.name,DESCRIPTION:description"
|
PlanListFormat = "NAMESPACE:metadata.namespace,NAME:metadata.name,DESCRIPTION:description"
|
||||||
|
// HostListFormat is used to print tables with host list
|
||||||
|
HostListFormat = "NodeName:nodename,NodeID:nodeid"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PrintObjects prints suitable
|
// PrintObjects prints suitable
|
||||||
|
@ -24,7 +24,8 @@ import (
|
|||||||
// MockClient is a fake Redfish client for unit testing.
|
// MockClient is a fake Redfish client for unit testing.
|
||||||
type MockClient struct {
|
type MockClient struct {
|
||||||
mock.Mock
|
mock.Mock
|
||||||
nodeID string
|
nodeID string
|
||||||
|
nodeName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeID provides a stubbed method that can be mocked to test functions that use the Redfish client without
|
// NodeID provides a stubbed method that can be mocked to test functions that use the Redfish client without
|
||||||
@ -40,6 +41,19 @@ func (m *MockClient) NodeID() string {
|
|||||||
return args.String(0)
|
return args.String(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NodeName provides a stubbed method that can be mocked to test functions that use the Redfish client without
|
||||||
|
// making any Redfish API calls or requiring the appropriate Redfish client settings.
|
||||||
|
//
|
||||||
|
// Example usage:
|
||||||
|
// client := redfishutils.NewClient()
|
||||||
|
// client.On("NodeName").Return(<return values>)
|
||||||
|
//
|
||||||
|
// err := client.NodeName()
|
||||||
|
func (m *MockClient) NodeName() string {
|
||||||
|
args := m.Called()
|
||||||
|
return args.String(0)
|
||||||
|
}
|
||||||
|
|
||||||
// EjectVirtualMedia provides a stubbed method that can be mocked to test functions that use the
|
// EjectVirtualMedia provides a stubbed method that can be mocked to test functions that use the
|
||||||
// Redfish client without making any Redfish API calls or requiring the appropriate Redfish client
|
// Redfish client without making any Redfish API calls or requiring the appropriate Redfish client
|
||||||
// settings.
|
// settings.
|
||||||
@ -147,7 +161,7 @@ func (m *MockClient) RemoteDirect(ctx context.Context, isoURL string) error {
|
|||||||
|
|
||||||
// NewClient returns a mocked Redfish client in order to test functions that use the Redfish client without making any
|
// NewClient returns a mocked Redfish client in order to test functions that use the Redfish client without making any
|
||||||
// Redfish API calls.
|
// Redfish API calls.
|
||||||
func NewClient(redfishURL string, insecure bool, useProxy bool, username string,
|
func NewClient(nodeName string, redfishURL string, insecure bool, useProxy bool, username string,
|
||||||
password string) (*MockClient, error) {
|
password string) (*MockClient, error) {
|
||||||
if redfishURL == "" {
|
if redfishURL == "" {
|
||||||
return nil, redfish.ErrRedfishMissingConfig{What: "Redfish URL"}
|
return nil, redfish.ErrRedfishMissingConfig{What: "Redfish URL"}
|
||||||
@ -159,6 +173,6 @@ func NewClient(redfishURL string, insecure bool, useProxy bool, username string,
|
|||||||
return nil, redfish.ErrRedfishMissingConfig{What: "management URL system ID"}
|
return nil, redfish.ErrRedfishMissingConfig{What: "management URL system ID"}
|
||||||
}
|
}
|
||||||
|
|
||||||
m := &MockClient{nodeID: systemID}
|
m := &MockClient{nodeID: systemID, nodeName: nodeName}
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user