[botanist] Add support for rebooting over AMT
Bug: IN-353 #comment
Change-Id: If16f88344fd0341693932492b486c7f3c2c6e653
diff --git a/Gopkg.lock b/Gopkg.lock
index 02aaedc..e175ab2 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -2,24 +2,15 @@
[[projects]]
+ digest = "1:4e800c0d846ed856a032380c87b22577ef03c146ccd26203b62ac90ef78e94b1"
name = "cloud.google.com/go"
packages = ["compute/metadata"]
+ pruneopts = ""
revision = "0fd7230b2a7505833d5f69b75cbd6c9582401479"
version = "v0.23.0"
[[projects]]
- name = "github.com/Microsoft/go-winio"
- packages = ["."]
- revision = "7da180ee92d8bd8bb8c37fc560e673e6557c392f"
- version = "v0.4.7"
-
-[[projects]]
- name = "github.com/davecgh/go-spew"
- packages = ["spew"]
- revision = "346938d642f2ec3594ed81d874461961cd0faa76"
- version = "v1.1.0"
-
-[[projects]]
+ digest = "1:f958a1c137db276e52f0b50efee41a1a389dcdded59a69711f3e872757dab34b"
name = "github.com/golang/protobuf"
packages = [
"jsonpb",
@@ -29,73 +20,73 @@
"ptypes/any",
"ptypes/duration",
"ptypes/struct",
- "ptypes/timestamp"
+ "ptypes/timestamp",
]
+ pruneopts = ""
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
version = "v1.1.0"
[[projects]]
branch = "master"
+ digest = "1:b264547c40314ec7619d2cf264e2621953843be7242c140efe1e3119f93877f4"
name = "github.com/google/subcommands"
packages = ["."]
+ pruneopts = ""
revision = "5bae204cdfb2d92dcc333d56014bae6a2f6c58b1"
[[projects]]
+ branch = "master"
+ digest = "1:5247b135b5492aa232a731acdcb52b08f32b874cb398f21ab460396eadbe866b"
+ name = "github.com/google/uuid"
+ packages = ["."]
+ pruneopts = ""
+ revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494"
+ source = "https://fuchsia.googlesource.com/third_party/github.com/google/uuid.git"
+
+[[projects]]
+ digest = "1:3c818dada3e41bdb0f509f78e6775610f1bb179449ec8c4c86a45fae35460f3f"
name = "github.com/julienschmidt/httprouter"
packages = ["."]
+ pruneopts = ""
revision = "8c199fb6259ffc1af525cc3ad52ee60ba8359669"
version = "v1.1"
[[projects]]
- name = "github.com/kr/pretty"
- packages = ["."]
- revision = "73f6ac0b30a98e433b289500d779f50c1a6f0712"
- version = "v0.1.0"
-
-[[projects]]
- name = "github.com/kr/text"
- packages = ["."]
- revision = "e2ffdb16a802fe2bb95e2e35ff34f0e53aeef34f"
- version = "v0.1.0"
-
-[[projects]]
branch = "master"
+ digest = "1:c1a5639af00686cffcaefbc1deafb460f42523bf1810ad13e81a6c956be9da1c"
name = "github.com/maruel/subcommands"
packages = ["."]
+ pruneopts = ""
revision = "8c2c452e1460e1c2d42a8e3a3a527fb09bb68ee2"
[[projects]]
branch = "master"
+ digest = "1:99651e95333755cbe5c9768c1b80031300acca64a80870b40309202b32585a5a"
name = "github.com/mitchellh/go-homedir"
packages = ["."]
+ pruneopts = ""
revision = "3864e76763d94a6df2f9960b16a20a33da9f9a66"
[[projects]]
- name = "github.com/pmezard/go-difflib"
- packages = ["difflib"]
- revision = "792786c7400a136282c1664665ae0a8db921c6c2"
- version = "v1.0.0"
-
-[[projects]]
- name = "github.com/satori/go.uuid"
- packages = ["."]
- revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3"
- version = "v1.2.0"
-
-[[projects]]
- name = "github.com/stretchr/testify"
- packages = ["assert"]
- revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
- version = "v1.2.2"
-
-[[projects]]
branch = "master"
+ digest = "1:ff0671f12ff98386398469e4b44453369fe164563f48ddb6c6b8ce6963379f97"
name = "github.com/texttheater/golang-levenshtein"
packages = ["levenshtein"]
+ pruneopts = ""
revision = "d188e65d659ef53fcdb0691c12f1bba64928b649"
[[projects]]
branch = "master"
+ digest = "1:08f54f35f83370bac9bf1043df718d05ca270f48f5faa5bd8e233b5e69a550f0"
+ name = "github.com/xinsnake/go-http-digest-auth-client"
+ packages = ["."]
+ pruneopts = ""
+ revision = "9da83de55d71220f00cbffb736dba373e6e683b1"
+ source = "https://fuchsia.googlesource.com/third_party/github.com/xinsnake/go-http-digest-auth-client.git"
+
+[[projects]]
+ branch = "master"
+ digest = "1:fbf838a2b217690d144649163c51fa70185c751c6850c38a5698e11d9a91fc4f"
name = "go.chromium.org/luci"
packages = [
"auth",
@@ -107,16 +98,12 @@
"buildbucket/proto",
"common/cli",
"common/clock",
- "common/clock/clockflag",
"common/data/rand/cryptorand",
"common/data/rand/mathrand",
- "common/data/recordio",
"common/data/stringset",
"common/data/strpair",
"common/data/text/indented",
"common/errors",
- "common/flag/flagenum",
- "common/flag/stringmapflag",
"common/gcloud/googleoauth",
"common/gcloud/iam",
"common/iotools",
@@ -136,21 +123,19 @@
"hardcoded/chromeinfra",
"logdog/api/endpoints/coordinator/logs/v1",
"logdog/api/logpb",
- "logdog/client/butlerlib/bootstrap",
- "logdog/client/butlerlib/streamclient",
- "logdog/client/butlerlib/streamproto",
"logdog/client/coordinator",
"logdog/common/fetcher",
"logdog/common/renderer",
"logdog/common/types",
- "logdog/common/viewer",
"lucictx",
- "server/router"
+ "server/router",
]
+ pruneopts = ""
revision = "8acab14f36eb0e48a8521720d30f77deae4a9339"
[[projects]]
branch = "master"
+ digest = "1:5dc6753986b9eeba4abdf05dedc5ba06bb52dad43cc8aad35ffb42bb7adfa68f"
name = "golang.org/x/net"
packages = [
"context",
@@ -160,35 +145,38 @@
"http2/hpack",
"idna",
"internal/timeseries",
- "trace"
+ "trace",
]
+ pruneopts = ""
revision = "db08ff08e8622530d9ed3a0e8ac279f6d4c02196"
source = "https://go.googlesource.com/net.git"
[[projects]]
branch = "master"
+ digest = "1:872a8244645e68541452705451d7183a27781920fd171df927716ed8ce74dbf5"
name = "golang.org/x/oauth2"
packages = [
".",
"google",
"internal",
"jws",
- "jwt"
+ "jwt",
]
+ pruneopts = ""
revision = "113ce6928c4638e14fd5eba69b9e6ec899d5dd83"
source = "https://go.googlesource.com/oauth2.git"
[[projects]]
branch = "master"
+ digest = "1:a8bbf66046a1af68dd81d9d7b12cc9da2d28491fb5632b7757751cada4664444"
name = "golang.org/x/sys"
- packages = [
- "unix",
- "windows"
- ]
+ packages = ["unix"]
+ pruneopts = ""
revision = "fc8bd948cf46f9c7af0f07d34151ce25fe90e477"
source = "https://go.googlesource.com/sys.git"
[[projects]]
+ digest = "1:5acd3512b047305d49e8763eef7ba423901e85d5dd2fd1e71778a0ea8de10bd4"
name = "golang.org/x/text"
packages = [
"collate",
@@ -204,23 +192,27 @@
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
- "unicode/rangetable"
+ "unicode/rangetable",
]
+ pruneopts = ""
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[[projects]]
branch = "master"
+ digest = "1:7d15746ff4df12481c89fd953a28122fa75368fb1fb1bb1fed918a78647b3c3a"
name = "google.golang.org/api"
packages = [
"googleapi",
- "googleapi/internal/uritemplates"
+ "googleapi/internal/uritemplates",
]
+ pruneopts = ""
revision = "2eea9ba0a3d94f6ab46508083e299a00bbbc65f6"
source = "https://code.googlesource.com/google-api-go-client.git"
[[projects]]
branch = "master"
+ digest = "1:b53c1a5bf2a2d0ccf2b3ff9d6563f84f1e70ca04c0db230d19c160f21c481de5"
name = "google.golang.org/appengine"
packages = [
".",
@@ -232,21 +224,25 @@
"internal/modules",
"internal/remote_api",
"internal/urlfetch",
- "urlfetch"
+ "urlfetch",
]
+ pruneopts = ""
revision = "d9a072cfa7b9736e44311ef77b3e09d804bfa599"
source = "https://fuchsia.googlesource.com/third_party/github.com/golang/appengine.git"
[[projects]]
branch = "master"
+ digest = "1:d88c2eb6750028f5707971ed1340a02407d5f0967af85bf6ac70c031533f6c15"
name = "google.golang.org/genproto"
packages = [
"googleapis/rpc/status",
- "protobuf/field_mask"
+ "protobuf/field_mask",
]
+ pruneopts = ""
revision = "32ee49c4dd805befd833990acba36cb75042378c"
[[projects]]
+ digest = "1:dda79c5192c1c59f3f60bbc109a6c710f37e3ebef4d1e7527f586e11ec9ba2af"
name = "google.golang.org/grpc"
packages = [
".",
@@ -272,14 +268,30 @@
"stats",
"status",
"tap",
- "transport"
+ "transport",
]
+ pruneopts = ""
revision = "7a6a684ca69eb4cae85ad0a484f2e531598c047b"
version = "v1.12.2"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
- inputs-digest = "0cce7557b1319b77873a7f01642ecc5f57bd2bdf77640e02b24efc42f2c6e9a3"
+ input-imports = [
+ "github.com/google/subcommands",
+ "github.com/google/uuid",
+ "github.com/xinsnake/go-http-digest-auth-client",
+ "go.chromium.org/luci/auth",
+ "go.chromium.org/luci/auth/client/authcli",
+ "go.chromium.org/luci/buildbucket/proto",
+ "go.chromium.org/luci/grpc/prpc",
+ "go.chromium.org/luci/hardcoded/chromeinfra",
+ "go.chromium.org/luci/logdog/client/coordinator",
+ "go.chromium.org/luci/logdog/common/renderer",
+ "go.chromium.org/luci/logdog/common/types",
+ "go.chromium.org/luci/lucictx",
+ "golang.org/x/sys/unix",
+ "google.golang.org/genproto/protobuf/field_mask",
+ ]
solver-name = "gps-cdcl"
solver-version = 1
diff --git a/Gopkg.toml b/Gopkg.toml
index 1970090..3aace14 100644
--- a/Gopkg.toml
+++ b/Gopkg.toml
@@ -7,6 +7,16 @@
branch = "master"
source = "https://go.googlesource.com/sys.git"
+[[constraint]]
+ name = "github.com/google/uuid"
+ branch = "master"
+ source = "https://fuchsia.googlesource.com/third_party/github.com/google/uuid.git"
+
+[[constraint]]
+ name = "github.com/xinsnake/go-http-digest-auth-client"
+ branch = "master"
+ source = "https://fuchsia.googlesource.com/third_party/github.com/xinsnake/go-http-digest-auth-client.git"
+
[[override]]
name = "golang.org/x/net"
branch = "master"
diff --git a/pdu/amt/amt.go b/pdu/amt/amt.go
new file mode 100644
index 0000000..03e717c
--- /dev/null
+++ b/pdu/amt/amt.go
@@ -0,0 +1,62 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package amt
+
+import (
+ "fmt"
+ "net/url"
+
+ "github.com/google/uuid"
+ dac "github.com/xinsnake/go-http-digest-auth-client"
+)
+
+// Printf string with placeholders for destination uri, message uuid
+const payloadTmpl = `
+<?xml version="1.0" encoding="UTF-8"?>
+<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsman="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:pms="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_PowerManagementService">
+<s:Header>
+ <wsa:Action s:mustUnderstand="true">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_PowerManagementService/RequestPowerStateChange</wsa:Action>
+ <wsa:To s:mustUnderstand="true">%s</wsa:To>
+ <wsman:ResourceURI s:mustUnderstand="true">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_PowerManagementService</wsman:ResourceURI>
+ <wsa:MessageID s:mustUnderstand="true">uuid:%s</wsa:MessageID>
+ <wsa:ReplyTo><wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address></wsa:ReplyTo>
+ <wsman:SelectorSet>
+ <wsman:Selector Name="Name">Intel(r) AMT Power Management Service</wsman:Selector>
+ <wsman:Selector Name="SystemName">Intel(r) AMT</wsman:Selector>
+ <wsman:Selector Name="CreationClassName">CIM_PowerManagementService</wsman:Selector>
+ <wsman:Selector Name="SystemCreationClassName">CIM_ComputerSystem</wsman:Selector>
+ </wsman:SelectorSet>
+</s:Header>
+<s:Body>
+ <pms:RequestPowerStateChange_INPUT>
+ <pms:PowerState>10</pms:PowerState>
+ <pms:ManagedElement>
+ <wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>
+ <wsa:ReferenceParameters>
+ <wsman:ResourceURI>http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ComputerSystem</wsman:ResourceURI>
+ <wsman:SelectorSet>
+ <wsman:Selector Name="Name">ManagedSystem</wsman:Selector>
+ <wsman:Selector Name="CreationClassName">CIM_ComputerSystem</wsman:Selector>
+ </wsman:SelectorSet>
+ </wsa:ReferenceParameters>
+ </pms:ManagedElement>
+ </pms:RequestPowerStateChange_INPUT>
+</s:Body>
+</s:Envelope>
+`
+
+// Reboot sends a Master Bus Reset to an AMT compatible device at host:port.
+func Reboot(host, port, username, password string) error {
+ uri, err := url.Parse(fmt.Sprintf("http://%s:%s/wsman", host, port))
+ if err != nil {
+ return err
+ }
+ // Generate MessageID
+ uuid := uuid.New()
+ payload := fmt.Sprintf(payloadTmpl, uri.String(), uuid)
+ dr := dac.NewRequest(username, password, "POST", uri.String(), payload)
+ _, err = dr.Execute()
+ return nil
+}
diff --git a/pdu/reboot.go b/pdu/reboot.go
index cb53cf0..d99ba50 100644
--- a/pdu/reboot.go
+++ b/pdu/reboot.go
@@ -8,6 +8,7 @@
"net/http"
"strconv"
+ "fuchsia.googlesource.com/infra/infra/pdu/amt"
"fuchsia.googlesource.com/infra/infra/pdu/arduinorelay"
"fuchsia.googlesource.com/infra/infra/pdu/webcardlx"
)
@@ -37,6 +38,8 @@
// RebootDevice uses the given configuration to reboot the device.
func RebootDevice(cfg *Config) error {
switch cfg.Type {
+ case "amt":
+ return amt.Reboot(cfg.Host, cfg.DevicePort, cfg.Username, cfg.Password)
case "arduinorelay":
return arduinorelay.Reboot(cfg.DevicePath, cfg.DevicePort)
case "webcardlx":