Merge pull request #430 in YUNIONIO/onecloud from ~TANGBIN/onecloud:feature/tb-support-aws to release/2.3.0

* commit 'c386f26dd267d931f49c5fbdca98696ed0a1af98': (120 commits)
  add GetAttachDiskStatus
  add more log
  security group add id tag
  security group sync
  upload image
  add aws toHOST_TYPES
  add aws scheduler api
  bugfix
  add host type mapping
  bugfix
  bugfix
  bugfix
  support aws china
  add azure metadatas
  add aliyun tag
  bugfix
  add aws tags
  read aws instance type from file
  add todo
  zone bugfix
  ...
This commit is contained in:
唐斌
2018-11-10 20:07:29 +08:00
1059 changed files with 250563 additions and 62324 deletions
Generated
+217 -122
View File
@@ -79,7 +79,7 @@
version = "v1.19.0"
[[projects]]
digest = "1:5e9ea5618cb3451ce312505a48a563e95ce26c9ef498cd0a8833255e5e7f5c61"
digest = "1:bad9acf125c8b98ea473f45cf8eabee4c401fcd108534b65d2033af7481be25d"
name = "github.com/aliyun/alibaba-cloud-sdk-go"
packages = [
"sdk",
@@ -93,8 +93,8 @@
"sdk/utils",
]
pruneopts = "UT"
revision = "e61479d8220e534e78523e75ff42f92e8d5ac6e1"
version = "1.31.0"
revision = "1d757c22fbf7997c68c43d72e92d462ea05e1439"
version = "0.7.4"
[[projects]]
digest = "1:5a2d4da3f703696f4bec1ba1d363f50461b72934b1817c07ab0963496ed1c90d"
@@ -113,11 +113,57 @@
version = "v1.0.1"
[[projects]]
digest = "1:eee9386329f4fcdf8d6c0def0c9771b634bdd5ba460d888aa98c17d59b37a76c"
digest = "1:e64acfe8cda1955db545ede8e863c54d69f1ac6cd058df4349be4040320840fd"
name = "github.com/apache/thrift"
packages = ["lib/go/thrift"]
pruneopts = "UT"
revision = "e59b73d3c2bf1c328ccb78e683c0462fa1a473c7"
revision = "327ebb6c2b6df8bf075da02ef45a2a034e9b79ba"
version = "0.11.0"
[[projects]]
digest = "1:55bf2a4da68caa693d660683e53bab3e651a940cd46354b997ab68bec7920e23"
name = "github.com/aws/aws-sdk-go"
packages = [
"aws",
"aws/awserr",
"aws/awsutil",
"aws/client",
"aws/client/metadata",
"aws/corehandlers",
"aws/credentials",
"aws/credentials/ec2rolecreds",
"aws/credentials/endpointcreds",
"aws/credentials/stscreds",
"aws/csm",
"aws/defaults",
"aws/ec2metadata",
"aws/endpoints",
"aws/request",
"aws/session",
"aws/signer/v4",
"internal/ini",
"internal/s3err",
"internal/sdkio",
"internal/sdkrand",
"internal/sdkuri",
"internal/shareddefaults",
"private/protocol",
"private/protocol/ec2query",
"private/protocol/eventstream",
"private/protocol/eventstream/eventstreamapi",
"private/protocol/query",
"private/protocol/query/queryutil",
"private/protocol/rest",
"private/protocol/restxml",
"private/protocol/xml/xmlutil",
"service/ec2",
"service/iam",
"service/s3",
"service/sts",
]
pruneopts = "UT"
revision = "cf00ea20983ce38df17ab0a0814463ab8838459f"
version = "v1.15.73"
[[projects]]
branch = "master"
@@ -144,7 +190,7 @@
version = "v0.2.1"
[[projects]]
digest = "1:7205ab9c5433db402268526647efc47daa3236f9a85a1faba705fda12fdafd29"
digest = "1:1c45e98df3726b24a0cc200f5ed182e5eefbe6a8cf2927f9d4335151aa190d15"
name = "github.com/coredns/coredns"
packages = [
"core/dnsserver",
@@ -186,6 +232,7 @@
"plugin/pkg/response",
"plugin/pkg/tls",
"plugin/pkg/trace",
"plugin/pkg/transport",
"plugin/pkg/uniq",
"plugin/pkg/up",
"plugin/pkg/upstream",
@@ -197,8 +244,8 @@
"request",
]
pruneopts = "UT"
revision = "eb51e8bac90fac86d34c9e1cb89b04ea0936b034"
version = "v1.2.2"
revision = "756749c5cad4cd40453b82f70592bc19bb9ccb15"
version = "v1.2.6"
[[projects]]
digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
@@ -258,11 +305,11 @@
[[projects]]
branch = "master"
digest = "1:a76c5e933af8688d9dcfbe718f2b0bfc955208fe0e47e74218b45f1df83ef2ae"
digest = "1:26e2bfc6572da45d1bc22de65cbb4d47bf4ab191279719e7aed71f16b865d7db"
name = "github.com/farsightsec/golang-framestream"
packages = ["."]
pruneopts = "UT"
revision = "d0f7ed81b7afcc56d3c1a66a0fd26a1b609675f3"
revision = "8a0cb8ba87105c2d27e725e48e50ce0b5c521d57"
[[projects]]
digest = "1:865079840386857c809b72ce300be7580cb50d3d3129ce11bf9aa6ca2bc1934a"
@@ -280,14 +327,6 @@
pruneopts = "UT"
revision = "3f9db97f856818214da2e1057f8ad84803971cff"
[[projects]]
digest = "1:2cd7915ab26ede7d95b8749e6b1f933f1c6d5398030684e6505940a10f31cfda"
name = "github.com/ghodss/yaml"
packages = ["."]
pruneopts = "UT"
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:36fe9527deed01d2a317617e59304eb2c4ce9f8a24115bcc5c2e37b3aee5bae4"
@@ -297,16 +336,15 @@
revision = "22d885f9ecc78bf4ee5d72b937e4bbcdc58e8cae"
[[projects]]
digest = "1:ff09f03ca12c4d23c28c596eb0738745e36c1cac111f62f64819210f40607cd2"
digest = "1:ab00ecdc9607692ffd5fb1ac21a9ba2d6cc95bae011f327022c0b1c323d218e2"
name = "github.com/gin-gonic/gin"
packages = [
"binding",
"json",
"render",
]
pruneopts = "UT"
revision = "b869fe1415e4b9eb52f247441830d502aece2d4d"
version = "v1.3.0"
revision = "d459835d2b077e44f7c9b453505ee29881d5d12d"
version = "v1.2"
[[projects]]
digest = "1:31a18dae27a29aa074515e43a443abfd2ba6deb6d69309d8d7ce789c45f34659"
@@ -325,15 +363,15 @@
version = "v1.4.0"
[[projects]]
digest = "1:34e709f36fd4f868fb00dbaf8a6cab4c1ae685832d392874ba9d7c5dec2429d1"
digest = "1:b7a8552c62868d867795b63eaf4f45d3e92d36db82b428e680b9c95a8c33e5b1"
name = "github.com/gogo/protobuf"
packages = [
"proto",
"sortkeys",
]
pruneopts = "UT"
revision = "636bf0302bc95575d69441b25a2603156ffdddf1"
version = "v1.1.1"
revision = "342cbe0a04158f6dcb03ca0079991a51a4248c02"
version = "v0.5"
[[projects]]
digest = "1:94d8c9e3a4954505ca89243e2121180972eecf8e3d160f3b34a48825ddd95cc1"
@@ -361,15 +399,14 @@
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:1ba1d79f2810270045c328ae5d674321db34e3aae468eb4233883b473c5c0467"
digest = "1:2edd2416f89b4e841df0e4a78802ce14d2bc7ad79eba1a45986e39f0f8cb7d87"
name = "github.com/golang/glog"
packages = ["."]
pruneopts = "UT"
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
revision = "44145f04b68cf362d9c4df2182967c2275eaefed"
[[projects]]
digest = "1:4c0989ca0bcd10799064318923b9bc2db6b4d6338dd75f3f2d86c3511aaaf5cf"
digest = "1:17fe264ee908afc795734e8c4e63db2accabaf57326dbf21763a7d6b86096260"
name = "github.com/golang/protobuf"
packages = [
"proto",
@@ -379,8 +416,8 @@
"ptypes/timestamp",
]
pruneopts = "UT"
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
version = "v1.2.0"
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
version = "v1.1.0"
[[projects]]
branch = "master"
@@ -399,23 +436,21 @@
revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306"
[[projects]]
branch = "master"
digest = "1:3ee90c0d94da31b442dde97c99635aaafec68d0b8a3c12ee2075c6bdabeec6bb"
digest = "1:41bfd4219241b7f7d6e6fdb13fc712576f1337e68e6b895136283b76928fdd66"
name = "github.com/google/gofuzz"
packages = ["."]
pruneopts = "UT"
revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1"
revision = "44d81051d367757e1c7c6a5a86423ece9afcf63c"
[[projects]]
digest = "1:3a26588bc48b96825977c1b3df964f8fd842cd6860cc26370588d3563433cf11"
digest = "1:9f7a9e0b3f54aad2c053f778b9933263de723f6d722c68092b1eec06b95a5860"
name = "github.com/google/uuid"
packages = ["."]
pruneopts = "UT"
revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494"
version = "v1.0.0"
revision = "7e072fc3a7be179aee6d3359e46015aa8c995314"
[[projects]]
digest = "1:65c4414eeb350c47b8de71110150d0ea8a281835b1f386eacaa3ad7325929c21"
digest = "1:75eb87381d25cc75212f52358df9c3a2719584eaa9685cd510ce28699122f39d"
name = "github.com/googleapis/gnostic"
packages = [
"OpenAPIv2",
@@ -423,8 +458,7 @@
"extensions",
]
pruneopts = "UT"
revision = "7c663266750e7d82587642f65e60bc4083f1f84e"
version = "v0.2.0"
revision = "0c5108395e2debce0d731cf0287ddf7242066aba"
[[projects]]
branch = "master"
@@ -443,11 +477,11 @@
[[projects]]
branch = "master"
digest = "1:8ec54d9488698e9db22139250bde10e35aab02c20236e4d1c1457604c2c4fe18"
digest = "1:3eb026ba34d6dd12b45bb6abd63b4e917ebca8d8f3022a139c0881d900ad1bee"
name = "github.com/googollee/go-socket.io"
packages = ["."]
pruneopts = "UT"
revision = "25e1f67559cf5d0e41efbc3e0157bb952596ffc3"
revision = "c8aeb1ed9b49d7de8fef8662efb18f1d289c5f2e"
[[projects]]
digest = "1:c79fb010be38a59d657c48c6ba1d003a8aa651fa56b579d959d74573b7dff8e1"
@@ -486,15 +520,14 @@
revision = "36ee7e946282a3fb1cfecd476ddc9b35d8847e42"
[[projects]]
branch = "master"
digest = "1:86c1210529e69d69860f2bb3ee9ccce0b595aa3f9165e7dd1388e5c612915888"
digest = "1:878f0defa9b853f9acfaf4a162ba450a89d0050eff084f9fe7f5bd15948f172a"
name = "github.com/gregjones/httpcache"
packages = [
".",
"diskcache",
]
pruneopts = "UT"
revision = "9cad4c3443a7200dd6400aef47183728de563a38"
revision = "787624de3eb7bd915c329cba748687a3b22666a6"
[[projects]]
branch = "master"
@@ -505,20 +538,20 @@
revision = "8e809c8a86450a29b90dcc9efbf062d0fe6d9746"
[[projects]]
branch = "master"
digest = "1:09970bb8daf100bdf11b48b72c71ef980cd2b50efbd903989b3d182956be0b83"
name = "github.com/hako/durafmt"
packages = ["."]
pruneopts = "UT"
revision = "7b7ae1e72eade09dbc9c2cfba3e6c4bae7b8bcac"
version = "1.0.0"
[[projects]]
digest = "1:8eb1de8112c9924d59bf1d3e5c26f5eaa2bfc2a5fcbb92dc1c2e4546d695f277"
digest = "1:3e260afa138eab6492b531a3b3d10ab4cb70512d423faa78b8949dec76e66a21"
name = "github.com/imdario/mergo"
packages = ["."]
pruneopts = "UT"
revision = "9f23e2d6bd2a77f959b2bf6acdbefd708a83a4a4"
version = "v0.3.6"
revision = "9316a62528ac99aaecb4e47eadd6dc8aa6533d58"
version = "v0.3.5"
[[projects]]
digest = "1:b6f4477f09f11785097a121811f3a90d8d26cab73c1aa71abda859bdf6ad2334"
@@ -540,28 +573,26 @@
revision = "04140366298a54a039076d798123ffa108fff46c"
[[projects]]
digest = "1:b87714e57a511d88f307aba7d5b63522da12bed0a050889c81272fc50f71100e"
digest = "1:e22af8c7518e1eab6f2eab2b7d7558927f816262586cd6ed9f349c97a6c285c4"
name = "github.com/jmespath/go-jmespath"
packages = ["."]
pruneopts = "UT"
revision = "3433f3ea46d9f8019119e7dd41274e112a2359a9"
version = "0.2.2"
revision = "0b12d6b5"
[[projects]]
digest = "1:3e551bbb3a7c0ab2a2bf4660e7fcad16db089fdcfbb44b0199e62838038623ea"
digest = "1:bb3cc4c1b21ea18cfa4e3e47440fc74d316ab25b0cf42927e8c1274917bd9891"
name = "github.com/json-iterator/go"
packages = ["."]
pruneopts = "UT"
revision = "1624edc4454b8682399def8740d46db5e4362ba4"
version = "v1.1.5"
revision = "f2b4162afba35581b6d4a50d3b8f34e33c144682"
[[projects]]
branch = "master"
digest = "1:f44d34fda864bed6d6c71514cd40b2ee097e6e67f745d5d014113e1faa5af8b7"
digest = "1:0a69a1c0db3591fcefb47f115b224592c8dfa4368b7ba9fae509d5e16cdc95c8"
name = "github.com/konsorten/go-windows-terminal-sequences"
packages = ["."]
pruneopts = "UT"
revision = "b729f2633dfe35f4d1d8a32385f6685610ce1cb5"
revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242"
version = "v1.0.1"
[[projects]]
branch = "master"
@@ -572,12 +603,12 @@
revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0"
[[projects]]
branch = "master"
digest = "1:29d28429a93b076908a36420a7ecb2bf429d24c15a4b5e2c220ea00fc84b71af"
name = "github.com/kr/pty"
packages = ["."]
pruneopts = "UT"
revision = "db8e3cd836b82e82e0a9c8edc6896967dd31374f"
version = "v1.1.3"
[[projects]]
digest = "1:4e878df5f4e9fd625bf9c9aac77ef7cbfa4a74c01265505527c23470c0e40300"
@@ -604,12 +635,12 @@
version = "v0.0.4"
[[projects]]
branch = "master"
digest = "1:cdb899c199f907ac9fb50495ec71212c95cb5b0e0a8ee0800da0238036091033"
name = "github.com/mattn/go-runewidth"
packages = ["."]
pruneopts = "UT"
revision = "ce7b0b5c7b45a81508558cd1dba6bb1e4ddb51bb"
version = "v0.0.3"
[[projects]]
branch = "master"
@@ -649,12 +680,12 @@
version = "v0.10.11"
[[projects]]
digest = "1:b39aee4261f1ae13fdd21a0db189e0bba0f96c0f2eba77ab278428e2d3b00052"
digest = "1:b20d8767957e40b9302a8caaee88caa698513fbd972509a54555302c3aebfa04"
name = "github.com/miekg/dns"
packages = ["."]
pruneopts = "UT"
revision = "f4db2ca6edc3af0ee51bf332099cc480bcf3ef9d"
version = "v1.0.10"
revision = "7064f7248f5fa5fd79382a76328b4e200b79e4ae"
version = "v1.0.15"
[[projects]]
digest = "1:33422d238f147d247752996a26574ac48dcf472976eda7f5134015f06bf16563"
@@ -665,12 +696,12 @@
version = "1.0.3"
[[projects]]
digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855"
digest = "1:c56ad36f5722eb07926c979d5e80676ee007a9e39e7808577b9d87ec92b00460"
name = "github.com/modern-go/reflect2"
packages = ["."]
pruneopts = "UT"
revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
version = "1.0.1"
revision = "94122c33edd36123c84d5368cfb2b69df93a0ec8"
version = "v1.0.1"
[[projects]]
branch = "master"
@@ -688,6 +719,14 @@
pruneopts = "UT"
revision = "9ac6cf4d929b2fa8fd2d2e6dec5bb0feb4f4911d"
[[projects]]
digest = "1:0d3513430f7d83565e9a6bc2727de8fa16f7103ef628b179fefc712590670e7e"
name = "github.com/nelsonken/cos-go-sdk-v5"
packages = ["cos"]
pruneopts = "UT"
revision = "5247afdb7a80666955f2b8b108772bf7af5031c8"
version = "v1.21"
[[projects]]
branch = "master"
digest = "1:2da0e5077ed40453dc281b9a2428d84cf6ad14063aed189f6296ca5dd25cf13d"
@@ -740,23 +779,23 @@
version = "v2.0.1"
[[projects]]
digest = "1:4f0885b3f0dba96128a09a6f4b4231c42688fbd05f323224c6aa5adc9f4e87bf"
digest = "1:e39a5ee8fcbec487f8fc68863ef95f2b025e0739b0e4aa55558a2b4cf8f0ecf0"
name = "github.com/pierrec/lz4"
packages = [
".",
"internal/xxh32",
]
pruneopts = "UT"
revision = "bb6bfd13c6a262f1943c0446eb25b7f54c1fb9a2"
version = "v2.0.6"
revision = "635575b42742856941dbc767b44905bb9ba083f6"
version = "v2.0.7"
[[projects]]
branch = "master"
digest = "1:4f43b3c1b7e44980a5f3c593f8bf0e18844dc44f451a071c93e77e28cf990db6"
digest = "1:4cd499f102d1dbd7583f07431c8530b385f089c4b188a0778bc47a870930eb9b"
name = "github.com/pkg/term"
packages = ["termios"]
pruneopts = "UT"
revision = "bffc007b7fd5a70e20e28f5b7649bb84671ef436"
revision = "93e6c91493094ff99a036fea0040802a1e0a4f69"
[[projects]]
digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe"
@@ -767,15 +806,16 @@
version = "v1.0.0"
[[projects]]
digest = "1:d14a5f4bfecf017cb780bdde1b6483e5deb87e12c332544d2c430eda58734bcb"
digest = "1:26663fafdea73a38075b07e8e9d82fc0056379d2be8bb4e13899e8fda7c7dd23"
name = "github.com/prometheus/client_golang"
packages = [
"prometheus",
"prometheus/internal",
"prometheus/promhttp",
]
pruneopts = "UT"
revision = "c5b7fccd204277076155f10851dad72b76a49317"
version = "v0.8.0"
revision = "abad2d1bd44235a26707c172eab6bca5bf2dbad3"
version = "v0.9.1"
[[projects]]
branch = "master"
@@ -787,7 +827,7 @@
[[projects]]
branch = "master"
digest = "1:63b68062b8968092eb86bedc4e68894bd096ea6b24920faca8b9dcf451f54bb5"
digest = "1:db712fde5d12d6cdbdf14b777f0c230f4ff5ab0be8e35b239fc319953ed577a4"
name = "github.com/prometheus/common"
packages = [
"expfmt",
@@ -795,11 +835,11 @@
"model",
]
pruneopts = "UT"
revision = "c7de2306084e37d54b8be01f3541a8464345e9a5"
revision = "0b1957f9d949dfa3084171a6ec5642b38055276a"
[[projects]]
branch = "master"
digest = "1:ef1dd9945e58ee9b635273d28c0ef3fa3742a7dedc038ebe207fd63e6ce000ef"
digest = "1:ef74914912f99c79434d9c09658274678bc85080ebe3ab32bec3940ebce5e1fc"
name = "github.com/prometheus/procfs"
packages = [
".",
@@ -808,15 +848,15 @@
"xfs",
]
pruneopts = "UT"
revision = "418d78d0b9a7b7de3a6bbc8a23def624cc977bb2"
revision = "185b4288413d2a0dd0806f78c90dde719829e5ae"
[[projects]]
branch = "master"
digest = "1:c4556a44e350b50a490544d9b06e9fba9c286c21d6c0e47f54f3a9214597298c"
digest = "1:d38f81081a389f1466ec98192cf9115a82158854d6f01e1c23e2e7554b97db71"
name = "github.com/rcrowley/go-metrics"
packages = ["."]
pruneopts = "UT"
revision = "e2704e165165ec55d062f5919b4b29494e9fa790"
revision = "3113b8401b8a98917cde58f8bbd42a1b1c03b1fd"
[[projects]]
digest = "1:274f67cb6fed9588ea2521ecdac05a6d62a8c51c074c1fccc6a49a40ba80e925"
@@ -835,20 +875,20 @@
revision = "49a4782e9908fe098c907022a1bd7519c79803d6"
[[projects]]
digest = "1:dc2d85c13ac22c22a1f3170a41a8e1b897fa05134aaf533f16df44f66a25b4a1"
digest = "1:69b1cc331fca23d702bd72f860c6a647afd0aa9fcbc1d0659b1365e26546dd70"
name = "github.com/sirupsen/logrus"
packages = ["."]
pruneopts = "UT"
revision = "a67f783a3814b8729bd2dac5780b5f78f8dbd64d"
version = "v1.1.0"
revision = "bcd833dfe83d3cebad139e4a29ed79cb2318bf95"
version = "v1.2.0"
[[projects]]
digest = "1:dab83a1bbc7ad3d7a6ba1a1cc1760f25ac38cdf7d96a5cdd55cd915a4f5ceaf9"
digest = "1:9424f440bba8f7508b69414634aef3b2b3a877e522d8a4624692412805407bb7"
name = "github.com/spf13/pflag"
packages = ["."]
pruneopts = "UT"
revision = "9a97c102cda95a86cec2345a6f09f55a939babf5"
version = "v1.0.2"
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
version = "v1.0.1"
[[projects]]
digest = "1:18752d0b95816a1b777505a97f71c7467a8445b8ffb55631a7bf779f6ba4fa83"
@@ -858,6 +898,19 @@
revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
version = "v1.2.2"
[[projects]]
digest = "1:a115409defa2eb9059f215a91573ac1126123c4feac6bbb8d97f05e2b7761fe2"
name = "github.com/tencentcloud/tencentcloud-sdk-go"
packages = [
"tencentcloud/common",
"tencentcloud/common/errors",
"tencentcloud/common/http",
"tencentcloud/common/profile",
]
pruneopts = "UT"
revision = "805d01dd0e2ef6e8ab69faf815c680e93c52c91a"
version = "3.0.30"
[[projects]]
branch = "master"
digest = "1:a38c75e7edd595bbaa03334c1ac26163a5e990d81f05cd9ec5fd0edc9c786078"
@@ -879,15 +932,14 @@
revision = "7d3ee1afa71c90fd1514c8f557ae6c5f414208eb"
[[projects]]
digest = "1:98e5cda86f67cd1ac95389d98670b66dea8cae480fe6292b83bccccfe60b4106"
digest = "1:7b36ba7867ad2d262abedeff4c9362f2e8aa00cf6dd3254a509f24c27eb1d5b7"
name = "github.com/ugorji/go"
packages = ["codec"]
pruneopts = "UT"
revision = "f3cacc17c85ecb7f1b6a9e373ee85d1480919868"
revision = "9c7f9b7a2bc3a520f7c7b30b34b7f85f47fe27b6"
[[projects]]
branch = "master"
digest = "1:35f0192bdf8cdd76e1851c53e293c92c058c20870ccb0af1a292f5e64075fe40"
digest = "1:506f2f0fee9b0e75b987286233a3b0d3fbf7cb145d754b0719b672822246cbc6"
name = "github.com/vmware/govmomi"
packages = [
".",
@@ -907,11 +959,12 @@
"vim25/xml",
]
pruneopts = "UT"
revision = "c8ddb4b2bcda00a066d84c889dbb40d1aa9f2519"
revision = "3617f28d167d448f93f282a867870f109516d2a5"
version = "v0.19.0"
[[projects]]
branch = "master"
digest = "1:71c5989353531072eeb9547066e05bdeaaf9ef0512673bca3b4b824092d70de3"
digest = "1:9bca23e99b8dc02f7f22d197ee886acde6dd7c7a16855f1822ed78f362c2ff1b"
name = "golang.org/x/crypto"
packages = [
"curve25519",
@@ -926,11 +979,11 @@
"ssh/terminal",
]
pruneopts = "UT"
revision = "5295e8364332db77d75fce11f1d19c053919a9c9"
revision = "e4dc69e5b2fd71dcaf8bd5d054eb936deb78d1fa"
[[projects]]
branch = "master"
digest = "1:4ab551743538ce88c540073958b2fb653ca077c5d4c3d1991d86016dd38e22f6"
digest = "1:81bd9a6bed3c32ef0c7350aca59f5cbd816b2e2a4cbde0eb5fdca60526be57e0"
name = "golang.org/x/net"
packages = [
"bpf",
@@ -947,18 +1000,28 @@
"trace",
]
pruneopts = "UT"
revision = "4dfa2610cdf3b287375bbba5b8f2a14d3b01d8de"
revision = "03003ca0c849e57b6ea29a4bab8d3cb6e4d568fe"
[[projects]]
digest = "1:9359217acc6040b4be710ce34473acef28023ad39bfafecea34ffaea7f1e1890"
name = "golang.org/x/oauth2"
packages = [
".",
"internal",
]
pruneopts = "UT"
revision = "a6bd8cefa1811bd24b86f8902872e4e8225f74c4"
[[projects]]
branch = "master"
digest = "1:2c607ffa8a0a34a9acba4aba7b33d981b5a2150bfcec41b1f2ef1d791bcf6c14"
digest = "1:6a875550c3b582f6c2d7e2ce44aba792511f00016d7c46b0a4fb26f730ef3058"
name = "golang.org/x/sys"
packages = [
"unix",
"windows",
]
pruneopts = "UT"
revision = "dad3d9fb7b6e83d0f9ac8f54670f6334c3a287b4"
revision = "66b7b1311ac80bbafcd2daeef9a5e6e2cd1e2399"
[[projects]]
digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
@@ -984,20 +1047,28 @@
version = "v0.3.0"
[[projects]]
branch = "master"
digest = "1:c9e7a4b4d47c0ed205d257648b0e5b0440880cb728506e318f8ac7cd36270bc4"
digest = "1:d37b0ef2944431fe9e8ef35c6fffc8990d9e2ca300588df94a6890f3649ae365"
name = "golang.org/x/time"
packages = ["rate"]
pruneopts = "UT"
revision = "fbb02b2291d28baffd63558aa44b4b56f178d650"
revision = "f51c12702a4d776e4c1fa9b0fabab841babae631"
[[projects]]
digest = "1:c25289f43ac4a68d88b02245742347c94f1e108c534dda442188015ff80669b3"
digest = "1:a623ed4965cad144a32551cb009b9bad9ad247c22ca1afdd934fc85d0c891f93"
name = "google.golang.org/appengine"
packages = ["cloudsql"]
packages = [
"cloudsql",
"internal",
"internal/base",
"internal/datastore",
"internal/log",
"internal/remote_api",
"internal/urlfetch",
"urlfetch",
]
pruneopts = "UT"
revision = "ae0ab99deb4dc413a2b4bd6c8bdd0eb67f1e4d06"
version = "v1.2.0"
revision = "4a4468ece617fc8205e99368fa2200e9d1fad421"
version = "v1.3.0"
[[projects]]
branch = "master"
@@ -1005,10 +1076,10 @@
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
pruneopts = "UT"
revision = "0e822944c569bf5c9afd034adaa56208bd2906ac"
revision = "b5d43981345bdb2c233eb4bf3277847b48c6fdc6"
[[projects]]
digest = "1:ab8e92d746fb5c4c18846b0879842ac8e53b3d352449423d0924a11f1020ae1b"
digest = "1:c3ad9841823db6da420a5625b367913b4ff54bbe60e8e3c98bd20e243e62e2d2"
name = "google.golang.org/grpc"
packages = [
".",
@@ -1039,8 +1110,8 @@
"tap",
]
pruneopts = "UT"
revision = "8dea3dc473e90c8179e519d91302d0597c0ca1d1"
version = "v1.15.0"
revision = "2e463a05d100327ca47ac218281906921038fd95"
version = "v1.16.0"
[[projects]]
digest = "1:2655728699af00d823b0a68bd7169fd241a30c04252f456b34421908701b9c3f"
@@ -1051,20 +1122,20 @@
version = "v1.2"
[[projects]]
digest = "1:cbc72c4c4886a918d6ab4b95e347ffe259846260f99ebdd8a198c2331cf2b2e9"
digest = "1:1b4724d3c8125f6044925f02b485b74bfec9905cbf579d95aafd1a6c8f8447d3"
name = "gopkg.in/go-playground/validator.v8"
packages = ["."]
pruneopts = "UT"
revision = "5f1438d3fca68893a817e4a66806cea46a9e4ebf"
version = "v8.18.2"
revision = "5f57d2222ad794d0dffb07e664ea05e2ee07d60c"
version = "v8.18.1"
[[projects]]
digest = "1:2d1fbdc6777e5408cabeb02bf336305e724b925ff4546ded0fa8715a7267922a"
digest = "1:ef72505cf098abdd34efeea032103377bec06abb61d8a06f002d5d296a4b1185"
name = "gopkg.in/inf.v0"
packages = ["."]
pruneopts = "UT"
revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf"
version = "v0.9.1"
revision = "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4"
version = "v0.9.0"
[[projects]]
digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"
@@ -1075,7 +1146,7 @@
version = "v2.2.1"
[[projects]]
digest = "1:74142cd2275f77547c35ac51514108d9798a09aa0cf377a5c1084718ef7aa225"
digest = "1:910ec974550174f4ca48b9f4a3caec16b693e584c3762dc726dc0dcf28f8e318"
name = "k8s.io/api"
packages = [
"admissionregistration/v1alpha1",
@@ -1089,10 +1160,12 @@
"authorization/v1beta1",
"autoscaling/v1",
"autoscaling/v2beta1",
"autoscaling/v2beta2",
"batch/v1",
"batch/v1beta1",
"batch/v2alpha1",
"certificates/v1beta1",
"coordination/v1beta1",
"core/v1",
"events/v1beta1",
"extensions/v1beta1",
@@ -1109,10 +1182,12 @@
"storage/v1beta1",
]
pruneopts = "UT"
revision = "072894a440bdee3a891dea811fe42902311cd2a3"
revision = "fd83cbc87e7632ccd8bbab63d2b673d4e0c631cc"
version = "kubernetes-1.12.0"
[[projects]]
digest = "1:29d5abc33d8cbec19b4cd032a87d28010dd615578dd695a655fc3d5ec3ab86b6"
branch = "master"
digest = "1:8d1aedc658be5554671b9fa17e03beba96481e9a9b445baa4756836a65ed342c"
name = "k8s.io/apimachinery"
packages = [
"pkg/api/errors",
@@ -1140,22 +1215,22 @@
"pkg/util/framer",
"pkg/util/intstr",
"pkg/util/json",
"pkg/util/naming",
"pkg/util/net",
"pkg/util/runtime",
"pkg/util/sets",
"pkg/util/validation",
"pkg/util/validation/field",
"pkg/util/wait",
"pkg/util/yaml",
"pkg/version",
"pkg/watch",
"third_party/forked/golang/reflect",
]
pruneopts = "UT"
revision = "103fd098999dc9c0c88536f5c9ad2e5da39373ae"
revision = "90473842928c717082a393d6adceee99889fe8cc"
[[projects]]
digest = "1:ac46cc5d5c55dd93d4844327334d2253d563d76f14d4b38a8b522b97f0f52214"
digest = "1:51fd9ac9f2be10d79f5af101a7a1d758ef283fdb028a0d11198754bd3d4a6020"
name = "k8s.io/client-go"
packages = [
"discovery",
@@ -1172,10 +1247,12 @@
"kubernetes/typed/authorization/v1beta1",
"kubernetes/typed/autoscaling/v1",
"kubernetes/typed/autoscaling/v2beta1",
"kubernetes/typed/autoscaling/v2beta2",
"kubernetes/typed/batch/v1",
"kubernetes/typed/batch/v1beta1",
"kubernetes/typed/batch/v2alpha1",
"kubernetes/typed/certificates/v1beta1",
"kubernetes/typed/coordination/v1beta1",
"kubernetes/typed/core/v1",
"kubernetes/typed/events/v1beta1",
"kubernetes/typed/extensions/v1beta1",
@@ -1212,8 +1289,16 @@
"util/integer",
]
pruneopts = "UT"
revision = "7d04d0e2a0a1a4d4a1cd6baa432a2301492e4e65"
version = "v8.0.0"
revision = "1638f8970cefaa404ff3a62950f88b08292b2696"
version = "v9.0.0"
[[projects]]
digest = "1:7719608fe0b52a4ece56c2dde37bedd95b938677d1ab0f84b8a7852e4c59f849"
name = "sigs.k8s.io/yaml"
packages = ["."]
pruneopts = "UT"
revision = "fd68e9863619f6ec2fdd8625fe1f02e7c877e480"
version = "v1.1.0"
[[projects]]
digest = "1:356a33d2d627cbb232a1d71cc42051fbac0e5e6a1717679f110054baa02472e5"
@@ -1318,6 +1403,12 @@
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests",
"github.com/aliyun/aliyun-oss-go-sdk/oss",
"github.com/aokoli/goutils",
"github.com/aws/aws-sdk-go/aws",
"github.com/aws/aws-sdk-go/aws/credentials",
"github.com/aws/aws-sdk-go/aws/session",
"github.com/aws/aws-sdk-go/service/ec2",
"github.com/aws/aws-sdk-go/service/iam",
"github.com/aws/aws-sdk-go/service/s3",
"github.com/bitly/go-simplejson",
"github.com/c-bata/go-prompt",
"github.com/coredns/coredns/core/dnsserver",
@@ -1359,8 +1450,12 @@
"github.com/mholt/caddy/startupshutdown",
"github.com/miekg/dns",
"github.com/moul/http2curl",
"github.com/nelsonken/cos-go-sdk-v5/cos",
"github.com/serialx/hashring",
"github.com/stretchr/testify/assert",
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common",
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http",
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile",
"github.com/tredoe/osutil/user/crypt/sha512_crypt",
"github.com/vmware/govmomi",
"github.com/vmware/govmomi/object",
+135 -80
View File
@@ -25,17 +25,145 @@
# unused-packages = true
[[constraint]]
name = "github.com/360EntSecGroup-Skylar/excelize"
version = "1.4.0"
[[constraint]]
name = "github.com/Azure/azure-sdk-for-go"
version = "=19.1.0"
[[constraint]]
branch = "master"
name = "github.com/Microsoft/azure-vhd-utils"
[[constraint]]
name = "github.com/aliyun/alibaba-cloud-sdk-go"
version = "0.7.4"
[[constraint]]
name = "github.com/aliyun/aliyun-oss-go-sdk"
version = "1.9.1"
[[constraint]]
name = "github.com/aokoli/goutils"
version = "1.0.1"
[[constraint]]
name = "github.com/aws/aws-sdk-go"
version = "=1.15.73"
[[constraint]]
name = "github.com/bitly/go-simplejson"
version = "0.5.0"
[[constraint]]
name = "github.com/c-bata/go-prompt"
version = "=0.2.1"
[[constraint]]
branch = "master"
name = "yunion.io/x/jsonutils"
name = "github.com/coredns/coredns"
version = "1.2.6"
[[constraint]]
name = "github.com/fatih/color"
version = "1.7.0"
[[constraint]]
name = "github.com/go-sql-driver/mysql"
version = "1.4.0"
[[constraint]]
name = "github.com/golang-plus/uuid"
version = "1.0.0"
[[constraint]]
branch = "master"
name = "yunion.io/x/sqlchemy"
name = "github.com/googollee/go-socket.io"
[[constraint]]
name = "github.com/gorilla/mux"
version = "1.6.2"
[[constraint]]
name = "github.com/gorilla/websocket"
version = "1.4.0"
[[constraint]]
branch = "master"
name = "github.com/gosuri/uitable"
[[constraint]]
name = "github.com/hako/durafmt"
version = "1.0.0"
[[constraint]]
name = "github.com/jinzhu/gorm"
version = "1.9.1"
[[constraint]]
name = "github.com/kr/pty"
version = "1.1.3"
[[constraint]]
name = "github.com/mholt/caddy"
version = "0.10.11"
[[constraint]]
name = "github.com/miekg/dns"
version = "1.0.15"
[[constraint]]
branch = "master"
name = "github.com/moul/http2curl"
[[constraint]]
name = "github.com/nelsonken/cos-go-sdk-v5"
version = "1.21.0"
[[constraint]]
branch = "master"
name = "github.com/serialx/hashring"
[[constraint]]
name = "github.com/stretchr/testify"
version = "1.2.2"
[[constraint]]
name = "github.com/tencentcloud/tencentcloud-sdk-go"
version = "=3.0.30"
[[constraint]]
branch = "master"
name = "github.com/tredoe/osutil"
[[constraint]]
name = "github.com/vmware/govmomi"
version = "0.19.0"
[[constraint]]
branch = "master"
name = "golang.org/x/crypto"
[[constraint]]
name = "gopkg.in/gin-gonic/gin.v1"
version = "1.2.0"
[[constraint]]
name = "k8s.io/api"
version = "kubernetes-1.12.0"
[[constraint]]
branch = "master"
name = "k8s.io/apimachinery"
[[constraint]]
name = "k8s.io/client-go"
version = "9.0.0"
[[constraint]]
branch = "master"
name = "yunion.io/x/jsonutils"
[[constraint]]
branch = "master"
@@ -45,87 +173,14 @@
branch = "master"
name = "yunion.io/x/pkg"
[[constraint]]
branch = "master"
name = "yunion.io/x/sqlchemy"
[[constraint]]
branch = "master"
name = "yunion.io/x/structarg"
# client-go v8.0.0 uses apimachinery 103fd098999dc9c0c88536f5c9ad2e5da39373ae
# and api 072894a440bdee3a891dea811fe42902311cd2a3 (see Godep.json). go dep
# is unable to match Godep.json automatically so have to specify here.
[[constraint]]
name = "k8s.io/client-go"
version = "v8.0.0"
[[override]]
name = "k8s.io/apimachinery"
revision = "103fd098999dc9c0c88536f5c9ad2e5da39373ae"
[[override]]
name = "k8s.io/api"
revision = "072894a440bdee3a891dea811fe42902311cd2a3"
[[override]]
name = "github.com/apache/thrift"
revision = "e59b73d3c2bf1c328ccb78e683c0462fa1a473c7"
[[override]]
name = "github.com/ugorji/go"
revision = "f3cacc17c85ecb7f1b6a9e373ee85d1480919868"
[[constraint]]
name = "github.com/coredns/coredns"
version = "v1.2.0"
[prune]
go-tests = true
unused-packages = true
[[constraint]]
branch = "master"
name = "github.com/vmware/govmomi"
[[constraint]]
branch = "master"
name = "github.com/hako/durafmt"
[[constraint]]
name = "github.com/Azure/azure-sdk-for-go"
version = "19.1.0"
[[constraint]]
branch = "master"
name = "github.com/googollee/go-socket.io"
[[constraint]]
branch = "master"
name = "github.com/kr/pty"
[[constraint]]
branch = "master"
name = "github.com/Microsoft/azure-vhd-utils"
[[constraint]]
branch = "master"
name = "github.com/texttheater/golang-levenshtein"
[[constraint]]
name = "github.com/360EntSecGroup-Skylar/excelize"
version = "v1.3.0"
[[constraint]]
name = "github.com/tencentcloud/tencentcloud-sdk-go"
version = "=v3.0.28"
[[constraint]]
branch = "master"
name = "github.com/nelsonken/cos-go-sdk-v5"
[[constraint]]
branch = "master"
name = "github.com/tredoe/osutil"
[[constraint]]
branch = "master"
name = "golang.org/x/crypto"
[[constraint]]
branch = "master"
name = "github.com/forhappy/cos-go-sdk"
+123
View File
@@ -0,0 +1,123 @@
package main
import (
"fmt"
"os"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/util/aws"
"yunion.io/x/onecloud/pkg/util/shellutils"
"yunion.io/x/structarg"
_ "yunion.io/x/onecloud/pkg/util/aws/shell"
)
type BaseOptions struct {
Help bool `help:"Show help"`
AccessUrl string `help:"Access key" default:"$AWS_ACCESS_URL" choices:"ChinaCloud|InternationalCloud"`
AccessKey string `help:"Access key" default:"$AWS_ACCESS_KEY"`
Secret string `help:"Secret" default:"$AWS_SECRET"`
RegionId string `help:"RegionId" default:"$AWS_REGION"`
SUBCOMMAND string `help:"awscli subcommand" subcommand:"true"`
}
func getSubcommandParser() (*structarg.ArgumentParser, error) {
parse, e := structarg.NewArgumentParser(&BaseOptions{},
"awscli",
"Command-line interface to aws API.",
`See "awscli help COMMAND" for help on a specific command.`)
if e != nil {
return nil, e
}
subcmd := parse.GetSubcommand()
if subcmd == nil {
return nil, fmt.Errorf("No subcommand argument.")
}
type HelpOptions struct {
SUBCOMMAND string `help:"sub-command name"`
}
shellutils.R(&HelpOptions{}, "help", "Show help of a subcommand", func(args *HelpOptions) error {
helpstr, e := subcmd.SubHelpString(args.SUBCOMMAND)
if e != nil {
return e
} else {
fmt.Print(helpstr)
return nil
}
})
for _, v := range shellutils.CommandTable {
_, e := subcmd.AddSubParser(v.Options, v.Command, v.Desc, v.Callback)
if e != nil {
return nil, e
}
}
return parse, nil
}
func showErrorAndExit(e error) {
log.Errorf("%s", e)
os.Exit(1)
}
func newClient(options *BaseOptions) (*aws.SRegion, error) {
if len(options.AccessKey) == 0 {
return nil, fmt.Errorf("Missing accessKey")
}
if len(options.Secret) == 0 {
return nil, fmt.Errorf("Missing secret")
}
cli, err := aws.NewAwsClient("", "", options.AccessUrl, options.AccessKey, options.Secret)
if err != nil {
return nil, err
}
region := cli.GetRegion(options.RegionId)
if region == nil {
return nil, fmt.Errorf("No such region %s", options.RegionId)
}
return region, nil
}
func main() {
parser, e := getSubcommandParser()
if e != nil {
showErrorAndExit(e)
}
e = parser.ParseArgs(os.Args[1:], false)
options := parser.Options().(*BaseOptions)
if options.Help {
fmt.Print(parser.HelpString())
} else {
subcmd := parser.GetSubcommand()
subparser := subcmd.GetSubParser()
if e != nil {
if subparser != nil {
fmt.Print(subparser.Usage())
} else {
fmt.Print(parser.Usage())
}
showErrorAndExit(e)
} else {
suboptions := subparser.Options()
if options.SUBCOMMAND == "help" {
e = subcmd.Invoke(suboptions)
} else {
var region *aws.SRegion
region, e = newClient(options)
if e != nil {
showErrorAndExit(e)
}
e = subcmd.Invoke(region, suboptions)
}
if e != nil {
showErrorAndExit(e)
}
}
}
}
+334
View File
@@ -0,0 +1,334 @@
package guestdrivers
import (
"context"
"fmt"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/mcclient"
)
type SAwsGuestDriver struct {
SManagedVirtualizedGuestDriver
}
func (self *SAwsGuestDriver) GetHypervisor() string {
return models.HYPERVISOR_AWS
}
func (self *SAwsGuestDriver) ChooseHostStorage(host *models.SHost, backend string) *models.SStorage {
storages := host.GetAttachedStorages("")
for i := 0; i < len(storages); i += 1 {
if storages[i].StorageType == backend {
return &storages[i]
}
}
for _, stype := range []string{"gp2", "io1", "st1", "sc1", "standard"} {
for i := 0; i < len(storages); i += 1 {
if storages[i].StorageType == stype {
return &storages[i]
}
}
}
return nil
}
func (self *SAwsGuestDriver) GetDetachDiskStatus() ([]string, error) {
return []string{models.VM_READY, models.VM_RUNNING}, nil
}
func (self *SAwsGuestDriver) RequestDetachDisk(ctx context.Context, guest *models.SGuest, task taskman.ITask) error {
return guest.StartSyncTask(ctx, task.GetUserCred(), false, task.GetTaskId())
}
func (self *SAwsGuestDriver) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
return self.SManagedVirtualizedGuestDriver.ValidateCreateData(ctx, userCred, data)
}
func fetchAwsIVMinfo(desc SManagedVMCreateConfig, iVM cloudprovider.ICloudVM, guestId string) *jsonutils.JSONDict {
data := jsonutils.NewDict()
data.Add(jsonutils.NewString(iVM.GetOSType()), "os")
if len(desc.OsDistribution) > 0 {
data.Add(jsonutils.NewString(desc.OsDistribution), "distro")
}
if len(desc.OsVersion) > 0 {
data.Add(jsonutils.NewString(desc.OsVersion), "version")
}
idisks, err := iVM.GetIDisks()
if err != nil {
log.Errorf("GetiDisks error %s", err)
} else {
diskInfo := make([]SDiskInfo, len(idisks))
for i := 0; i < len(idisks); i += 1 {
dinfo := SDiskInfo{}
dinfo.Uuid = idisks[i].GetGlobalId()
dinfo.Size = idisks[i].GetDiskSizeMB()
dinfo.DiskType = idisks[i].GetDiskType()
if metaData := idisks[i].GetMetadata(); metaData != nil {
dinfo.Metadata = make(map[string]string, 0)
if err := metaData.Unmarshal(dinfo.Metadata); err != nil {
log.Errorf("Get disk %s metadata info error: %v", idisks[i].GetName(), err)
}
}
diskInfo[i] = dinfo
}
data.Add(jsonutils.Marshal(&diskInfo), "disks")
}
data.Add(jsonutils.NewString(iVM.GetGlobalId()), "uuid")
data.Add(iVM.GetMetadata(), "metadata")
return data
}
func (self *SAwsGuestDriver) RequestDeployGuestOnHost(ctx context.Context, guest *models.SGuest, host *models.SHost, task taskman.ITask) error {
config := guest.GetDeployConfigOnHost(ctx, host, task.GetParams())
log.Debugf("RequestDeployGuestOnHost: %s", config)
action, err := config.GetString("action")
if err != nil {
return err
}
ihost, err := host.GetIHost()
if err != nil {
return err
}
desc := SManagedVMCreateConfig{}
err = config.Unmarshal(&desc, "desc")
if err != nil {
return err
}
publicKey, _ := config.GetString("public_key")
passwd, _ := config.GetString("password")
adminPublicKey, _ := config.GetString("admin_public_key")
projectPublicKey, _ := config.GetString("project_public_key")
oUserData, _ := config.GetString("user_data")
userData := generateUserData(adminPublicKey, projectPublicKey, oUserData)
switch action {
case "create":
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
nets := guest.GetNetworks()
net := nets[0].GetNetwork()
vpc := net.GetVpc()
ivpc, err := vpc.GetIVpc()
if err != nil {
log.Errorf("getIVPC fail %s", err)
return nil, err
}
secgrpId, err := ivpc.SyncSecurityGroup(desc.SecGroupId, desc.SecGroupName, desc.SecRules)
if err != nil {
log.Errorf("SyncSecurityGroup fail %s", err)
return nil, err
}
iVM, err := ihost.CreateVM(desc.Name, desc.ExternalImageId, desc.SysDiskSize, desc.Cpu, desc.Memory, desc.ExternalNetworkId,
desc.IpAddr, desc.Description, "", desc.StorageType, desc.DataDisks, publicKey, secgrpId, userData)
if err != nil {
return nil, err
}
log.Debugf("VMcreated %s, wait status running ...", iVM.GetGlobalId())
err = cloudprovider.WaitStatus(iVM, models.VM_RUNNING, time.Second*5, time.Second*1800)
if err != nil {
return nil, err
}
log.Debugf("VMcreated %s, and status is ready", iVM.GetGlobalId())
iVM, err = ihost.GetIVMById(iVM.GetGlobalId())
if err != nil {
log.Errorf("cannot find vm %s", err)
return nil, err
}
data := fetchAwsIVMinfo(desc, iVM, guest.Id)
return data, nil
})
case "deploy":
iVM, err := ihost.GetIVMById(guest.GetExternalId())
if err != nil || iVM == nil {
log.Errorf("cannot find vm %s", err)
return fmt.Errorf("cannot find vm")
}
params := task.GetParams()
log.Debugf("Deploy VM params %s", params.String())
name, _ := params.GetString("name")
description, _ := params.GetString("description")
publicKey, _ := config.GetString("public_key")
deleteKeypair := jsonutils.QueryBoolean(params, "__delete_keypair__", false)
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
err := iVM.DeployVM(name, passwd, publicKey, deleteKeypair, description)
if err != nil {
return nil, err
}
data := fetchIVMinfo(desc, iVM, guest.Id, DEFAULT_USER, passwd, action)
return data, nil
})
case "rebuild":
iVM, err := ihost.GetIVMById(guest.GetExternalId())
if err != nil || iVM == nil {
log.Errorf("cannot find vm %s", err)
return fmt.Errorf("cannot find vm")
}
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
diskId, err := iVM.RebuildRoot(desc.ExternalImageId, passwd, publicKey, desc.SysDiskSize)
if err != nil {
return nil, err
}
log.Debugf("VMrebuildRoot %s new diskID %s, wait status ready ...", iVM.GetGlobalId(), diskId)
err = cloudprovider.WaitStatus(iVM, models.VM_READY, time.Second*5, time.Second*1800)
if err != nil {
return nil, err
}
log.Debugf("VMrebuildRoot %s, and status is ready", iVM.GetGlobalId())
maxWaitSecs := 300
waited := 0
for {
// hack, wait disk number consistent
idisks, err := iVM.GetIDisks()
if err != nil {
log.Errorf("fail to find VM idisks %s", err)
return nil, err
}
if len(idisks) < len(desc.DataDisks)+1 {
if waited > maxWaitSecs {
log.Errorf("inconsistent disk number, wait timeout, must be something wrong on remote")
return nil, cloudprovider.ErrTimeout
}
log.Debugf("inconsistent disk number???? %d != %d", len(idisks), len(desc.DataDisks)+1)
time.Sleep(time.Second * 5)
waited += 5
} else {
if idisks[0].GetGlobalId() != diskId {
log.Errorf("system disk id inconsistent %s != %s", idisks[0].GetGlobalId(), diskId)
return nil, fmt.Errorf("inconsistent sys disk id after rebuild root")
}
break
}
}
data := fetchIVMinfo(desc, iVM, guest.Id, DEFAULT_USER, passwd, action)
return data, nil
})
default:
log.Errorf("RequestDeployGuestOnHost: Action %s not supported", action)
return fmt.Errorf("Action %s not supported", action)
}
return nil
}
func (self *SAwsGuestDriver) OnGuestDeployTaskDataReceived(ctx context.Context, guest *models.SGuest, task taskman.ITask, data jsonutils.JSONObject) error {
if data.Contains("disks") {
diskInfo := make([]SDiskInfo, 0)
err := data.Unmarshal(&diskInfo, "disks")
if err != nil {
return err
}
disks := guest.GetDisks()
if len(disks) != len(diskInfo) {
msg := fmt.Sprintf("inconsistent disk number: have %d want %d", len(disks), len(diskInfo))
log.Errorf(msg)
return fmt.Errorf(msg)
}
for i := 0; i < len(diskInfo); i += 1 {
disk := disks[i].GetDisk()
_, err = disk.GetModelManager().TableSpec().Update(disk, func() error {
disk.DiskSize = diskInfo[i].Size
disk.ExternalId = diskInfo[i].Uuid
disk.DiskType = diskInfo[i].DiskType
disk.Status = models.DISK_READY
if len(diskInfo[i].Metadata) > 0 {
for key, value := range diskInfo[i].Metadata {
if err := disk.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil {
log.Errorf("set disk %s mata %s => %s error: %v", disk.Name, key, value, err)
}
}
}
return nil
})
if err != nil {
msg := fmt.Sprintf("save disk info failed %s", err)
log.Errorf(msg)
break
} else {
db.OpsLog.LogEvent(disk, db.ACT_ALLOCATE, disk.GetShortDesc(), task.GetUserCred())
}
}
}
uuid, _ := data.GetString("uuid")
if len(uuid) > 0 {
guest.SetExternalId(uuid)
}
if metaData, _ := data.Get("metadata"); metaData != nil {
meta := make(map[string]string, 0)
if err := metaData.Unmarshal(meta); err != nil {
log.Errorf("Get guest %s metadata error: %v", guest.Name, err)
} else {
for key, value := range meta {
if err := guest.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil {
log.Errorf("set guest %s mata %s => %s error: %v", guest.Name, key, value, err)
}
}
}
}
guest.SaveDeployInfo(ctx, task.GetUserCred(), data)
return nil
}
func (self *SAwsGuestDriver) RequestDiskSnapshot(ctx context.Context, guest *models.SGuest, task taskman.ITask, snapshotId, diskId string) error {
iDisk, _ := models.DiskManager.FetchById(diskId)
disk := iDisk.(*models.SDisk)
providerDisk, err := disk.GetIDisk()
if err != nil {
return err
}
iSnapshot, _ := models.SnapshotManager.FetchById(snapshotId)
snapshot := iSnapshot.(*models.SSnapshot)
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
cloudSnapshot, err := providerDisk.CreateISnapshot(snapshot.Name, "")
if err != nil {
return nil, err
}
res := jsonutils.NewDict()
res.Set("snapshot_id", jsonutils.NewString(cloudSnapshot.GetId()))
res.Set("manager_id", jsonutils.NewString(cloudSnapshot.GetManagerId()))
res.Set("cloudregion_id", jsonutils.NewString(cloudSnapshot.GetRegionId()))
return res, nil
})
return nil
}
func (self *SAwsGuestDriver) GetAttachDiskStatus() ([]string, error) {
return []string{models.VM_READY, models.VM_RUNNING}, nil
}
func init() {
driver := SAwsGuestDriver{}
models.RegisterGuestDriver(&driver)
}
+194
View File
@@ -0,0 +1,194 @@
package hostdrivers
import (
"context"
"fmt"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/compute/models"
)
type SAwsHostDriver struct {
SBaseHostDriver
}
func (self *SAwsHostDriver) GetHostType() string {
return models.HOST_TYPE_AWS
}
func (self *SAwsHostDriver) CheckAndSetCacheImage(ctx context.Context, host *models.SHost, storageCache *models.SStoragecache, task taskman.ITask) error {
params := task.GetParams()
imageId, err := params.GetString("image_id")
if err != nil {
return err
}
osArch, _ := params.GetString("os_arch")
osType, _ := params.GetString("os_type")
osDist, _ := params.GetString("os_distribution")
isForce := jsonutils.QueryBoolean(params, "is_force", false)
userCred := task.GetUserCred()
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
lockman.LockRawObject(ctx, "cachedimages", fmt.Sprintf("%s-%s", storageCache.Id, imageId))
defer lockman.ReleaseRawObject(ctx, "cachedimages", fmt.Sprintf("%s-%s", storageCache.Id, imageId))
scimg := models.StoragecachedimageManager.Register(ctx, task.GetUserCred(), storageCache.Id, imageId)
iStorageCache, err := storageCache.GetIStorageCache()
if err != nil {
return nil, err
}
extImgId, err := iStorageCache.UploadImage(userCred, imageId, osArch, osType, osDist, scimg.ExternalId, isForce)
if err != nil {
return nil, err
} else {
scimg.SetExternalId(extImgId)
ret := jsonutils.NewDict()
ret.Add(jsonutils.NewString(extImgId), "image_id")
return ret, nil
}
})
return nil
}
func (self *SAwsHostDriver) RequestPrepareSaveDiskOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask) error {
task.ScheduleRun(nil)
return nil
}
func (self *SAwsHostDriver) RequestSaveUploadImageOnHost(ctx context.Context, host *models.SHost, disk *models.SDisk, imageId string, task taskman.ITask, data jsonutils.JSONObject) error {
if iDisk, err := disk.GetIDisk(); err != nil {
return err
} else if iStorage, err := disk.GetIStorage(); err != nil {
return err
} else if iStoragecache := iStorage.GetIStoragecache(); iStoragecache == nil {
return httperrors.NewResourceNotFoundError("fail to find iStoragecache for storage: %s", iStorage.GetName())
} else {
taskman.LocalTaskRun(task, func() (jsonutils.JSONObject, error) {
if snapshot, err := iDisk.CreateISnapshot(fmt.Sprintf("Snapshot-%s", imageId), "PrepareSaveImage"); err != nil {
return nil, err
} else {
params := task.GetParams()
osType, _ := params.GetString("properties", "os_type")
scimg := models.StoragecachedimageManager.Register(ctx, task.GetUserCred(), iStoragecache.GetId(), imageId)
if scimg.Status != models.CACHED_IMAGE_STATUS_READY {
scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHING, "request_prepare_save_disk_on_host")
}
if iImage, err := iStoragecache.CreateIImage(snapshot.GetId(), fmt.Sprintf("Image-%s", imageId), osType, ""); err != nil {
log.Errorf("fail to create iImage: %v", err)
scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHE_FAILED, err.Error())
return nil, err
} else {
scimg.SetExternalId(iImage.GetId())
if result, err := iStoragecache.DownloadImage(task.GetUserCred(), imageId, iImage.GetId(), options.Options.TempPath); err != nil {
scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_CACHE_FAILED, err.Error())
return nil, err
} else {
if err := iImage.Delete(); err != nil {
log.Errorf("Delete iImage %s failed: %v", iImage.GetId(), err)
}
if err := snapshot.Delete(); err != nil {
log.Errorf("Delete snapshot %s failed: %v", snapshot.GetId(), err)
}
scimg.SetStatus(task.GetUserCred(), models.CACHED_IMAGE_STATUS_READY, "")
return result, nil
}
}
}
})
}
return nil
}
func (self *SAwsHostDriver) RequestAllocateDiskOnStorage(ctx context.Context, host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask, content *jsonutils.JSONDict) error {
if iCloudStorage, err := storage.GetIStorage(); err != nil {
return err
} else {
if size, err := content.Int("size"); err != nil {
return err
} else {
size = size >> 10
if iDisk, err := iCloudStorage.CreateIDisk(disk.GetName(), int(size), ""); err != nil {
return err
} else {
if _, err := disk.GetModelManager().TableSpec().Update(disk, func() error {
disk.ExternalId = iDisk.GetGlobalId()
if metaData := iDisk.GetMetadata(); metaData != nil {
meta := make(map[string]string)
if err := metaData.Unmarshal(meta); err != nil {
log.Errorf("Get disk %s Metadata error: %v", disk.Name, err)
} else {
for key, value := range meta {
if err := disk.SetMetadata(ctx, key, value, task.GetUserCred()); err != nil {
log.Errorf("set disk %s mata %s => %s error: %v", disk.Name, key, value, err)
}
}
}
}
return nil
}); err != nil {
log.Errorf("Update disk externalId err: %v", err)
return err
}
data := jsonutils.NewDict()
data.Add(jsonutils.NewInt(int64(iDisk.GetDiskSizeMB())), "disk_size")
data.Add(jsonutils.NewString(iDisk.GetDiskFormat()), "disk_format")
task.ScheduleRun(data)
}
}
}
return nil
}
func (self *SAwsHostDriver) RequestDeallocateDiskOnHost(host *models.SHost, storage *models.SStorage, disk *models.SDisk, task taskman.ITask) error {
data := jsonutils.NewDict()
if iCloudStorage, err := storage.GetIStorage(); err != nil {
return err
} else if iDisk, err := iCloudStorage.GetIDisk(disk.GetExternalId()); err != nil {
if err == cloudprovider.ErrNotFound {
task.ScheduleRun(data)
return nil
}
return err
} else if err := iDisk.Delete(); err != nil {
return err
}
task.ScheduleRun(data)
return nil
}
func (self *SAwsHostDriver) RequestResizeDiskOnHostOnline(host *models.SHost, storage *models.SStorage, disk *models.SDisk, size int64, task taskman.ITask) error {
return self.RequestResizeDiskOnHost(host, storage, disk, size, task)
}
func (self *SAwsHostDriver) RequestResizeDiskOnHost(host *models.SHost, storage *models.SStorage, disk *models.SDisk, size int64, task taskman.ITask) error {
if iCloudStorage, err := storage.GetIStorage(); err != nil {
return err
} else if iDisk, err := iCloudStorage.GetIDisk(disk.GetExternalId()); err != nil {
return err
} else if err := iDisk.Resize(size >> 10); err != nil {
return err
} else {
task.ScheduleRun(jsonutils.Marshal(map[string]int64{"disk_size": size}))
}
return nil
}
func init() {
driver := SAwsHostDriver{}
models.RegisterHostDriver(&driver)
}
+1
View File
@@ -33,6 +33,7 @@ const (
CLOUD_PROVIDER_ALIYUN = "Aliyun"
CLOUD_PROVIDER_QCLOUD = "Qcloud"
CLOUD_PROVIDER_AZURE = "Azure"
CLOUD_PROVIDER_AWS = "Aws"
)
type SCloudproviderManager struct {
+5 -2
View File
@@ -128,6 +128,7 @@ const (
HYPERVISOR_ALIYUN = "aliyun"
HYPERVISOR_QCLOUD = "qcloud"
HYPERVISOR_AZURE = "azure"
HYPERVISOR_AWS = "aws"
// HYPERVISOR_DEFAULT = HYPERVISOR_KVM
HYPERVISOR_DEFAULT = HYPERVISOR_ALIYUN
@@ -136,9 +137,9 @@ const (
var VM_RUNNING_STATUS = []string{VM_START_START, VM_STARTING, VM_RUNNING, VM_SNAPSHOT_STREAM}
var VM_CREATING_STATUS = []string{VM_CREATE_NETWORK, VM_CREATE_DISK, VM_START_DEPLOY, VM_DEPLOYING}
var HYPERVISORS = []string{HYPERVISOR_KVM, HYPERVISOR_BAREMETAL, HYPERVISOR_ESXI, HYPERVISOR_CONTAINER, HYPERVISOR_ALIYUN, HYPERVISOR_AZURE, HYPERVISOR_QCLOUD}
var HYPERVISORS = []string{HYPERVISOR_KVM, HYPERVISOR_BAREMETAL, HYPERVISOR_ESXI, HYPERVISOR_CONTAINER, HYPERVISOR_ALIYUN, HYPERVISOR_AZURE, HYPERVISOR_AWS, HYPERVISOR_QCLOUD}
var PUBLIC_CLOUD_HYPERVISORS = []string{HYPERVISOR_ALIYUN, HYPERVISOR_AZURE}
var PUBLIC_CLOUD_HYPERVISORS = []string{HYPERVISOR_ALIYUN, HYPERVISOR_AWS, HYPERVISOR_AZURE, HYPERVISOR_QCLOUD}
// var HYPERVISORS = []string{HYPERVISOR_ALIYUN}
@@ -149,6 +150,7 @@ var HYPERVISOR_HOSTTYPE = map[string]string{
HYPERVISOR_CONTAINER: HOST_TYPE_KUBELET,
HYPERVISOR_ALIYUN: HOST_TYPE_ALIYUN,
HYPERVISOR_AZURE: HOST_TYPE_AZURE,
HYPERVISOR_AWS: HOST_TYPE_AWS,
HYPERVISOR_QCLOUD: HOST_TYPE_QCLOUD,
}
@@ -159,6 +161,7 @@ var HOSTTYPE_HYPERVISOR = map[string]string{
HOST_TYPE_KUBELET: HYPERVISOR_CONTAINER,
HOST_TYPE_ALIYUN: HYPERVISOR_ALIYUN,
HOST_TYPE_AZURE: HYPERVISOR_AZURE,
HOST_TYPE_AWS: HYPERVISOR_AWS,
HOST_TYPE_QCLOUD: HYPERVISOR_QCLOUD,
}
+3 -1
View File
@@ -43,6 +43,7 @@ const (
HOST_TYPE_HYPERV = "hyperv" // # Microsoft Hyper-V
HOST_TYPE_XEN = "xen" // # XenServer
HOST_TYPE_ALIYUN = "aliyun"
HOST_TYPE_AWS = "aws"
HOST_TYPE_QCLOUD = "qcloud"
HOST_TYPE_AZURE = "azure"
@@ -82,7 +83,8 @@ const (
HOST_STATUS_UNKNOWN = BAREMETAL_UNKNOWN
)
var HOST_TYPES = []string{HOST_TYPE_BAREMETAL, HOST_TYPE_HYPERVISOR, HOST_TYPE_ESXI, HOST_TYPE_KUBELET, HOST_TYPE_XEN, HOST_TYPE_ALIYUN, HOST_TYPE_AZURE, HOST_TYPE_QCLOUD}
var HOST_TYPES = []string{HOST_TYPE_BAREMETAL, HOST_TYPE_HYPERVISOR, HOST_TYPE_ESXI, HOST_TYPE_KUBELET, HOST_TYPE_XEN, HOST_TYPE_ALIYUN, HOST_TYPE_AZURE, HOST_TYPE_AWS, HOST_TYPE_QCLOUD}
var NIC_TYPES = []string{NIC_TYPE_IPMI, NIC_TYPE_ADMIN}
type SHostManager struct {
+5
View File
@@ -29,6 +29,11 @@ const (
STORAGE_CLOUD_EFFICIENCY = "cloud_efficiency"
STORAGE_CLOUD_SSD = "cloud_ssd"
STORAGE_EPHEMERAL_SSD = "ephemeral_ssd"
STORAGE_GP2_SSD = "gp2" // aws general purpose ssd
STORAGE_IO1_SSD = "io1" // aws Provisioned IOPS SSD
STORAGE_ST1_HDD = "st1" // aws Throughput Optimized HDD
STORAGE_SC1_SSD = "sc1" // aws Cold HDD
STORAGE_STANDARD_SSD = "standard" // aws Magnetic volumes
STORAGE_ENABLED = "enabled"
STORAGE_DISABLED = "disabled"
+3
View File
@@ -58,6 +58,9 @@ type ComputeOptions struct {
DefaultMaxSnapshotCount int `default:"9" help:"Per Disk max snapshot count, default 9"`
DefaultMaxManualSnapshotCount int `default:"2" help:"Per Disk max manual snapshot count, default 2"`
// aws instance type file
DefaultAwsInstanceTypeFile string `default:"/etc/yunion/aws_instance_types.json" help:"aws instance type json file"`
ConvertHypervisorDefaultTemplate string `default:"Default template" help:"Kvm baremetal convert option"`
ConvertEsxiDefaultTemplate string `default:"Default template" help:"ESXI baremetal convert option"`
ConvertKubeletDockerVolumeSize string `default:"256g" help:"Docker volume size"`
+1
View File
@@ -12,6 +12,7 @@ import (
_ "yunion.io/x/onecloud/pkg/compute/hostdrivers"
_ "yunion.io/x/onecloud/pkg/compute/tasks"
_ "yunion.io/x/onecloud/pkg/util/aliyun/provider"
_ "yunion.io/x/onecloud/pkg/util/aws/provider"
_ "yunion.io/x/onecloud/pkg/util/azure/provider"
_ "yunion.io/x/onecloud/pkg/util/esxi/provider"
_ "yunion.io/x/onecloud/pkg/util/qcloud/provider"
+2
View File
@@ -18,6 +18,7 @@ const (
HostHypervisorForKvm = "hypervisor"
HostTypeAliyun = "aliyun"
HostTypeAzure = "azure"
HostTypeAws = "aws"
HostTypeQcloud = "qcloud"
HostTypeKubelet = "kubelet"
@@ -51,6 +52,7 @@ var (
PublicCloudProviders = sets.NewString(
HostTypeAliyun,
HostTypeAzure,
HostTypeAws,
HostTypeQcloud,
)
+58
View File
@@ -150,6 +150,58 @@ func (self *SRegion) GetInstances(zoneId string, ids []string, offset int, limit
return instances, int(total), nil
}
func (self *SRegion) fetchTags(resourceType string, resourceId string) (*jsonutils.JSONDict, error) {
// 资源类型。取值范围:
// disk
// instance
// image
// securitygroup
// snapshot
var page int64 = 1
var pageSize int64 = 50
params := make(map[string]string)
params["RegionId"] = self.RegionId
params["ResourceType"] = resourceType
params["ResourceId"] = resourceId
params["PageSize"] = fmt.Sprintf("%d", pageSize)
params["PageNumber"] = fmt.Sprintf("%d", page)
ret, err := self.ecsRequest("DescribeTags", params)
if err != nil {
return nil, err
}
tags := jsonutils.NewDict()
result, _ := ret.GetArray("Tags", "Tag")
for _, item := range result {
k, _ := item.GetString("TagKey")
v, _ := item.Get("TagValue")
if len(k) > 0 {
tags.Set(k, v)
}
}
total, _ := ret.Int("TotalCount")
for ; total > page*pageSize; page++ {
params["PageSize"] = fmt.Sprintf("%d", pageSize)
params["PageNumber"] = fmt.Sprintf("%d", page)
ret, err := self.ecsRequest("DescribeTags", params)
if err != nil {
return nil, err
}
result, _ := ret.GetArray("Tags", "Tag")
for _, item := range result {
k, _ := item.GetString("TagKey")
v, _ := item.Get("TagValue")
if len(k) > 0 {
tags.Set(k, v)
}
}
}
return tags, nil
}
func (self *SInstance) GetMetadata() *jsonutils.JSONDict {
data := jsonutils.NewDict()
@@ -161,6 +213,12 @@ func (self *SInstance) GetMetadata() *jsonutils.JSONDict {
priceKey := fmt.Sprintf("%s::%s::%s::%s::%s", self.RegionId, self.InstanceType, self.InstanceNetworkType, self.OSType, optimized)
data.Add(jsonutils.NewString(priceKey), "price_key")
tags, err := self.host.zone.region.fetchTags("instance", self.InstanceId)
if err != nil {
log.Errorf(err.Error())
}
data.Update(tags)
if len(self.ImageId) > 0 {
if image, err := self.host.zone.region.GetImage(self.ImageId); err != nil {
log.Errorf("Failed to find image %s for instance %s", self.ImageId, self.GetName())
-1
View File
@@ -156,7 +156,6 @@ func init() {
return e
}
// todo : add create disks
err := cli.ChangeVMConfig(instance.ZoneId, args.ID, args.Ncpu, args.Vmem, nil)
if err != nil {
return err
+210
View File
@@ -0,0 +1,210 @@
package aws
import (
"github.com/coredns/coredns/plugin/pkg/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
sdk "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
)
const (
CLOUD_PROVIDER_AWS = models.CLOUD_PROVIDER_AWS
CLOUD_PROVIDER_AWS_CN = "AWS"
AWS_INTERNATIONAL_DEFAULT_REGION = "us-west-1"
AWS_CHINA_DEFAULT_REGION = "cn-north-1"
AWS_API_VERSION = "2018-10-10"
)
type SAwsClient struct {
providerId string
providerName string
accessUrl string // 服务区域 ChinaCloud | InternationalCloud
accessKey string
secret string
iregions []cloudprovider.ICloudRegion
}
func NewAwsClient(providerId string, providerName string, accessUrl string, accessKey string, secret string) (*SAwsClient, error) {
client := SAwsClient{providerId: providerId, providerName: providerName, accessUrl: accessUrl, accessKey: accessKey, secret: secret}
err := client.fetchRegions()
if err != nil {
return nil, err
}
return &client, nil
}
func (self *SAwsClient) getDefaultSession() (*session.Session, error) {
defaultRegion := AWS_INTERNATIONAL_DEFAULT_REGION
switch self.accessUrl {
case "InternationalCloud":
defaultRegion = AWS_INTERNATIONAL_DEFAULT_REGION
case "ChinaCloud":
defaultRegion = AWS_CHINA_DEFAULT_REGION
}
return session.NewSession(&sdk.Config{
Region: sdk.String(defaultRegion),
Credentials: credentials.NewStaticCredentials(self.accessKey, self.secret, ""),
})
}
func (self *SAwsClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
// todo: implement me
err := self.fetchRegions()
if err != nil {
return nil, err
}
subAccount := cloudprovider.SSubAccount{}
subAccount.Name = self.providerName
subAccount.Account = self.accessKey
return []cloudprovider.SSubAccount{subAccount}, nil
}
func (self *SAwsClient) UpdateAccount(accessKey, secret string) error {
if self.accessKey != accessKey || self.secret != secret {
self.accessKey = accessKey
self.secret = secret
return self.fetchRegions()
} else {
return nil
}
}
// 用于初始化region信息
func (self *SAwsClient) fetchRegions() error {
s, err := self.getDefaultSession()
if err != nil {
return err
}
svc := ec2.New(s)
// https://docs.aws.amazon.com/sdk-for-go/api/service/ec2/#EC2.DescribeRegions
result, err := svc.DescribeRegions(&ec2.DescribeRegionsInput{})
log.Debugf("remote regions: %s", result)
if err != nil {
return err
}
regions := make([]SRegion, 0)
// empty iregions
if self.iregions != nil {
self.iregions = self.iregions[:0]
}
for _, region := range result.Regions {
name := *region.RegionName
endpoint := *region.Endpoint
sregion := SRegion{client: self, RegionId: name, RegionEndpoint: endpoint}
// 初始化region client
sregion.getEc2Client()
regions = append(regions, sregion)
self.iregions = append(self.iregions, &sregion)
}
return nil
}
// 只是使用fetchRegions初始化好的self.iregions. 本身并不从云服务器厂商拉取region信息
func (self *SAwsClient) GetRegions() []SRegion {
regions := make([]SRegion, len(self.iregions))
for i := 0; i < len(regions); i += 1 {
region := self.iregions[i].(*SRegion)
regions[i] = *region
}
return regions
}
func (self *SAwsClient) GetIRegions() []cloudprovider.ICloudRegion {
return self.iregions
}
func (self *SAwsClient) GetRegion(regionId string) *SRegion {
if len(regionId) == 0 {
regionId = AWS_INTERNATIONAL_DEFAULT_REGION
switch self.accessUrl {
case "InternationalCloud":
regionId = AWS_INTERNATIONAL_DEFAULT_REGION
case "ChinaCloud":
regionId = AWS_CHINA_DEFAULT_REGION
}
}
for i := 0; i < len(self.iregions); i += 1 {
if self.iregions[i].GetId() == regionId {
return self.iregions[i].(*SRegion)
}
}
return nil
}
func (self *SAwsClient) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
for i := 0; i < len(self.iregions); i += 1 {
if self.iregions[i].GetGlobalId() == id {
return self.iregions[i], nil
}
}
return nil, cloudprovider.ErrNotFound
}
func (self *SAwsClient) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
for i := 0; i < len(self.iregions); i += 1 {
ihost, err := self.iregions[i].GetIHostById(id)
if err == nil {
return ihost, nil
} else if err != cloudprovider.ErrNotFound {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
}
func (self *SAwsClient) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
for i := 0; i < len(self.iregions); i += 1 {
ihost, err := self.iregions[i].GetIVpcById(id)
if err == nil {
return ihost, nil
} else if err != cloudprovider.ErrNotFound {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
}
func (self *SAwsClient) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
for i := 0; i < len(self.iregions); i += 1 {
ihost, err := self.iregions[i].GetIStorageById(id)
if err == nil {
return ihost, nil
} else if err != cloudprovider.ErrNotFound {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
}
func (self *SAwsClient) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) {
for i := 0; i < len(self.iregions); i += 1 {
ihost, err := self.iregions[i].GetIStoragecacheById(id)
if err == nil {
return ihost, nil
} else if err != cloudprovider.ErrNotFound {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
}
type SAccountBalance struct {
AvailableAmount float64
AvailableCashAmount float64
CreditAmount float64
MybankCreditAmount float64
Currency string
}
func (self *SAwsClient) QueryAccountBalance() (*SAccountBalance, error) {
// todo: aws 貌似没有余额?
panic("implement me")
}
+393
View File
@@ -0,0 +1,393 @@
package aws
import (
"fmt"
"time"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/coredns/coredns/plugin/pkg/log"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
)
type SMountInstances struct {
MountInstance []string
}
type STags struct {
Tag []string
}
type SDisk struct {
storage *SStorage
RegionId string
ZoneId string // AvailabilityZone
DiskId string // VolumeId
DiskName string // Tag Name
Size int // Size
Category string // VolumeType
Type string // system | data
Status string // State
AttachmentStatus string // attachment.status
Device string // Device
InstanceId string // InstanceId
Encrypted bool // Encrypted
SourceSnapshotId string // SnapshotId
Iops int // Iops
Tags TagSpec
CreationTime time.Time // CreateTime
AttachedTime time.Time // AttachTime
DetachedTime time.Time
DeleteWithInstance bool // DeleteOnTermination
EnableAutoSnapshot bool
EnableAutomatedSnapshotPolicy bool
/*下面这些字段也许不需要*/
AutoSnapshotPolicyId string
DeleteAutoSnapshot bool
Description string
DiskChargeType InstanceChargeType
ExpiredTime time.Time
ImageId string
MountInstances SMountInstances
Portable bool
ProductCode string
ResourceGroupId string
}
func (self *SDisk) GetId() string {
return self.DiskId
}
func (self *SDisk) GetName() string {
if len(self.DiskName) > 0 {
return self.DiskName
}
return self.DiskId
}
func (self *SDisk) GetGlobalId() string {
return self.DiskId
}
func (self *SDisk) GetStatus() string {
// creating | available | in-use | deleting | deleted | error
switch self.Status {
case "creating":
return models.DISK_ALLOCATING
case "deleting":
return models.DISK_DEALLOC
case "error":
return models.DISK_ALLOC_FAILED
default:
return models.DISK_READY
}
}
func (self *SDisk) Refresh() error {
new, err := self.storage.zone.region.GetDisk(self.DiskId)
if err != nil {
return err
}
return jsonutils.Update(self, new)
}
func (self *SDisk) IsEmulated() bool {
return false
}
func (self *SDisk) GetMetadata() *jsonutils.JSONDict {
data := jsonutils.NewDict()
data.Add(jsonutils.NewString(models.HYPERVISOR_AWS), "hypervisor")
return data
}
func (self *SDisk) GetBillingType() string {
// todo: implement me
return models.BILLING_TYPE_PREPAID
}
func (self *SDisk) GetExpiredAt() time.Time {
return self.ExpiredTime
}
func (self *SDisk) GetIStorge() cloudprovider.ICloudStorage {
return self.storage
}
func (self *SDisk) GetDiskFormat() string {
return "vhd"
}
func (self *SDisk) GetDiskSizeMB() int {
return self.Size * 1024
}
func (self *SDisk) GetIsAutoDelete() bool {
return self.DeleteWithInstance
}
func (self *SDisk) GetTemplateId() string {
return self.ImageId
}
func (self *SDisk) GetDiskType() string {
return self.Type
}
func (self *SDisk) GetFsFormat() string {
return ""
}
func (self *SDisk) GetIsNonPersistent() bool {
return false
}
func (self *SDisk) GetDriver() string {
return "scsi"
}
func (self *SDisk) GetCacheMode() string {
return "none"
}
func (self *SDisk) GetMountpoint() string {
return ""
}
func (self *SDisk) Delete() error {
if _, err := self.storage.zone.region.GetDisk(self.DiskId); err == cloudprovider.ErrNotFound {
log.Errorf("Failed to find disk %s when delete", self.DiskId)
return nil
}
return self.storage.zone.region.DeleteDisk(self.DiskId)
}
func (self *SDisk) CreateISnapshot(name string, desc string) (cloudprovider.ICloudSnapshot, error) {
if snapshotId, err := self.storage.zone.region.CreateSnapshot(self.DiskId, name, desc); err != nil {
log.Errorf("createSnapshot fail %s", err)
return nil, err
} else if snapshot, err := self.getSnapshot(snapshotId); err != nil {
return nil, err
} else {
snapshot.region = self.storage.zone.region
if err := cloudprovider.WaitStatus(snapshot, models.SNAPSHOT_READY, 15*time.Second, 3600*time.Second); err != nil {
return nil, err
}
return snapshot, nil
}
}
func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) {
if snapshot, err := self.getSnapshot(snapshotId); err != nil {
return nil, err
} else {
snapshot.region = self.storage.zone.region
return snapshot, nil
}
}
func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
snapshots := make([]SSnapshot, 0)
for {
if parts, total, err := self.storage.zone.region.GetSnapshots("", self.DiskId, "", []string{}, 0, 20); err != nil {
log.Errorf("GetDisks fail %s", err)
return nil, err
} else {
snapshots = append(snapshots, parts...)
if len(snapshots) >= total {
break
}
}
}
isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots))
for i := 0; i < len(snapshots); i++ {
snapshots[i].region = self.storage.zone.region
isnapshots[i] = &snapshots[i]
}
return isnapshots, nil
}
func (self *SDisk) Resize(newSize int64) error {
return self.storage.zone.region.resizeDisk(self.DiskId, newSize)
}
func (self *SDisk) Reset(snapshotId string) error {
return self.storage.zone.region.resetDisk(self.DiskId, snapshotId)
}
func (self *SDisk) getSnapshot(snapshotId string) (*SSnapshot, error) {
if snapshots, total, err := self.storage.zone.region.GetSnapshots("", "", "", []string{snapshotId}, 0, 1); err != nil {
return nil, err
} else if total != 1 {
return nil, cloudprovider.ErrNotFound
} else {
return &snapshots[0], nil
}
}
func (self *SRegion) GetDisks(instanceId string, zoneId string, storageType string, diskIds []string, offset int, limit int) ([]SDisk, int, error) {
params := &ec2.DescribeVolumesInput{}
filters := make([]*ec2.Filter, 0)
if len(instanceId) > 0 {
filters = AppendSingleValueFilter(filters, "attachment.instance-id", instanceId)
}
if len(zoneId) > 0 {
filters = AppendSingleValueFilter(filters, "availability-zone", zoneId)
}
if len(storageType) > 0 {
filters = AppendSingleValueFilter(filters, "volume-type", storageType)
}
if len(filters) > 0 {
params.SetFilters(filters)
}
if len(diskIds) > 0 {
params.SetVolumeIds(ConvertedList(diskIds))
}
ret, err := self.ec2Client.DescribeVolumes(params)
if err != nil {
return nil, 0, err
}
disks := []SDisk{}
for _, item := range ret.Volumes {
if err := FillZero(item); err != nil {
return nil, 0, err
}
tagspec := TagSpec{}
tagspec.LoadingEc2Tags(item.Tags)
disk := SDisk{}
disk.ZoneId = *item.AvailabilityZone
disk.Status = *item.State
disk.DiskName = tagspec.GetNameTag()
disk.Size = int(*item.Size)
disk.Category = *item.VolumeType
disk.RegionId = self.RegionId
disk.SourceSnapshotId = *item.SnapshotId
disk.Encrypted = *item.Encrypted
disk.DiskId = *item.VolumeId
disk.Iops = int(*item.Iops)
disk.CreationTime = *item.CreateTime
disk.Tags = tagspec
if len(item.Attachments) > 0 {
disk.DeleteWithInstance = *item.Attachments[0].DeleteOnTermination
disk.AttachedTime = *item.Attachments[0].AttachTime
disk.AttachmentStatus = *item.Attachments[0].State
disk.Device = StrVal(item.Attachments[0].Device)
disk.InstanceId = StrVal(item.Attachments[0].InstanceId)
// todo: 需要通过describe-instances 的root device 判断是否是系统盘
// todo: 系统盘需要放在返回disks列表的首位
if len(disk.InstanceId) > 0 {
instance, err := self.GetInstance(disk.InstanceId)
if err != nil {
log.Debug(err)
return nil, 0, err
}
if disk.Device == instance.RootDeviceName {
disk.Type = models.DISK_TYPE_SYS
} else {
disk.Type = models.DISK_TYPE_DATA
}
} else {
disk.Type = models.DISK_TYPE_DATA
}
}
disks = append(disks, disk)
}
return disks, len(disks), nil
}
func (self *SRegion) GetDisk(diskId string) (*SDisk, error) {
disks, total, err := self.GetDisks("", "", "", []string{diskId}, 0, 1)
if err != nil {
return nil, err
}
if total != 1 {
return nil, cloudprovider.ErrNotFound
}
return &disks[0], nil
}
func (self *SRegion) DeleteDisk(diskId string) error {
disk, err := self.GetDisk(diskId)
if err != nil {
return err
}
if disk.Status != ec2.VolumeStateAvailable {
return fmt.Errorf("disk status not in %s", ec2.VolumeStateAvailable)
}
params := &ec2.DeleteVolumeInput{}
if len(diskId) <= 0 {
return fmt.Errorf("disk id should not be empty")
}
params.SetVolumeId(diskId)
_, err = self.ec2Client.DeleteVolume(params)
return err
}
func (self *SRegion) resizeDisk(diskId string, size int64) error {
// https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/volume_constraints.html
// MBR -> 2 TiB
// GPT -> 16 TiB
// size unit GiB
params := &ec2.ModifyVolumeInput{}
if size > 0 {
params.SetSize(size)
} else {
return fmt.Errorf("size should great than 0")
}
if len(diskId) <= 0 {
return fmt.Errorf("disk id should not be empty")
} else {
params.SetVolumeId(diskId)
}
_, err := self.ec2Client.ModifyVolume(params)
return err
}
func (self *SRegion) resetDisk(diskId, snapshotId string) error {
// aws貌似不支持直接重置
return cloudprovider.ErrNotImplemented
}
func (self *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, snapshotId string, desc string) (string, error) {
tagspec := TagSpec{ResourceType: "volume"}
tagspec.SetNameTag(name)
tagspec.SetDescTag(desc)
ec2Tags, _ := tagspec.GetTagSpecifications()
params := &ec2.CreateVolumeInput{}
params.SetAvailabilityZone(zoneId)
params.SetVolumeType(category)
params.SetSize(int64(sizeGb))
if len(snapshotId) > 0 {
params.SetSnapshotId(snapshotId)
}
params.SetTagSpecifications([]*ec2.TagSpecification{ec2Tags})
ret, err := self.ec2Client.CreateVolume(params)
if err != nil {
return "", err
}
return StrVal(ret.VolumeId), nil
}
+256
View File
@@ -0,0 +1,256 @@
package aws
import (
"fmt"
"time"
"github.com/aws/aws-sdk-go/service/ec2"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
)
const (
EIP_STATUS_INUSE = "InUse"
EIP_STATUS_AVAILABLE = "Available"
)
type SEipAddress struct {
region *SRegion
AllocationId string
Bandwidth int
Tags TagSpec
Status string
InstanceId string
AssociationId string
Domain string
NetworkInterfaceId string
NetworkInterfaceOwnerId string
PrivateIpAddress string
IpAddress string
}
func (self *SEipAddress) GetId() string {
return self.AllocationId
}
func (self *SEipAddress) GetName() string {
return self.IpAddress
}
func (self *SEipAddress) GetGlobalId() string {
return self.AllocationId
}
func (self *SEipAddress) GetStatus() string {
switch self.Status {
// todo: EIP_STATUS_INUSE 对应READY?
case EIP_STATUS_AVAILABLE, EIP_STATUS_INUSE:
return models.EIP_STATUS_READY
default:
return models.EIP_STATUS_UNKNOWN
}
}
func (self *SEipAddress) Refresh() error {
if self.IsEmulated() {
return nil
}
new, err := self.region.GetEip(self.AllocationId)
if err != nil {
return err
}
return jsonutils.Update(self, new)
}
func (self *SEipAddress) IsEmulated() bool {
if self.AllocationId == self.InstanceId {
return true
}
return false
}
func (self *SEipAddress) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (self *SEipAddress) GetIpAddr() string {
return self.IpAddress
}
func (self *SEipAddress) GetMode() string {
if self.InstanceId == self.AllocationId {
return models.EIP_MODE_INSTANCE_PUBLICIP
} else {
return models.EIP_MODE_STANDALONE_EIP
}
}
func (self *SEipAddress) GetAssociationType() string {
// todo : ?
return "server"
}
func (self *SEipAddress) GetAssociationExternalId() string {
return self.InstanceId
}
func (self *SEipAddress) GetBandwidth() int {
return self.Bandwidth
}
func (self *SEipAddress) GetInternetChargeType() string {
// todo : implement me
return models.EIP_CHARGE_TYPE_BY_TRAFFIC
}
func (self *SEipAddress) GetManagerId() string {
return self.region.client.providerId
}
func (self *SEipAddress) Delete() error {
return self.region.DeallocateEIP(self.AllocationId)
}
func (self *SEipAddress) Associate(instanceId string) error {
err := self.region.AssociateEip(self.AllocationId, instanceId)
if err != nil {
return err
}
err = cloudprovider.WaitStatus(self, models.EIP_STATUS_READY, 10*time.Second, 180*time.Second)
return err
}
func (self *SEipAddress) Dissociate() error {
err := self.region.DissociateEip(self.AllocationId, self.InstanceId)
if err != nil {
return err
}
err = cloudprovider.WaitStatus(self, models.EIP_STATUS_READY, 10*time.Second, 180*time.Second)
return err
}
func (self *SEipAddress) ChangeBandwidth(bw int) error {
return self.region.UpdateEipBandwidth(self.AllocationId, bw)
}
func (self *SRegion) GetEips(eipId string, offset int, limit int) ([]SEipAddress, int, error) {
params := ec2.DescribeAddressesInput{}
if len(eipId) > 0 {
params.SetAllocationIds([]*string{&eipId})
}
res, err := self.ec2Client.DescribeAddresses(&params)
if err != nil {
log.Errorf("DescribeEipAddresses fail %s", err)
return nil, 0, err
}
eips := make([]SEipAddress, 0)
for _, ip := range res.Addresses {
if err := FillZero(ip); err != nil {
return nil, 0, err
}
tagspec := TagSpec{ResourceType: "eip"}
tagspec.LoadingEc2Tags(ip.Tags)
var status string
if len(*ip.AssociationId) > 0 {
status = EIP_STATUS_INUSE
} else {
status = EIP_STATUS_AVAILABLE
}
eips = append(eips, SEipAddress{
region: self,
AllocationId: *ip.AllocationId,
Tags: tagspec,
Status: status,
InstanceId: *ip.InstanceId,
AssociationId: *ip.AssociationId,
Domain: *ip.Domain,
NetworkInterfaceId: *ip.NetworkInterfaceId,
NetworkInterfaceOwnerId: *ip.NetworkInterfaceOwnerId,
PrivateIpAddress: *ip.PrivateIpAddress,
IpAddress: *ip.PublicIp,
})
}
return eips, len(eips), nil
}
func (self *SRegion) GetEip(eipId string) (*SEipAddress, error) {
eips, total, err := self.GetEips(eipId, 0, 0)
if err != nil {
return nil, err
}
if total != 1 {
return nil, cloudprovider.ErrNotFound
}
return &eips[0], nil
}
func (self *SRegion) AllocateEIP(domainType string) (*SEipAddress, error) {
params := &ec2.AllocateAddressInput{}
params.SetDomain(domainType)
eip, err := self.ec2Client.AllocateAddress(params)
if err != nil {
log.Errorf("AllocateEipAddress fail %s", err)
return nil, err
}
err = self.fetchInfrastructure()
if err != nil {
return nil, err
}
return self.GetEip(*eip.AllocationId)
}
func (self *SRegion) CreateEIP(name string, bwMbps int, chargeType string) (cloudprovider.ICloudEIP, error) {
// todo: aws 不支持指定bwMbps, chargeType ?
log.Debugf("CreateEip: aws not support specific params name/bwMbps/chargeType.")
return self.AllocateEIP("vpc")
}
func (self *SRegion) DeallocateEIP(eipId string) error {
params := &ec2.ReleaseAddressInput{}
params.SetAllocationId(eipId)
_, err := self.ec2Client.ReleaseAddress(params)
return err
}
func (self *SRegion) AssociateEip(eipId string, instanceId string) error {
params := &ec2.AssociateAddressInput{}
params.SetAllocationId(eipId)
params.SetInstanceId(instanceId)
_, err := self.ec2Client.AssociateAddress(params)
return err
}
func (self *SRegion) DissociateEip(eipId string, instanceId string) error {
eip, err := self.GetEip(eipId)
if err != nil {
return err
}
if len(eip.AssociationId) == 0 {
// 已经是解绑状态
return nil
}
if eip.InstanceId != instanceId {
return fmt.Errorf("eip %s associate with another instance %s", eipId, eip.InstanceId)
}
params := &ec2.DisassociateAddressInput{}
params.SetAssociationId(eip.AssociationId)
_, err = self.ec2Client.DisassociateAddress(params)
return err
}
func (self *SRegion) UpdateEipBandwidth(eipId string, bw int) error {
return cloudprovider.ErrNotSupported
}
+270
View File
@@ -0,0 +1,270 @@
package aws
import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
)
type SHost struct {
zone *SZone
}
func (self *SHost) GetId() string {
return fmt.Sprintf("%s-%s", self.zone.region.client.providerId, self.zone.GetId())
}
func (self *SHost) GetName() string {
return fmt.Sprintf("%s-%s", self.zone.region.client.providerName, self.zone.GetId())
}
func (self *SHost) GetGlobalId() string {
return fmt.Sprintf("%s-%s", self.zone.region.client.providerId, self.zone.GetId())
}
func (self *SHost) GetStatus() string {
return models.HOST_STATUS_RUNNING
}
func (self *SHost) Refresh() error {
return nil
}
func (self *SHost) IsEmulated() bool {
return true
}
func (self *SHost) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) {
vms := make([]SInstance, 0)
vms, _, err := self.zone.region.GetInstances(self.zone.ZoneId, nil, len(vms), 50)
if err != nil {
return nil, err
}
ivms := make([]cloudprovider.ICloudVM, len(vms))
for i := 0; i < len(vms); i += 1 {
vms[i].host = self
ivms[i] = &vms[i]
}
return ivms, nil
}
func (self *SHost) GetIVMById(gid string) (cloudprovider.ICloudVM, error) {
log.Debugf("GetIVMById %s", gid)
ivms, _, err := self.zone.region.GetInstances(self.zone.ZoneId, []string{gid}, 0, 1)
if err != nil {
return nil, err
}
if len(ivms) == 0 {
return nil, cloudprovider.ErrNotFound
}
if len(ivms) > 1 {
return nil, cloudprovider.ErrDuplicateId
}
ivms[0].host = self
return &ivms[0], nil
}
func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) {
return self.zone.GetIWires()
}
func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
return self.zone.GetIStorages()
}
func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
return self.zone.GetIStorageById(id)
}
func (self *SHost) GetEnabled() bool {
return true
}
func (self *SHost) GetHostStatus() string {
return models.HOST_ONLINE
}
func (self *SHost) GetAccessIp() string {
return ""
}
func (self *SHost) GetAccessMac() string {
return ""
}
func (self *SHost) GetSysInfo() jsonutils.JSONObject {
info := jsonutils.NewDict()
info.Add(jsonutils.NewString(CLOUD_PROVIDER_AWS), "manufacture")
return info
}
func (self *SHost) GetSN() string {
return ""
}
func (self *SHost) GetCpuCount() int8 {
return 0
}
func (self *SHost) GetNodeCount() int8 {
return 0
}
func (self *SHost) GetCpuDesc() string {
return ""
}
func (self *SHost) GetCpuMhz() int {
return 0
}
func (self *SHost) GetMemSizeMB() int {
return 0
}
func (self *SHost) GetStorageSizeMB() int {
return 0
}
func (self *SHost) GetStorageType() string {
return models.DISK_TYPE_HYBRID
}
func (self *SHost) GetHostType() string {
return models.HOST_TYPE_AWS
}
func (self *SHost) GetManagerId() string {
return self.zone.region.client.providerId
}
func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) {
inst, err := self.zone.region.GetInstance(instanceId)
if err != nil {
return nil, err
}
inst.host = self
return inst, nil
}
func (self *SHost) CreateVM(name, imgId string, sysDiskSize, cpu, memMB int, networkId, ipAddr, desc,
passwd, storageType string, diskSizes []int, publicKey string, secgroupId string, userData string) (cloudprovider.ICloudVM, error) {
if len(publicKey) == 0 {
return nil, fmt.Errorf("AWS instance create error: keypair required")
}
if len(passwd) > 0 {
log.Debugf("Ignored: AWS not support password.Use keypair instand")
}
vmId, err := self._createVM(name, imgId, sysDiskSize, cpu, memMB, networkId, ipAddr, desc, passwd, storageType, diskSizes, publicKey, secgroupId)
if err != nil {
return nil, err
}
vm, err := self.GetInstanceById(vmId)
if err != nil {
return nil, err
}
return vm, err
}
func (self *SHost) _createVM(name, imgId string, sysDiskSize, cpu, memMB int,
networkId, ipAddr, desc, passwd,
storageType string, diskSizes []int, publicKey string, secgroupId string) (string, error) {
// 网络配置及安全组绑定
net := self.zone.getNetworkById(networkId)
if net == nil {
return "", fmt.Errorf("invalid network ID %s", networkId)
}
if net.wire == nil {
log.Errorf("network's wire is empty")
return "", fmt.Errorf("network's wire is empty")
}
if net.wire.vpc == nil {
log.Errorf("wire's vpc is empty")
return "", fmt.Errorf("wire's vpc is empty")
}
if len(secgroupId) == 0 {
secgroups, err := net.wire.vpc.GetISecurityGroups()
if err != nil {
return "", fmt.Errorf("get security group error %s", err)
}
if len(secgroups) == 0 {
// aws 默认就已经创建好了一个默认安全组。正常情况下并不需要手动创建
secId, err := self.zone.region.createDefaultSecurityGroup(net.wire.vpc.VpcId)
if err != nil {
return "", fmt.Errorf("no secgroup for vpc and failed to create a default One!!")
} else {
secgroupId = secId
}
} else {
secgroupId = secgroups[0].GetId()
}
}
// 同步keypair
keypair := ""
if len(publicKey) <= 0 {
return "", fmt.Errorf("publickey should not be empty")
}
keypair, err := self.zone.region.syncKeypair(publicKey)
if err != nil {
return "", err
}
// 镜像及硬盘配置
img, err := self.zone.region.GetImage(imgId)
if err != nil {
log.Errorf("getiamge fail %s", err)
return "", err
}
if img.Status != ImageStatusAvailable {
log.Errorf("image %s status %s", imgId, img.Status)
return "", fmt.Errorf("image not ready")
}
disks := make([]SDisk, len(diskSizes)+1)
disks[0].Size = img.Size
if sysDiskSize > 0 && sysDiskSize > img.Size {
disks[0].Size = sysDiskSize
}
disks[0].Category = storageType
for i, sz := range diskSizes {
disks[i+1].Size = sz
disks[i+1].Category = storageType
}
instanceTypes, err := self.zone.region.GetMatchInstanceTypes(cpu, memMB, 0, self.zone.ZoneId)
if err != nil {
return "", err
}
if len(instanceTypes) == 0 {
return "", fmt.Errorf("instance type %dC%dMB not avaiable", cpu, memMB)
}
// 匹配实例类型
for _, instType := range instanceTypes {
instanceTypeId := instType.InstanceTypeId
log.Debugf("Try instancetype : %s", instanceTypeId)
vmId, err := self.zone.region.CreateInstance(name, imgId, instanceTypeId, networkId, secgroupId, self.zone.ZoneId, desc, disks, ipAddr, keypair)
if err != nil {
log.Errorf("Failed for %s: %s", instanceTypeId, err)
} else {
return vmId, nil
}
}
// 创建实例
return "", fmt.Errorf("Failed to create, specification not supported")
}
+287
View File
@@ -0,0 +1,287 @@
package aws
import (
"fmt"
"github.com/aws/aws-sdk-go/service/ec2"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
)
type ImageStatusType string
const (
ImageStatusCreating ImageStatusType = "pending"
ImageStatusAvailable ImageStatusType = "available"
ImageStatusCreateFailed ImageStatusType = "failed"
)
type ImageOwnerType string
const (
ImageOwnerSystem ImageOwnerType = "amazon"
ImageOwnerSelf ImageOwnerType = "self"
ImageOwnerOthers ImageOwnerType = "microsoft"
ImageOwnerMarketplace ImageOwnerType = "aws-marketplace"
)
type ImageImportTask struct {
ImageId string
RegionId string
TaskId string
}
type RootDevice struct {
SnapshotId string
Size int // GB
Category string // VolumeType
}
type SImage struct {
storageCache *SStoragecache
Architecture string
CreationTime string
Description string
ImageId string
ImageName string
OSName string
OSType string
ImageType string
IsSupportCloudinit bool
IsSupportIoOptimized bool
Platform string
Size int
Status ImageStatusType
Usage string
RootDevice RootDevice
}
func (self *SImage) GetId() string {
return self.ImageId
}
func (self *SImage) GetName() string {
return self.ImageName
}
func (self *SImage) GetGlobalId() string {
return self.ImageId
}
func (self *SImage) GetStatus() string {
switch self.Status {
case ImageStatusCreating:
return models.IMAGE_STATUS_QUEUED
case ImageStatusAvailable:
return models.IMAGE_STATUS_ACTIVE
case ImageStatusCreateFailed:
return models.IMAGE_STATUS_KILLED
default:
return models.IMAGE_STATUS_KILLED
}
}
func (self *SImage) Refresh() error {
// todo: GetImage
new, err := self.storageCache.region.GetImage(self.ImageId)
if err != nil {
return err
}
return jsonutils.Update(self, new)
}
func (self *SImage) IsEmulated() bool {
return false
}
func (self *SImage) GetMetadata() *jsonutils.JSONDict {
data := jsonutils.NewDict()
if len(self.Architecture) > 0 {
data.Add(jsonutils.NewString(self.Architecture), "os_arch")
}
if len(self.OSType) > 0 {
data.Add(jsonutils.NewString(self.OSType), "os_name")
}
if len(self.Platform) > 0 {
data.Add(jsonutils.NewString(self.Platform), "os_distribution")
}
if len(self.OSName) > 0 {
data.Add(jsonutils.NewString(self.OSName), "os_version")
}
return data
}
func (self *SImage) Delete() error {
// todo: implement me
return self.storageCache.region.DeleteImage(self.ImageId)
}
func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache {
return self.storageCache
}
func (self *SRegion) ImportImage(name string, osArch string, osType string, osDist string, diskFormat string, bucket string, key string) (*ImageImportTask, error) {
params := &ec2.ImportImageInput{}
params.SetArchitecture(osArch)
params.SetHypervisor("xen") // todo: osType?
params.SetPlatform(osType)
// https://docs.aws.amazon.com/zh_cn/vm-import/latest/userguide/vmimport-image-import.html#import-vm-image
params.SetRoleName("vmimport")
container := &ec2.ImageDiskContainer{}
container.SetDescription(fmt.Sprintf("vmimport %s", name))
container.SetFormat(diskFormat)
container.SetDeviceName("/dev/sda") // default /dev/sda
bkt := &ec2.UserBucket{S3Bucket: &bucket, S3Key: &key}
container.SetUserBucket(bkt)
params.SetDiskContainers([]*ec2.ImageDiskContainer{container})
params.SetLicenseType("BYOL") // todo: AWS?
ret, err := self.ec2Client.ImportImage(params)
if err != nil {
return nil, err
}
log.Debugf("ImportImage task: %s", ret.String())
return &ImageImportTask{ImageId: StrVal(ret.ImageId), RegionId: self.RegionId, TaskId: *ret.ImportTaskId}, nil
}
type ImageExportTask struct {
ImageId string
RegionId string
TaskId string
}
func (self *SRegion) ExportImage(instanceId string, imageId string) (*ImageExportTask, error) {
params := &ec2.CreateInstanceExportTaskInput{}
params.SetInstanceId(instanceId)
params.SetDescription(fmt.Sprintf("image %s export from aws", imageId))
params.SetTargetEnvironment("vmware")
spec := &ec2.ExportToS3TaskSpecification{}
spec.SetContainerFormat("ova")
spec.SetDiskImageFormat("RAW")
spec.SetS3Bucket("imgcache-onecloud")
params.SetExportToS3Task(spec)
ret, err := self.ec2Client.CreateInstanceExportTask(params)
if err != nil {
return nil, err
}
return &ImageExportTask{ImageId: imageId, RegionId: self.RegionId, TaskId: *ret.ExportTask.ExportTaskId}, nil
}
func (self *SRegion) GetImage(imageId string) (*SImage, error) {
images, _, err := self.GetImages("", ImageOwnerSelf, []string{imageId}, "", 0, 1)
if err != nil {
return nil, err
}
if len(images) == 0 {
return nil, fmt.Errorf("image %s not found", imageId)
}
return &images[0], nil
}
func (self *SRegion) GetImageByName(name string) (*SImage, error) {
images, _, err := self.GetImages("", ImageOwnerSelf, nil, name, 0, 1)
if err != nil {
return nil, err
}
if len(images) == 0 {
return nil, cloudprovider.ErrNotFound
}
return &images[0], nil
}
func (self *SRegion) GetImageStatus(imageId string) (ImageStatusType, error) {
image, err := self.GetImage(imageId)
if err != nil {
return "", err
}
return image.Status, nil
}
func getRootDiskSize(image *ec2.Image) (int, error) {
rootDeivce := *image.RootDeviceName
for _, volume := range image.BlockDeviceMappings {
if len(rootDeivce) > 0 && *volume.DeviceName == rootDeivce {
return int(*volume.Ebs.VolumeSize), nil
}
}
return 0, fmt.Errorf("image size not found: %s", image.String())
}
func (self *SRegion) GetImages(status ImageStatusType, owner ImageOwnerType, imageId []string, name string, offset int, limit int) ([]SImage, int, error) {
params := &ec2.DescribeImagesInput{}
filters := make([]*ec2.Filter, 0)
if len(status) > 0 {
filters = AppendSingleValueFilter(filters, "state", string(status))
}
if len(name) > 0 {
filters = AppendSingleValueFilter(filters, "name", name)
}
if len(owner) > 0 {
own := string(owner)
params.SetOwners([]*string{&own})
}
if len(imageId) > 0 {
params.SetImageIds(ConvertedList(imageId))
}
ret, err := self.ec2Client.DescribeImages(params)
if err != nil {
return nil, 0, err
}
images := []SImage{}
for _, image := range ret.Images {
if err := FillZero(image); err != nil {
return nil, 0, err
}
tagspec := TagSpec{}
tagspec.LoadingEc2Tags(image.Tags)
size, err := getRootDiskSize(image)
if err != nil {
log.Debugf(err.Error())
}
var rootDevice RootDevice
for _, block := range image.BlockDeviceMappings {
if len(*image.RootDeviceName) > 0 && *block.DeviceName == *image.RootDeviceName {
rootDevice.SnapshotId = *block.Ebs.SnapshotId
rootDevice.Category = *block.Ebs.VolumeType
rootDevice.Size = int(*block.Ebs.VolumeSize)
}
}
images = append(images, SImage{
storageCache: self.getStoragecache(),
Architecture: *image.Architecture,
Description: *image.Description,
ImageId: *image.ImageId,
ImageName: tagspec.GetNameTag(),
ImageType: *image.ImageType,
IsSupportIoOptimized: *image.EnaSupport,
Platform: *image.Platform,
Status: ImageStatusType(*image.State),
CreationTime: *image.CreationDate,
Size: size,
RootDevice: rootDevice,
// Usage: "",
// OSName: *image.Platform,
})
}
return images, len(images), nil
}
func (self *SRegion) DeleteImage(imageId string) error {
params := &ec2.DeregisterImageInput{}
params.SetImageId(imageId)
_, err := self.ec2Client.DeregisterImage(params)
return err
}
+805
View File
@@ -0,0 +1,805 @@
package aws
import (
"fmt"
"time"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/coredns/coredns/plugin/pkg/log"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/pkg/util/osprofile"
"yunion.io/x/pkg/util/secrules"
)
const (
InstanceStatusPending = "pending"
InstanceStatusRunning = "running"
InstanceStatusShutting = "shutting-down"
InstanceStatusTerminated = "terminated"
InstanceStatusStopping = "stopping"
InstanceStatusStopped = "stopped"
)
type InstanceChargeType string
type SIpAddress struct {
IpAddress []string
}
type SNetworkInterfaces struct {
NetworkInterface []SNetworkInterface
}
type SNetworkInterface struct {
MacAddress string
NetworkInterfaceId string
PrimaryIpAddress string // PrivateIpAddress
}
type SSecurityGroupIds struct {
SecurityGroupId []string
}
type SVpcAttributes struct {
PrivateIpAddress SIpAddress
NetworkId string // subnet id
VpcId string
}
type SInstance struct {
host *SHost
RegionId string
ZoneId string
InstanceId string
ImageId string
HostName string
InstanceName string
InstanceType string
Cpu int8
Memory int
IoOptimized bool
KeyPairName string
CreationTime time.Time // LaunchTime
ExpiredTime time.Time
ProductCodes []string
PublicDNSName string
InnerIpAddress SIpAddress
PublicIpAddress SIpAddress
RootDeviceName string
Status string // state
VlanId string // subnet ID ?
VpcAttributes SVpcAttributes
SecurityGroupIds SSecurityGroupIds
NetworkInterfaces SNetworkInterfaces
EipAddress SEipAddress
Disks []string
DeviceNames []string
OSName string
OSType string
Description string
// 这些貌似都没啥用
// AutoReleaseTime string
// DeviceAvailable bool
// GPUAmount int
// GPUSpec string
// InstanceChargeType InstanceChargeType
// InstanceNetworkType string
// InstanceTypeFamily string
// InternetChargeType string
// InternetMaxBandwidthIn int
// InternetMaxBandwidthOut int
// OperationLocks SOperationLocks
// Recyclable bool
// SerialNumber string
// SpotPriceLimit string
// SpotStrategy string
// StartTime time.Time
// StoppedMode string
}
func (self *SInstance) UpdateUserData(userData string) error {
return cloudprovider.ErrNotImplemented
}
func (self *SInstance) GetId() string {
return self.InstanceId
}
func (self *SInstance) GetName() string {
return self.InstanceName
}
func (self *SInstance) GetGlobalId() string {
return self.InstanceId
}
func (self *SInstance) GetStatus() string {
// todo : implement me
switch self.Status {
case InstanceStatusRunning:
return models.VM_RUNNING
case InstanceStatusPending: // todo: pending ?
return models.VM_STARTING
case InstanceStatusStopping:
return models.VM_STOPPING
case InstanceStatusStopped:
return models.VM_READY
default:
return models.VM_UNKNOWN
}
}
func (self *SInstance) Refresh() error {
new, err := self.host.zone.region.GetInstance(self.InstanceId)
if err != nil {
return err
}
return jsonutils.Update(self, new)
}
func (self *SInstance) IsEmulated() bool {
return false
}
func (self *SInstance) GetMetadata() *jsonutils.JSONDict {
data := jsonutils.NewDict()
// todo: add price_key here
tags, err := FetchTags(self.host.zone.region.ec2Client, self.InstanceId)
if err != nil {
log.Errorf(err.Error())
}
data.Update(tags)
if len(self.ImageId) > 0 {
if image, err := self.host.zone.region.GetImage(self.ImageId); err != nil {
log.Errorf("Failed to find image %s for instance %s zone %s", self.ImageId, self.GetId(), self.ZoneId)
} else if meta := image.GetMetadata(); meta != nil {
data.Update(meta)
}
}
for _, secgroupId := range self.SecurityGroupIds.SecurityGroupId {
if len(secgroupId) > 0 {
data.Add(jsonutils.NewString(secgroupId), "secgroupId")
break
}
}
return data
}
func (self *SInstance) GetBillingType() string {
// todo: implement me
return models.BILLING_TYPE_POSTPAID
}
func (self *SInstance) GetExpiredAt() time.Time {
return self.ExpiredTime
}
func (self *SInstance) GetCreateTime() time.Time {
return self.CreationTime
}
func (self *SInstance) GetIHost() cloudprovider.ICloudHost {
return self.host
}
func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
disks, _, err := self.host.zone.region.GetDisks(self.InstanceId, "", "", nil, 0, 0)
if err != nil {
log.Errorf("fetchDisks fail %s", err)
return nil, err
}
idisks := make([]cloudprovider.ICloudDisk, len(disks))
for i := 0; i < len(disks); i += 1 {
store, err := self.host.zone.getStorageByCategory(disks[i].Category)
if err != nil {
return nil, err
}
disks[i].storage = store
idisks[i] = &disks[i]
}
return idisks, nil
}
func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
nics := make([]cloudprovider.ICloudNic, 0)
for _, ip := range self.VpcAttributes.PrivateIpAddress.IpAddress {
nic := SInstanceNic{instance: self, ipAddr: ip}
nics = append(nics, &nic)
}
return nics, nil
}
func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
// todo: implement me
if len(self.PublicIpAddress.IpAddress) > 0 {
eip := SEipAddress{}
eip.region = self.host.zone.region
eip.IpAddress = self.PublicIpAddress.IpAddress[0]
eip.InstanceId = self.InstanceId
eip.AllocationId = self.InstanceId // fixed
eip.Bandwidth = 10000
return &eip, nil
} else if len(self.EipAddress.IpAddress) > 0 {
return self.host.zone.region.GetEip(self.EipAddress.AllocationId)
} else {
return nil, nil
}
}
func (self *SInstance) GetVcpuCount() int8 {
return self.Cpu
}
func (self *SInstance) GetVmemSizeMB() int {
return self.Memory
}
func (self *SInstance) GetBootOrder() string {
return "dcn"
}
func (self *SInstance) GetVga() string {
return "std"
}
func (self *SInstance) GetVdi() string {
return "vnc"
}
func (self *SInstance) GetOSType() string {
return osprofile.NormalizeOSType(self.OSType)
}
func (self *SInstance) GetOSName() string {
return self.OSName
}
func (self *SInstance) GetBios() string {
return "BIOS"
}
func (self *SInstance) GetMachine() string {
return "pc"
}
func (self *SInstance) SyncSecurityGroup(secgroupId string, name string, rules []secrules.SecurityRule) error {
if vpc, err := self.getVpc(); err != nil {
return err
} else if len(secgroupId) == 0 {
for index, secgrpId := range self.SecurityGroupIds.SecurityGroupId {
if err := vpc.revokeSecurityGroup(secgrpId, self.InstanceId, index == 0); err != nil {
return err
}
}
} else if secgrpId, err := vpc.SyncSecurityGroup(secgroupId, name, rules); err != nil {
return err
} else if err := vpc.assignSecurityGroup(secgrpId, self.InstanceId); err != nil {
return err
} else {
for _, secgroupId := range self.SecurityGroupIds.SecurityGroupId {
if secgroupId != secgrpId {
if err := vpc.revokeSecurityGroup(secgroupId, self.InstanceId, false); err != nil {
return err
}
}
}
self.SecurityGroupIds.SecurityGroupId = []string{secgrpId}
}
return nil
}
func (self *SInstance) GetHypervisor() string {
return models.HYPERVISOR_AWS
}
func (self *SInstance) StartVM() error {
timeout := 300 * time.Second
interval := 15 * time.Second
startTime := time.Now()
for time.Now().Sub(startTime) < timeout {
err := self.Refresh()
if err != nil {
return err
}
log.Debugf("status %s expect %s", self.GetStatus(), models.VM_RUNNING)
if self.GetStatus() == models.VM_RUNNING {
return nil
} else if self.GetStatus() == models.VM_READY {
err := self.host.zone.region.StartVM(self.InstanceId)
if err != nil {
return err
}
}
time.Sleep(interval)
}
return cloudprovider.ErrTimeout
}
func (self *SInstance) StopVM(isForce bool) error {
err := self.host.zone.region.StopVM(self.InstanceId, isForce)
if err != nil {
return err
}
return cloudprovider.WaitStatus(self, models.VM_READY, 10*time.Second, 300*time.Second) // 5mintues
}
func (self *SInstance) DeleteVM() error {
for {
err := self.host.zone.region.DeleteVM(self.InstanceId)
if err != nil {
return err
} else {
break
}
}
return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes
}
func (self *SInstance) UpdateVM(name string) error {
return self.host.zone.region.UpdateVM(self.InstanceId, name)
}
func (self *SInstance) RebuildRoot(imageId string, passwd string, publicKey string, sysSizeGB int) (string, error) {
if len(publicKey) > 0 || len(passwd) > 0 {
return "", fmt.Errorf("aws rebuild root not support specific publickey/password")
}
diskId, err := self.host.zone.region.ReplaceSystemDisk(self.InstanceId, imageId, sysSizeGB)
if err != nil {
return "", err
}
return diskId, nil
}
func (self *SInstance) DeployVM(name string, password string, publicKey string, deleteKeypair bool, description string) error {
return self.host.zone.region.DeployVM(self.InstanceId, name, password, publicKey, deleteKeypair, description)
}
func (self *SInstance) ChangeConfig(instanceId string, ncpu int, vmem int) error {
return self.host.zone.region.ChangeVMConfig(self.ZoneId, self.InstanceId, ncpu, vmem, nil)
}
func (self *SInstance) GetVNCInfo() (jsonutils.JSONObject, error) {
panic("implement me")
}
func (self *SInstance) AttachDisk(diskId string) error {
// todo:bugfix . self.DeviceNames => self.GetDeviceNames()
name, err := NextDeviceName(self.DeviceNames)
if err != nil {
return err
}
return self.host.zone.region.AttachDisk(self.InstanceId, diskId, name)
}
func (self *SInstance) DetachDisk(diskId string) error {
return self.host.zone.region.DetachDisk(self.InstanceId, diskId)
}
func (self *SInstance) getVpc() (*SVpc, error) {
return self.host.zone.region.getVpc(self.VpcAttributes.VpcId)
}
func (self *SRegion) GetInstances(zoneId string, ids []string, offset int, limit int) ([]SInstance, int, error) {
params := &ec2.DescribeInstancesInput{}
filters := make([]*ec2.Filter, 0)
if len(zoneId) > 0 {
filters = AppendSingleValueFilter(filters, "availability-zone", zoneId)
}
if len(ids) > 0 {
params = params.SetInstanceIds(ConvertedList(ids))
}
if len(filters) > 0 {
params = params.SetFilters(filters)
}
log.Debugf("GetInstances with params: %s", params.String())
res, err := self.ec2Client.DescribeInstances(params)
if err != nil {
log.Errorf("GetInstances fail %s", err)
return nil, 0, err
}
instances := []SInstance{}
for _, reservation := range res.Reservations {
for _, instance := range reservation.Instances {
log.Debugf("GetInstances %s", instance.String())
if err := FillZero(instance); err != nil {
return nil, 0, err
}
instanceType, err := self.GetInstanceType(*instance.InstanceType)
if err != nil {
return nil, 0, err
}
tagspec := TagSpec{}
tagspec.LoadingEc2Tags(instance.Tags)
disks := []string{}
devicenames := []string{}
for _, d := range instance.BlockDeviceMappings {
if d.Ebs != nil && d.Ebs.VolumeId != nil {
disks = append(disks, *d.Ebs.VolumeId)
devicenames = append(devicenames, *d.DeviceName)
}
}
var secgroups SSecurityGroupIds
for _, s := range instance.SecurityGroups {
if s.GroupId != nil {
secgroups.SecurityGroupId = append(secgroups.SecurityGroupId, *s.GroupId)
}
}
var networkInterfaces SNetworkInterfaces
for _, n := range instance.NetworkInterfaces {
i := SNetworkInterface{
MacAddress: *n.MacAddress,
NetworkInterfaceId: *n.NetworkInterfaceId,
PrimaryIpAddress: *n.PrivateIpAddress,
}
networkInterfaces.NetworkInterface = append(networkInterfaces.NetworkInterface, i)
}
var vpcattr SVpcAttributes
vpcattr.VpcId = *instance.VpcId
vpcattr.PrivateIpAddress = SIpAddress{[]string{*instance.PrivateIpAddress}}
vpcattr.NetworkId = *instance.SubnetId
var productCodes []string
for _, p := range instance.ProductCodes {
productCodes = append(productCodes, *p.ProductCodeId)
}
sinstance := SInstance{
RegionId: self.RegionId,
ZoneId: *instance.Placement.AvailabilityZone,
InstanceId: *instance.InstanceId,
ImageId: *instance.ImageId,
InstanceType: *instance.InstanceType,
Cpu: int8(*instance.CpuOptions.CoreCount),
Memory: instanceType.memoryMB(),
IoOptimized: *instance.EbsOptimized,
KeyPairName: *instance.KeyName,
CreationTime: *instance.LaunchTime,
PublicDNSName: *instance.PublicDnsName,
RootDeviceName: *instance.RootDeviceName,
Status: *instance.State.Name,
InnerIpAddress: SIpAddress{[]string{*instance.PrivateIpAddress}},
PublicIpAddress: SIpAddress{[]string{*instance.PublicIpAddress}},
InstanceName: tagspec.GetNameTag(),
Description: tagspec.GetDescTag(),
Disks: disks,
DeviceNames: devicenames,
SecurityGroupIds: secgroups,
NetworkInterfaces: networkInterfaces,
VpcAttributes: vpcattr,
ProductCodes: productCodes,
// OSName todo: 通过关联的image获取 OS Name
// ExpiredTime:
// EipAddress:
// VlanId:
// OSType:
}
instances = append(instances, sinstance)
}
}
return instances, len(instances), nil
}
func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) {
instances, _, err := self.GetInstances("", []string{instanceId}, 0, 1)
if err != nil {
return nil, err
}
if len(instances) == 0 {
return nil, cloudprovider.ErrNotFound
}
return &instances[0], nil
}
func (self *SRegion) GetInstanceIdByImageId(imageId string) (string, error) {
params := &ec2.DescribeInstancesInput{}
filters := []*ec2.Filter{}
filters = AppendSingleValueFilter(filters, "image-id", imageId)
params.SetFilters(filters)
ret, err := self.ec2Client.DescribeInstances(params)
if err != nil {
return "", err
}
for _, item := range ret.Reservations {
for _, instance := range item.Instances {
return *instance.InstanceId, nil
}
}
return "", fmt.Errorf("instance launch with image %s not found", imageId)
}
func (self *SRegion) CreateInstance(name string, imageId string, instanceType string, SubnetId string, securityGroupId string,
zoneId string, desc string, disks []SDisk, ipAddr string,
keypair string) (string, error) {
var count int64 = 1
// disk
blockDevices := []*ec2.BlockDeviceMapping{}
for i, disk := range disks {
if i == 0 {
var size int64
size = int64(disk.Size)
ebs := &ec2.EbsBlockDevice{
DeleteOnTermination: &disk.DeleteWithInstance,
// The st1 volume type cannot be used for boot volumes. Please use a supported boot volume type: standard,io1,gp2.
// the encrypted flag cannot be specified since device /dev/sda1 has a snapshot specified.
// Encrypted: &disk.Encrypted,
VolumeSize: &size,
VolumeType: &disk.Category,
}
// todo: 这里是镜像绑定的deviceName
divceName := fmt.Sprintf("/dev/sda1")
blockDevice := &ec2.BlockDeviceMapping{
DeviceName: &divceName,
Ebs: ebs,
}
blockDevices = append(blockDevices, blockDevice)
} else {
var size int64
size = int64(disk.Size)
ebs := &ec2.EbsBlockDevice{
DeleteOnTermination: &disk.DeleteWithInstance,
Encrypted: &disk.Encrypted,
VolumeSize: &size,
VolumeType: &disk.Category,
}
// todo: generator device name
divceName := fmt.Sprintf("/dev/sd%s", string(98+i))
blockDevice := &ec2.BlockDeviceMapping{
DeviceName: &divceName,
Ebs: ebs,
}
blockDevices = append(blockDevices, blockDevice)
}
}
// tags
tags := TagSpec{ResourceType: "instance"}
tags.SetNameTag(name)
tags.SetDescTag(desc)
ec2TagSpec, err := tags.GetTagSpecifications()
if err != nil {
return "", err
}
params := ec2.RunInstancesInput{
ImageId: &imageId,
InstanceType: &instanceType,
MaxCount: &count,
MinCount: &count,
SubnetId: &SubnetId,
PrivateIpAddress: &ipAddr,
BlockDeviceMappings: blockDevices,
KeyName: &keypair,
Placement: &ec2.Placement{AvailabilityZone: &zoneId},
SecurityGroupIds: []*string{&securityGroupId},
TagSpecifications: []*ec2.TagSpecification{ec2TagSpec},
}
res, err := self.ec2Client.RunInstances(&params)
if err != nil {
log.Errorf("CreateInstance fail %s", err)
return "", err
}
if len(res.Instances) == 1 {
return *res.Instances[0].InstanceId, nil
} else {
msg := fmt.Sprintf("CreateInstance fail: %s instance created. ", len(res.Instances))
log.Errorf(msg)
return "", fmt.Errorf(msg)
}
}
func (self *SRegion) GetInstanceStatus(instanceId string) (string, error) {
instance, err := self.GetInstance(instanceId)
if err != nil {
return "", err
}
return instance.Status, nil
}
func (self *SRegion) instanceStatusChecking(instanceId, status string) error {
remoteStatus, err := self.GetInstanceStatus(instanceId)
if err != nil {
log.Errorf("Fail to get instance status on StartVM: %s", err)
return err
}
if status != remoteStatus {
log.Errorf("StartVM: vm status is %s expect %s", remoteStatus, status)
return cloudprovider.ErrInvalidStatus
}
return nil
}
func (self *SRegion) StartVM(instanceId string) error {
if err := self.instanceStatusChecking(instanceId, InstanceStatusStopped); err != nil {
return err
}
params := &ec2.StartInstancesInput{}
params.SetInstanceIds([]*string{&instanceId})
_, err := self.ec2Client.StartInstances(params)
return err
}
func (self *SRegion) StopVM(instanceId string, isForce bool) error {
if err := self.instanceStatusChecking(instanceId, InstanceStatusRunning); err != nil {
return err
}
params := &ec2.StopInstancesInput{}
params.SetInstanceIds([]*string{&instanceId})
_, err := self.ec2Client.StopInstances(params)
return err
}
func (self *SRegion) DeleteVM(instanceId string) error {
if err := self.instanceStatusChecking(instanceId, InstanceStatusStopped); err != nil {
return err
}
params := &ec2.TerminateInstancesInput{}
params.SetInstanceIds([]*string{&instanceId})
_, err := self.ec2Client.TerminateInstances(params)
return err
}
func (self *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error {
params := &ec2.CreateTagsInput{}
params.SetResources([]*string{&instanceId})
tagspec := TagSpec{ResourceType: "instance"}
if len(keypairName) > 0 {
return fmt.Errorf("aws not support reset publickey")
}
if len(password) > 0 {
return fmt.Errorf("aws not support set password, use publickey instead")
}
if deleteKeypair {
return fmt.Errorf("aws not support delete publickey")
}
if len(name) > 0 {
tagspec.SetNameTag(name)
}
if len(description) > 0 {
tagspec.SetDescTag(description)
}
ec2Tag, _ := tagspec.GetTagSpecifications()
if len(ec2Tag.Tags) > 0 {
params.SetTags(ec2Tag.Tags)
_, err := self.ec2Client.CreateTags(params)
if err != nil {
return err
}
} else {
log.Debugf("no changes")
}
return nil
}
func (self *SRegion) UpdateVM(instanceId string, hostname string) error {
// https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/set-hostname.html
return fmt.Errorf("aws not support change hostname.")
}
func (self *SRegion) ReplaceSystemDisk(instanceId string, imageId string, sysDiskSizeGB int) (string, error) {
instance, err := self.GetInstance(instanceId)
if err != nil {
return "", err
}
disks, _, err := self.GetDisks(instanceId, instance.ZoneId, "", nil, 0, 0)
if err != nil {
return "", err
}
var rootDisk *SDisk
for _, disk := range disks {
if disk.Type == models.DISK_TYPE_SYS {
rootDisk = &disk
}
}
if rootDisk == nil {
return "", fmt.Errorf("can not find root disk of instance %s", instanceId)
}
image, err := self.GetImage(imageId)
if err != nil {
return "", err
}
diskId, err := self.CreateDisk(instance.ZoneId, rootDisk.Category, rootDisk.GetName(), sysDiskSizeGB, image.RootDevice.SnapshotId, "")
if err != nil {
return "", err
}
self.ec2Client.WaitUntilVolumeAvailable(&ec2.DescribeVolumesInput{VolumeIds: []*string{&diskId}})
// todo: 检查instance状态
err = instance.DetachDisk(rootDisk.DiskId)
if err != nil {
return "", err
}
self.ec2Client.WaitUntilInstanceStopped(&ec2.DescribeInstancesInput{InstanceIds: []*string{&instanceId}})
err = instance.AttachDisk(diskId)
if err != nil {
return "", err
}
self.ec2Client.WaitUntilInstanceStopped(&ec2.DescribeInstancesInput{InstanceIds: []*string{&instanceId}})
return diskId, nil
}
func (self *SRegion) ChangeVMConfig(zoneId string, instanceId string, ncpu int, vmem int, disks []*SDisk) error {
params := &ec2.ModifyInstanceAttributeInput{}
params.SetInstanceId(instanceId)
instanceTypes, err := self.GetMatchInstanceTypes(ncpu, vmem, 0, zoneId)
if err != nil {
return err
}
for _, instancetype := range instanceTypes {
t := &ec2.AttributeValue{Value: &instancetype.InstanceTypeId}
params.SetInstanceType(t)
_, err := self.ec2Client.ModifyInstanceAttribute(params)
if err != nil {
log.Errorf("Failed for %s: %s", instancetype.InstanceTypeId, err)
} else {
return nil
}
}
return fmt.Errorf("Failed to change vm config, specification not supported")
}
func (self *SRegion) DetachDisk(instanceId string, diskId string) error {
params := &ec2.DetachVolumeInput{}
params.SetInstanceId(instanceId)
params.SetVolumeId(diskId)
_, err := self.ec2Client.DetachVolume(params)
return err
}
func (self *SRegion) AttachDisk(instanceId string, diskId string, deviceName string) error {
params := &ec2.AttachVolumeInput{}
params.SetInstanceId(instanceId)
params.SetVolumeId(diskId)
params.SetDevice(deviceName)
_, err := self.ec2Client.AttachVolume(params)
return err
}
+40
View File
@@ -0,0 +1,40 @@
package aws
import (
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/pkg/util/netutils"
)
type SInstanceNic struct {
instance *SInstance
ipAddr string
}
func (self *SInstanceNic) GetIP() string {
return self.ipAddr
}
func (self *SInstanceNic) GetMAC() string {
ip, _ := netutils.NewIPV4Addr(self.ipAddr)
return ip.ToMac("00:16:")
}
func (self *SInstanceNic) GetDriver() string {
return "virtio"
}
func (self *SInstanceNic) GetINetwork() cloudprovider.ICloudNetwork {
networkId := self.instance.VpcAttributes.NetworkId
wires, err := self.instance.host.GetIWires()
if err != nil {
return nil
}
for i := 0; i < len(wires); i += 1 {
wire := wires[i].(*SWire)
net := wire.getNetworkById(networkId)
if net != nil {
return net
}
}
return nil
}
+105
View File
@@ -0,0 +1,105 @@
package aws
import (
"encoding/json"
"fmt"
"io/ioutil"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/compute/options"
)
type Cpu struct {
Cores int `json:"cores"`
Units string `json:"units"`
}
type CpuCredits struct {
OptimizationSupported bool `json:"optimizationSupported"`
}
type ProcessorFeatures struct {
AESNI bool `json:"AES-NI"`
AVX bool `json:"AVX"`
Turbo bool `json:"Turbo"`
}
type SInstanceType struct {
Architectures []string `json:"architectures"`
Cpu Cpu `json:"cpu"`
CpuCredits CpuCredits `json:"cpuCredits"`
Description string `json:"description"`
EbsEncryptionSupported bool `json:"ebsEncryptionSupported"`
EbsOnly bool `json:"ebsOnly"`
Family string `json:"family"`
FreeTierEligible bool `json:"freeTierEligible"`
Ipv6Support bool `json:"ipv6Support"`
Memory float32 `json:"memory"`
NetworkPerformance string `json:"networkPerformance"`
PhysicalProcessor string `json:"physicalProcessor"`
ProcessorFeatures ProcessorFeatures `json:"processorFeatures"`
ProcessorSpeed float32 `json:"processorSpeed"`
SpotSupported bool `json:"spotSupported"`
InstanceTypeId string `json:"typeName"`
VirtualizationTypes []string `json:"virtualizationTypes"`
Vpc bool `json:"vpc"`
VpcOnly bool `json:"vpcOnly"`
Windows bool `json:"windows"`
}
func (self *SInstanceType) memoryMB() int {
return int(self.Memory * 1024)
}
func (self *SRegion) GetInstanceTypes() ([]SInstanceType, error) {
if self.instanceTypes == nil {
var GlobalInstanceTyes []SInstanceType
instanceTypes, err := ioutil.ReadFile(options.Options.DefaultAwsInstanceTypeFile)
if err != nil {
return nil, err
}
err = json.Unmarshal([]byte(instanceTypes), &GlobalInstanceTyes)
if err != nil {
log.Errorf("GetInstanceTypes %s", err)
return nil, err
}
return GlobalInstanceTyes, err
} else {
return self.instanceTypes, nil
}
}
func (self *SRegion) GetInstanceType(instanceTypeId string) (*SInstanceType, error) {
ret, err := self.GetInstanceTypes()
if err != nil {
return nil, err
}
for _, item := range ret {
if item.InstanceTypeId == instanceTypeId {
return &item, nil
}
}
return nil, fmt.Errorf("instancetype %s not found", instanceTypeId)
}
func (self *SRegion) GetMatchInstanceTypes(cpu int, memMB int, gpu int, zoneId string) ([]SInstanceType, error) {
types, err := self.GetInstanceTypes()
if err != nil {
return nil, err
}
// 实例类型顺序: 微型实例 -> 通用型 -> 计算优化型 ...
// todo:部分实例类型 需要启用ena才能正常启动。需要过滤掉。
// https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/enhanced-networking-ena.html
ret := []SInstanceType{}
for _, t := range types {
// cpu & mem & disk & ena 都匹配才行
if t.Cpu.Cores == cpu && t.memoryMB() == memMB {
ret = append(ret, t)
}
}
return ret, nil
}
+91
View File
@@ -0,0 +1,91 @@
package aws
import (
"fmt"
"github.com/aokoli/goutils"
"github.com/aws/aws-sdk-go/service/ec2"
"golang.org/x/crypto/ssh"
"strconv"
"time"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SKeypair struct {
KeyPairFingerPrint string
KeyPairName string
}
func (self *SRegion) GetKeypairs(finger string, name string, offset int, limit int) ([]SKeypair, int, error) {
ret, err := self.ec2Client.DescribeKeyPairs(&ec2.DescribeKeyPairsInput{})
if err != nil {
return nil, 0, err
}
keypairs := []SKeypair{}
for _, item := range ret.KeyPairs {
if err := FillZero(item); err != nil {
return nil, 0, err
}
keypairs = append(keypairs, SKeypair{*item.KeyFingerprint, *item.KeyName})
}
return keypairs, len(keypairs), nil
}
func (self *SRegion) ImportKeypair(name string, pubKey string) (*SKeypair, error) {
params := &ec2.ImportKeyPairInput{}
params.SetKeyName(name)
params.SetPublicKeyMaterial([]byte(pubKey))
ret, err := self.ec2Client.ImportKeyPair(params)
if err != nil {
return nil, err
} else {
return &SKeypair{StrVal(ret.KeyFingerprint), StrVal(ret.KeyName)}, nil
}
}
func (self *SRegion) AttachKeypair(instanceId string, keypairName string) error {
return cloudprovider.ErrNotSupported
}
func (self *SRegion) DetachKeyPair(instanceId string, keypairName string) error {
return cloudprovider.ErrNotSupported
}
func (self *SRegion) lookUpAwsKeypair(publicKey string) (string, error) {
pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKey))
if err != nil {
return "", fmt.Errorf("publicKey error %s", err)
}
fingerprint := ssh.FingerprintLegacyMD5(pk)
ks, total, err := self.GetKeypairs(fingerprint, "*", 0, 1)
if total < 1 {
return "", fmt.Errorf("keypair not found %s", err)
} else {
return ks[0].KeyPairName, nil
}
}
func (self *SRegion) importAwsKeypair(publicKey string) (string, error) {
prefix, e := goutils.RandomAlphabetic(6)
if e != nil {
return "", fmt.Errorf("publicKey error %s", e)
}
name := prefix + strconv.FormatInt(time.Now().Unix(), 10)
if k, e := self.ImportKeypair(name, publicKey); e != nil {
return "", fmt.Errorf("keypair import error %s", e)
} else {
return k.KeyPairName, nil
}
}
func (self *SRegion) syncKeypair(publicKey string) (string, error) {
name, e := self.lookUpAwsKeypair(publicKey)
if e == nil {
return name, nil
}
return self.importAwsKeypair(publicKey)
}
+183
View File
@@ -0,0 +1,183 @@
package aws
import (
"github.com/aws/aws-sdk-go/service/ec2"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/pkg/util/netutils"
)
type SNetwork struct {
wire *SWire
AvailableIpAddressCount int
CidrBlock string
CreationTime time.Time
Description string
IsDefault bool
Status string
NetworkId string
NetworkName string
VpcId string
ZoneId string
}
func (self *SNetwork) GetId() string {
return self.NetworkId
}
func (self *SNetwork) GetName() string {
return self.NetworkName
}
func (self *SNetwork) GetGlobalId() string {
return self.NetworkId
}
func (self *SNetwork) GetStatus() string {
return strings.ToLower(self.Status)
}
func (self *SNetwork) Refresh() error {
log.Debugf("network refresh %s", self.NetworkId)
new, err := self.wire.zone.region.getNetwork(self.NetworkId)
if err != nil {
return err
}
return jsonutils.Update(self, new)
}
func (self *SNetwork) IsEmulated() bool {
return false
}
func (self *SNetwork) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (self *SNetwork) GetIWire() cloudprovider.ICloudWire {
return self.wire
}
func (self *SNetwork) GetIpStart() string {
pref, _ := netutils.NewIPV4Prefix(self.CidrBlock)
startIp := pref.Address.NetAddr(pref.MaskLen) // 0
startIp = startIp.StepUp() // 1
return startIp.String()
}
func (self *SNetwork) GetIpEnd() string {
pref, _ := netutils.NewIPV4Prefix(self.CidrBlock)
endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255
endIp = endIp.StepDown() // 254
endIp = endIp.StepDown() // 253
endIp = endIp.StepDown() // 252
return endIp.String()
}
func (self *SNetwork) GetIpMask() int8 {
pref, _ := netutils.NewIPV4Prefix(self.CidrBlock)
return pref.MaskLen
}
func (self *SNetwork) GetGateway() string {
pref, _ := netutils.NewIPV4Prefix(self.CidrBlock)
endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255
endIp = endIp.StepDown() // 254
return endIp.String()
}
func (self *SNetwork) GetServerType() string {
return models.SERVER_TYPE_GUEST
}
func (self *SNetwork) GetIsPublic() bool {
return true
}
func (self *SNetwork) Delete() error {
return self.wire.zone.region.deleteNetwork(self.NetworkId)
}
func (self *SNetwork) GetAllocTimeoutSeconds() int {
return 120 // 2 minutes
}
func (self *SRegion) createNetwork(zoneId string, vpcId string, name string, cidr string, desc string) (string, error) {
params := &ec2.CreateSubnetInput{}
params.SetAvailabilityZone(zoneId)
params.SetVpcId(vpcId)
params.SetCidrBlock(cidr)
ret, err := self.ec2Client.CreateSubnet(params)
if err != nil {
return "", err
} else {
return *ret.Subnet.SubnetId, nil
}
}
func (self *SRegion) getNetwork(networkId string) (*SNetwork, error) {
networks, total, err := self.GetNetwroks([]string{networkId}, "", 0, 0)
if err != nil {
return nil, err
}
if total != 1 {
return nil, cloudprovider.ErrNotFound
}
return &networks[0], nil
}
func (self *SRegion) deleteNetwork(networkId string) error {
params := &ec2.DeleteSubnetInput{}
params.SetSubnetId(networkId)
_, err := self.ec2Client.DeleteSubnet(params)
return err
}
func (self *SRegion) GetNetwroks(ids []string, vpcId string, limit int, offset int) ([]SNetwork, int, error) {
params := &ec2.DescribeSubnetsInput{}
if len(ids) > 0 {
_ids := make([]*string, len(ids))
for _, id := range ids {
_ids = append(_ids, &id)
}
params.SetSubnetIds(_ids)
}
if len(vpcId) > 0 {
filters := make([]*ec2.Filter, 1)
vpcFilter := &ec2.Filter{}
vpcFilter.SetName("vpc-id")
vpcFilter.SetValues([]*string{&vpcId})
filters = append(filters, vpcFilter)
params.SetFilters(filters)
}
ret, err := self.ec2Client.DescribeSubnets(params)
if err != nil {
return nil, 0, err
}
subnets := []SNetwork{}
for _, item := range ret.Subnets {
if err := FillZero(item); err != nil {
return nil, 0, err
}
subnet := SNetwork{}
subnet.CidrBlock = *item.CidrBlock
subnet.VpcId = *item.VpcId
subnet.Status = *item.State
subnet.ZoneId = *item.AvailabilityZone
subnet.IsDefault = *item.DefaultForAz
subnet.NetworkId = *item.SubnetId
subnet.NetworkName = *item.SubnetId
subnets = append(subnets, subnet)
}
return subnets, len(subnets), nil
}
+87
View File
@@ -0,0 +1,87 @@
package provider
import (
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/util/aws"
)
type SAwsProviderFactory struct {
}
func (self *SAwsProviderFactory) GetId() string {
return aws.CLOUD_PROVIDER_AWS
}
func (self *SAwsProviderFactory) GetProvider(providerId, providerName, url, account, secret string) (cloudprovider.ICloudProvider, error) {
client, err := aws.NewAwsClient(providerId, providerName, url, account, secret)
if err != nil {
return nil, err
}
return &SAwsProvider{client: client}, nil
}
func init() {
factory := SAwsProviderFactory{}
cloudprovider.RegisterFactory(&factory)
}
type SAwsProvider struct {
client *aws.SAwsClient
}
func (self *SAwsProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) {
return self.client.GetSubAccounts()
}
func (self *SAwsProvider) GetId() string {
return aws.CLOUD_PROVIDER_AWS
}
func (self *SAwsProvider) GetName() string {
return aws.CLOUD_PROVIDER_AWS_CN
}
func (self *SAwsProvider) GetIRegions() []cloudprovider.ICloudRegion {
return self.client.GetIRegions()
}
func (self *SAwsProvider) GetSysInfo() (jsonutils.JSONObject, error) {
regions := self.client.GetIRegions()
info := jsonutils.NewDict()
info.Add(jsonutils.NewInt(int64(len(regions))), "region_count")
info.Add(jsonutils.NewString(aws.AWS_API_VERSION), "api_version")
return info, nil
}
func (self *SAwsProvider) IsPublicCloud() bool {
return true
}
func (self *SAwsProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) {
return self.client.GetIRegionById(id)
}
func (self *SAwsProvider) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
return self.client.GetIHostById(id)
}
func (self *SAwsProvider) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
return self.client.GetIVpcById(id)
}
func (self *SAwsProvider) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
return self.client.GetIStorageById(id)
}
func (self *SAwsProvider) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) {
return self.client.GetIStoragecacheById(id)
}
func (self *SAwsProvider) GetBalance() (float64, error) {
balance, err := self.client.QueryAccountBalance()
if err != nil {
return 0.0, err
}
return balance.AvailableAmount, nil
}
+371
View File
@@ -0,0 +1,371 @@
package aws
import (
"fmt"
sdk "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/aws/aws-sdk-go/service/s3"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
)
type SRegion struct {
client *SAwsClient
ec2Client *ec2.EC2
iamClient *iam.IAM
s3Client *s3.S3
izones []cloudprovider.ICloudZone
ivpcs []cloudprovider.ICloudVpc
storageCache *SStoragecache
instanceTypes []SInstanceType
RegionEndpoint string
RegionId string // 这里为保持一致沿用阿里云RegionId的叫法, 与AWS RegionName字段对应
}
/////////////////////////////////////////////////////////////////////////////
/* 请不要使用这个client(AWS_DEFAULT_REGION)跨region查信息.有可能导致查询返回的信息为空。比如DescribeAvailabilityZones*/
func (self *SRegion) GetClient() *SAwsClient {
return self.client
}
func (self *SRegion) getEc2Client() (*ec2.EC2, error) {
if self.ec2Client == nil {
s, err := session.NewSession(&sdk.Config{
Region: sdk.String(self.RegionId),
Credentials: credentials.NewStaticCredentials(self.client.accessKey, self.client.secret, ""),
})
if err != nil {
return nil, err
}
self.ec2Client = ec2.New(s)
return self.ec2Client, nil
}
return self.ec2Client, nil
}
func (self *SRegion) getIamClient() (*iam.IAM, error) {
if self.iamClient == nil {
s, err := session.NewSession(&sdk.Config{
Region: sdk.String(self.RegionId),
Credentials: credentials.NewStaticCredentials(self.client.accessKey, self.client.secret, ""),
})
if err != nil {
return nil, err
}
self.iamClient = iam.New(s)
}
return self.iamClient, nil
}
func (self *SRegion) getS3Client() (*s3.S3, error) {
if self.s3Client == nil {
s, err := session.NewSession(&sdk.Config{
Region: sdk.String(self.RegionId),
Credentials: credentials.NewStaticCredentials(self.client.accessKey, self.client.secret, ""),
})
if err != nil {
return nil, err
}
self.s3Client = s3.New(s)
}
return self.s3Client, nil
}
/////////////////////////////////////////////////////////////////////////////
func (self *SRegion) fetchZones() error {
// todo: 这里将过滤出指定region下全部的zones。是否只过滤出可用的zone即可? The state of the Availability Zone (available | information | impaired | unavailable)
zones, err := self.ec2Client.DescribeAvailabilityZones(&ec2.DescribeAvailabilityZonesInput{})
if err != nil {
return err
}
err = FillZero(zones)
if err != nil {
return err
}
self.izones = make([]cloudprovider.ICloudZone, 0)
for _, zone := range zones.AvailabilityZones {
self.izones = append(self.izones, &SZone{ZoneId: *zone.ZoneName, State: *zone.State, LocalName: *zone.ZoneName, region: self})
}
return nil
}
func (self *SRegion) fetchIVpcs() error {
vpcs, err := self.ec2Client.DescribeVpcs(&ec2.DescribeVpcsInput{})
if err != nil {
return err
}
self.ivpcs = make([]cloudprovider.ICloudVpc, 0)
for _, vpc := range vpcs.Vpcs {
tags := make(map[string]string, 0)
for _, tag := range vpc.Tags {
tags[*tag.Key] = *tag.Value
}
self.ivpcs = append(self.ivpcs, &SVpc{region: self,
CidrBlock: *vpc.CidrBlock,
Tags: tags,
IsDefault: *vpc.IsDefault,
RegionId: self.RegionId,
Status: *vpc.State,
VpcId: *vpc.VpcId,
})
}
return nil
}
func (self *SRegion) fetchInfrastructure() error {
if _, err := self.getEc2Client(); err != nil {
return err
}
if err := self.fetchZones(); err != nil {
return err
}
if err := self.fetchIVpcs(); err != nil {
return err
}
for i := 0; i < len(self.ivpcs); i += 1 {
for j := 0; j < len(self.izones); j += 1 {
zone := self.izones[j].(*SZone)
vpc := self.ivpcs[i].(*SVpc)
wire := SWire{zone: zone, vpc: vpc}
zone.addWire(&wire)
vpc.addWire(&wire)
}
}
return nil
}
func (self *SRegion) GetId() string {
return self.RegionId
}
func (self *SRegion) GetName() string {
return fmt.Sprintf("%s %s", CLOUD_PROVIDER_AWS_CN, self.RegionId)
}
func (self *SRegion) GetGlobalId() string {
return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_AWS, self.RegionId)
}
func (self *SRegion) GetStatus() string {
return models.CLOUD_REGION_STATUS_INSERVER
}
func (self *SRegion) Refresh() error {
return nil
}
func (self *SRegion) IsEmulated() bool {
return false
}
func (self *SRegion) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (self *SRegion) GetLatitude() float32 {
return 0.0
}
func (self *SRegion) GetLongitude() float32 {
return 0.0
}
func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) {
if self.izones == nil {
if err := self.fetchInfrastructure(); err != nil {
return nil, err
}
}
return self.izones, nil
}
func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) {
if self.ivpcs == nil {
err := self.fetchInfrastructure()
if err != nil {
return nil, err
}
}
return self.ivpcs, nil
}
func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) {
_, err := self.getEc2Client()
if err != nil {
return nil, err
}
eips, total, err := self.GetEips("", 0, 0)
if err != nil {
return nil, err
}
ret := make([]cloudprovider.ICloudEIP, total)
for i := 0; i < len(eips); i += 1 {
ret[i] = &eips[i]
}
return ret, nil
}
func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) {
snapshots, _, err := self.GetSnapshots("", "", "", []string{}, 0, 0)
if err != nil {
return nil, err
}
ret := make([]cloudprovider.ICloudSnapshot, len(snapshots))
for i := 0; i < len(snapshots); i += 1 {
ret[i] = &snapshots[i]
}
return ret, nil
}
func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) {
izones, err := self.GetIZones()
if err != nil {
return nil, err
}
for _, zone := range izones {
if zone.GetGlobalId() == id {
return zone, nil
}
}
return nil, cloudprovider.ErrNotFound
}
func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) {
ivpcs, err := self.GetIVpcs()
if err != nil {
return nil, err
}
for _, vpc := range ivpcs {
if vpc.GetGlobalId() == id {
return vpc, nil
}
}
return nil, cloudprovider.ErrNotFound
}
func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
izones, err := self.GetIZones()
if err != nil {
return nil, err
}
for i := 0; i < len(izones); i += 1 {
ihost, err := izones[i].GetIHostById(id)
if err == nil {
return ihost, nil
} else if err != cloudprovider.ErrNotFound {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
}
func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
izones, err := self.GetIZones()
if err != nil {
return nil, err
}
for i := 0; i < len(izones); i += 1 {
istore, err := izones[i].GetIStorageById(id)
if err == nil {
return istore, nil
} else if err != cloudprovider.ErrNotFound {
return nil, err
}
}
return nil, cloudprovider.ErrNotFound
}
func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) {
if self.storageCache == nil {
self.storageCache = &SStoragecache{region: self}
}
if self.storageCache.GetGlobalId() == id {
return self.storageCache, nil
}
return nil, cloudprovider.ErrNotFound
}
func (self *SRegion) CreateIVpc(name string, desc string, cidr string) (cloudprovider.ICloudVpc, error) {
vpc, err := self.ec2Client.CreateVpc(&ec2.CreateVpcInput{CidrBlock: &cidr})
if err != nil {
return nil, err
}
err = self.fetchInfrastructure()
if err != nil {
return nil, err
}
return self.GetIVpcById(*vpc.Vpc.VpcId)
}
func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) {
eips, total, err := self.GetEips(eipId, 0, 0)
if err != nil {
return nil, err
}
if total == 0 {
return nil, cloudprovider.ErrNotFound
}
if total > 1 {
return nil, cloudprovider.ErrDuplicateId
}
return &eips[0], nil
}
func (self *SRegion) GetProvider() string {
return CLOUD_PROVIDER_AWS
}
func (self *SRegion) CreateInstanceSimple(name string, imgId string, cpu int, memGB int, storageType string, dataDiskSizesGB []int, networkId string, publicKey string) (*SInstance, error) {
izones, err := self.GetIZones()
if err != nil {
return nil, err
}
for i := 0; i < len(izones); i += 1 {
z := izones[i].(*SZone)
log.Debugf("Search in zone %s", z.LocalName)
net := z.getNetworkById(networkId)
if net != nil {
inst, err := z.getHost().CreateVM(name, imgId, 0, cpu, memGB*1024, networkId, "", "", "", storageType, dataDiskSizesGB, publicKey, "", "")
if err != nil {
return nil, err
}
return inst.(*SInstance), nil
}
}
return nil, fmt.Errorf("cannot find vswitch %s", networkId)
}
+444
View File
@@ -0,0 +1,444 @@
package aws
import (
"fmt"
"github.com/aws/aws-sdk-go/service/ec2"
"sort"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/pkg/util/secrules"
)
type Tags struct {
Tag []Tag
}
type Tag struct {
TagKey string
TagValue string
}
type SSecurityGroup struct {
vpc *SVpc
RegionId string
VpcId string
SecurityGroupId string
Description string
SecurityGroupName string
Permissions []secrules.SecurityRule
Tags Tags
// CreationTime time.Time
// InnerAccessPolicy string
}
func (self *SSecurityGroup) GetId() string {
return self.SecurityGroupId
}
func (self *SSecurityGroup) GetName() string {
if len(self.SecurityGroupName) > 0 {
return self.SecurityGroupName
}
return self.SecurityGroupId
}
func (self *SSecurityGroup) GetGlobalId() string {
return self.SecurityGroupId
}
func (self *SSecurityGroup) GetStatus() string {
return ""
}
func (self *SSecurityGroup) Refresh() error {
if new, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId); err != nil {
return err
} else {
return jsonutils.Update(self, new)
}
}
func (self *SSecurityGroup) IsEmulated() bool {
return false
}
func (self *SSecurityGroup) GetMetadata() *jsonutils.JSONDict {
if len(self.Tags.Tag) == 0 {
return nil
}
data := jsonutils.NewDict()
for _, value := range self.Tags.Tag {
data.Add(jsonutils.NewString(value.TagValue), value.TagKey)
}
return data
}
func (self *SSecurityGroup) GetDescription() string {
return self.Description
}
func (self *SSecurityGroup) GetRules() ([]secrules.SecurityRule, error) {
rules := make([]secrules.SecurityRule, 0)
if secgrp, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId); err != nil {
return rules, err
} else {
rules = secgrp.Permissions
}
return rules, nil
}
func (self *SRegion) addSecurityGroupRules(secGrpId string, rule *secrules.SecurityRule) error {
if len(rule.Ports) != 0 {
for _, port := range rule.Ports {
rule.PortStart, rule.PortEnd = port, port
if err := self.addSecurityGroupRule(secGrpId, rule); err != nil {
return err
}
}
} else {
return self.addSecurityGroupRule(secGrpId, rule)
}
return nil
}
func (self *SRegion) addSecurityGroupRule(secGrpId string, rule *secrules.SecurityRule) error {
ipPermissions, err := YunionSecRuleToAws(*rule)
log.Debugf("Aws security group rule: %s", ipPermissions)
if err != nil {
return err
}
if rule.Direction == secrules.SecurityRuleIngress {
params := &ec2.AuthorizeSecurityGroupIngressInput{}
params.SetGroupId(secGrpId)
params.SetIpPermissions(ipPermissions)
_, err := self.ec2Client.AuthorizeSecurityGroupIngress(params)
if err != nil {
return err
}
}
if rule.Direction == secrules.SecurityRuleEgress {
params := &ec2.AuthorizeSecurityGroupEgressInput{}
params.SetGroupId(secGrpId)
params.SetIpPermissions(ipPermissions)
_, err := self.ec2Client.AuthorizeSecurityGroupEgress(params)
if err != nil {
return err
}
}
return nil
}
func (self *SRegion) delSecurityGroupRule(secGrpId string, rule *secrules.SecurityRule) error {
ipPermissions, err := YunionSecRuleToAws(*rule)
if err != nil {
return err
}
if rule.Direction == secrules.SecurityRuleIngress {
params := &ec2.RevokeSecurityGroupIngressInput{}
params.SetGroupId(secGrpId)
params.SetIpPermissions(ipPermissions)
_, err := self.ec2Client.RevokeSecurityGroupIngress(params)
if err != nil {
return err
}
}
if rule.Direction == secrules.SecurityRuleEgress {
params := &ec2.RevokeSecurityGroupEgressInput{}
params.SetGroupId(secGrpId)
params.SetIpPermissions(ipPermissions)
_, err := self.ec2Client.RevokeSecurityGroupEgress(params)
if err != nil {
return err
}
}
return nil
}
func (self *SRegion) updateSecurityGroupRuleDescription(secGrpId string, rule *secrules.SecurityRule) error {
ipPermissions, err := YunionSecRuleToAws(*rule)
if err != nil {
return err
}
if rule.Direction == secrules.SecurityRuleIngress {
params := &ec2.UpdateSecurityGroupRuleDescriptionsIngressInput{}
params.SetGroupId(secGrpId)
params.SetIpPermissions(ipPermissions)
ret, err := self.ec2Client.UpdateSecurityGroupRuleDescriptionsIngress(params)
if err != nil {
return err
} else if ret.Return != nil && *ret.Return == false {
log.Debugf("update security group %s rule description failed: %s", secGrpId, ipPermissions)
}
}
if rule.Direction == secrules.SecurityRuleEgress {
params := &ec2.UpdateSecurityGroupRuleDescriptionsEgressInput{}
params.SetGroupId(secGrpId)
params.SetIpPermissions(ipPermissions)
ret, err := self.ec2Client.UpdateSecurityGroupRuleDescriptionsEgress(params)
if err != nil {
return err
} else if ret.Return != nil && *ret.Return == false {
log.Debugf("update security group %s rule description failed: %s", secGrpId, ipPermissions)
}
}
return nil
}
func (self *SRegion) createSecurityGroup(vpcId string, name string, secgroupIdTag string, desc string) (string, error) {
params := &ec2.CreateSecurityGroupInput{}
params.SetVpcId(vpcId)
params.SetDescription(desc)
params.SetGroupName(name)
group, err := self.ec2Client.CreateSecurityGroup(params)
if err != nil {
return "", err
}
tagspec := TagSpec{ResourceType: "security-group"}
tagspec.SetTag("id", secgroupIdTag)
tags, _ := tagspec.GetTagSpecifications()
tagParams := &ec2.CreateTagsInput{}
tagParams.SetResources([]*string{group.GroupId})
tagParams.SetTags(tags.Tags)
_, err = self.ec2Client.CreateTags(tagParams)
if err != nil {
return "", err
}
return *group.GroupId, nil
}
func (self *SRegion) createDefaultSecurityGroup(vpcId string) (string, error) {
secId, err := self.createSecurityGroup(vpcId, "vpc default", fmt.Sprintf("%s-default", vpcId), "vpc default group")
if err != nil {
return "", err
}
rule := &secrules.SecurityRule{
Priority: 1,
Action: secrules.SecurityRuleAllow,
Protocol: "",
Direction: secrules.SecurityRuleIngress,
PortStart: -1,
PortEnd: -1,
}
err = self.addSecurityGroupRule(secId, rule)
if err != nil {
return "", err
}
return secId, nil
}
func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup, error) {
params := &ec2.DescribeSecurityGroupsInput{}
params.SetGroupIds([]*string{&secGroupId})
ret, err := self.ec2Client.DescribeSecurityGroups(params)
if err != nil {
return nil, err
}
if len(ret.SecurityGroups) == 1 {
s := ret.SecurityGroups[0]
vpc, err := self.getVpc(*s.VpcId)
if err != nil {
fmt.Errorf("vpc %s not found", *s.VpcId)
}
permissions := self.getSecRules(s.IpPermissions, s.IpPermissionsEgress)
return &SSecurityGroup{
vpc: vpc,
Description: *s.Description,
SecurityGroupId: *s.GroupId,
SecurityGroupName: *s.GroupName,
VpcId: *s.VpcId,
Permissions: permissions,
RegionId: self.RegionId,
}, nil
} else {
return nil, fmt.Errorf("required one security group. but found: %d", len(ret.SecurityGroups))
}
}
func (self *SRegion) getSecurityGroupByTag(vpcId, secgroupId string) (*SSecurityGroup, error) {
secgroups, total, err := self.GetSecurityGroups(vpcId, secgroupId, 0, 0)
if err != nil {
return nil, err
}
if total != 1 {
log.Debugf("failed to find SecurityGroup %s: %d found", secgroupId, total)
return nil, httperrors.NewNotFoundError("failed to find SecurityGroup %s", secgroupId)
}
return &secgroups[0], nil
}
func (self *SRegion) addTagToSecurityGroup(secgroupId, key, value string, index int) error {
return nil
}
func (self *SRegion) modifySecurityGroup(secGrpId string, name string, desc string) error {
tagspec := TagSpec{ResourceType: "security-group"}
tagspec.SetNameTag(name)
tagspec.SetDescTag(desc)
ec2Tags, _ := tagspec.GetTagSpecifications()
params := &ec2.CreateTagsInput{}
params.SetTags(ec2Tags.Tags)
params.SetResources([]*string{&secGrpId})
_, err := self.ec2Client.CreateTags(params)
if err != nil {
return err
}
return nil
}
func (self *SRegion) syncSecgroupRules(secgroupId string, rules []secrules.SecurityRule) error {
if secgroup, err := self.GetSecurityGroupDetails(secgroupId); err != nil {
return err
} else {
sort.Sort(secrules.SecurityRuleSet(rules))
sort.Sort(secrules.SecurityRuleSet(secgroup.Permissions))
i, j := 0, 0
for i < len(rules) || j < len(secgroup.Permissions) {
if i < len(rules) && j < len(secgroup.Permissions) {
permissionStr := secgroup.Permissions[j].String()
ruleStr := rules[i].String()
cmp := strings.Compare(permissionStr, ruleStr)
if cmp == 0 {
if secgroup.Permissions[j].Description != rules[i].Description {
if err := self.updateSecurityGroupRuleDescription(secgroupId, &rules[i]); err != nil {
log.Errorf("updateSecurityGroupRuleDescription error %v", rules[i])
return err
}
}
i += 1
j += 1
} else if cmp > 0 {
if err := self.delSecurityGroupRule(secgroupId, &secgroup.Permissions[j]); err != nil {
log.Errorf("delSecurityGroupRule error %v", secgroup.Permissions[j])
return err
}
j += 1
} else {
if err := self.addSecurityGroupRules(secgroupId, &rules[i]); err != nil {
log.Errorf("addSecurityGroupRule error %v", rules[i])
return err
}
i += 1
}
} else if i >= len(rules) {
if err := self.delSecurityGroupRule(secgroupId, &secgroup.Permissions[j]); err != nil {
log.Errorf("delSecurityGroupRule error %v", secgroup.Permissions[j])
return err
}
j += 1
} else if j >= len(secgroup.Permissions) {
if err := self.addSecurityGroupRules(secgroupId, &rules[i]); err != nil {
log.Errorf("addSecurityGroupRule error %v", rules[i])
return err
}
i += 1
}
}
}
return nil
}
func (self *SRegion) getSecRules(ingress []*ec2.IpPermission, egress []*ec2.IpPermission) []secrules.SecurityRule {
rules := []secrules.SecurityRule{}
for _, p := range ingress {
ret, err := AwsIpPermissionToYunion(secrules.SecurityRuleIngress, *p)
if err != nil {
log.Debugf(err.Error())
}
for _, rule := range ret {
rules = append(rules, rule)
}
}
for _, p := range egress {
ret, err := AwsIpPermissionToYunion(secrules.SecurityRuleEgress, *p)
if err != nil {
log.Debugf(err.Error())
}
for _, rule := range ret {
rules = append(rules, rule)
}
}
return rules
}
func (self *SRegion) GetSecurityGroups(vpcId string, secgroupIdTag string, offset int, limit int) ([]SSecurityGroup, int, error) {
params := &ec2.DescribeSecurityGroupsInput{}
filters := make([]*ec2.Filter, 0)
if len(vpcId) > 0 {
filters = AppendSingleValueFilter(filters, "vpc-id", vpcId)
}
if len(secgroupIdTag) > 0 {
filters = AppendSingleValueFilter(filters, "tag:id", secgroupIdTag)
}
if len(filters) > 0 {
params.SetFilters(filters)
}
ret, err := self.ec2Client.DescribeSecurityGroups(params)
if err != nil {
return nil, 0, err
}
securityGroups := []SSecurityGroup{}
for _, item := range ret.SecurityGroups {
if err := FillZero(item); err != nil {
return nil, 0, err
}
if len(*item.VpcId) == 0 {
log.Debugf("ingored: security group with no vpc binded")
continue
}
vpc, err := self.getVpc(*item.VpcId)
if err != nil {
log.Errorf("vpc %s not found", *item.VpcId)
continue
}
permissions := self.getSecRules(item.IpPermissions, item.IpPermissionsEgress)
group := SSecurityGroup{
vpc: vpc,
Description: *item.Description,
SecurityGroupId: *item.GroupId,
SecurityGroupName: *item.GroupName,
VpcId: *item.VpcId,
Permissions: permissions,
RegionId: self.RegionId,
// Tags: *item.Tags,
}
securityGroups = append(securityGroups, group)
}
return securityGroups, len(securityGroups), nil
}
+35
View File
@@ -0,0 +1,35 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/aws"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type DiskListOptions struct {
Instance string `help:"Instance ID"`
Zone string `help:"Zone ID"`
Category string `help:"Disk category"`
Offset int `help:"List offset"`
Limit int `help:"List limit"`
}
shellutils.R(&DiskListOptions{}, "disk-list", "List disks", func(cli *aws.SRegion, args *DiskListOptions) error {
disks, total, e := cli.GetDisks(args.Instance, args.Zone, args.Category, nil, args.Offset, args.Limit)
if e != nil {
return e
}
printList(disks, total, args.Offset, args.Limit, []string{})
return nil
})
type DiskDeleteOptions struct {
Instance string `help:"Instance ID"`
}
shellutils.R(&DiskDeleteOptions{}, "disk-delete", "List disks", func(cli *aws.SRegion, args *DiskDeleteOptions) error {
e := cli.DeleteDisk(args.Instance)
if e != nil {
return e
}
return nil
})
}
+1
View File
@@ -0,0 +1 @@
package shell // import "yunion.io/x/onecloud/pkg/util/aws/shell"
+53
View File
@@ -0,0 +1,53 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/aws"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type EipListOptions struct {
Offset int `help:"List offset"`
Limit int `help:"List limit"`
}
shellutils.R(&EipListOptions{}, "eip-list", "List eips", func(cli *aws.SRegion, args *EipListOptions) error {
eips, total, e := cli.GetEips("", args.Offset, args.Limit)
if e != nil {
return e
}
printList(eips, total, args.Offset, args.Limit, []string{})
return nil
})
type EipAllocateOptions struct {
}
shellutils.R(&EipAllocateOptions{}, "eip-create", "Allocate an EIP", func(cli *aws.SRegion, args *EipAllocateOptions) error {
eip, err := cli.AllocateEIP("vpc")
if err != nil {
return err
}
printObject(eip)
return nil
})
type EipReleaseOptions struct {
ID string `help:"EIP allocation ID"`
}
shellutils.R(&EipReleaseOptions{}, "eip-delete", "Release an EIP", func(cli *aws.SRegion, args *EipReleaseOptions) error {
err := cli.DeallocateEIP(args.ID)
return err
})
type EipAssociateOptions struct {
ID string `help:"EIP allocation ID"`
INSTANCE string `help:"Instance ID"`
}
shellutils.R(&EipAssociateOptions{}, "eip-associate", "Associate an EIP", func(cli *aws.SRegion, args *EipAssociateOptions) error {
err := cli.AssociateEip(args.ID, args.INSTANCE)
return err
})
shellutils.R(&EipAssociateOptions{}, "eip-dissociate", "Dissociate an EIP", func(cli *aws.SRegion, args *EipAssociateOptions) error {
err := cli.DissociateEip(args.ID, args.INSTANCE)
return err
})
}
+32
View File
@@ -0,0 +1,32 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/aws"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type ImageListOptions struct {
Status string `help:"image status type" choices:"Creating|Available|UnAvailable|CreateFailed"`
Owner string `help:"Owner type" choices:"amazon|self|microsoft|aws-marketplace"`
Id []string `help:"Image ID"`
Name string `help:"image name"`
Limit int `help:"page size"`
Offset int `help:"page offset"`
}
shellutils.R(&ImageListOptions{}, "image-list", "List images", func(cli *aws.SRegion, args *ImageListOptions) error {
images, total, e := cli.GetImages(aws.ImageStatusType(args.Status), aws.ImageOwnerType(args.Owner), args.Id, args.Name, args.Offset, args.Limit)
if e != nil {
return e
}
printList(images, total, args.Offset, args.Limit, []string{})
return nil
})
type ImageDeleteOptions struct {
ID string `help:"ID or Name to delete"`
}
shellutils.R(&ImageDeleteOptions{}, "image-delete", "Delete image", func(cli *aws.SRegion, args *ImageDeleteOptions) error {
return cli.DeleteImage(args.ID)
})
}
+165
View File
@@ -0,0 +1,165 @@
package shell
import (
"fmt"
"io/ioutil"
"yunion.io/x/onecloud/pkg/util/aws"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type InstanceListOptions struct {
Id []string `help:"IDs of instances to show"`
Zone string `help:"Zone ID"`
Limit int `help:"page size"`
Offset int `help:"page offset"`
}
shellutils.R(&InstanceListOptions{}, "instance-list", "List intances", func(cli *aws.SRegion, args *InstanceListOptions) error {
instances, total, e := cli.GetInstances(args.Zone, args.Id, args.Offset, args.Limit)
if e != nil {
return e
}
printList(instances, total, args.Offset, args.Limit, []string{})
return nil
})
type InstanceCrateOptions struct {
NAME string `help:"name of instance"`
IMAGE string `help:"image ID"`
CPU int `help:"CPU count"`
MEMORYGB int `help:"MemoryGB"`
Disk []int `help:"Data disk sizes int GB"`
STORAGE string `help:"Storage type" choices:"gp2|io1|st1|sc1|standard"`
NETWORK string `help:"Network ID"`
PUBLICKEY string `help:"PublicKey file path"`
}
shellutils.R(&InstanceCrateOptions{}, "instance-create", "Create a instance", func(cli *aws.SRegion, args *InstanceCrateOptions) error {
content, err := ioutil.ReadFile(args.PUBLICKEY)
if err != nil {
return err
}
instance, e := cli.CreateInstanceSimple(args.NAME, args.IMAGE, args.CPU, args.MEMORYGB, args.STORAGE, args.Disk, args.NETWORK, string(content))
if e != nil {
return e
}
printObject(instance)
return nil
})
type InstanceDiskOperationOptions struct {
ID string `help:"instance ID"`
DISK string `help:"disk ID"`
}
type InstanceDiskAttachOptions struct {
ID string `help:"instance ID"`
DISK string `help:"disk ID"`
DEVICE string `help:"disk device name. eg. /dev/sdb"`
}
shellutils.R(&InstanceDiskAttachOptions{}, "instance-attach-disk", "Attach a disk to instance", func(cli *aws.SRegion, args *InstanceDiskAttachOptions) error {
err := cli.AttachDisk(args.ID, args.DISK, args.DEVICE)
if err != nil {
return err
}
return nil
})
shellutils.R(&InstanceDiskOperationOptions{}, "instance-detach-disk", "Detach a disk to instance", func(cli *aws.SRegion, args *InstanceDiskOperationOptions) error {
err := cli.DetachDisk(args.ID, args.DISK)
if err != nil {
return err
}
return nil
})
type InstanceOperationOptions struct {
ID string `help:"instance ID"`
}
shellutils.R(&InstanceOperationOptions{}, "instance-start", "Start a instance", func(cli *aws.SRegion, args *InstanceOperationOptions) error {
err := cli.StartVM(args.ID)
if err != nil {
return err
}
return nil
})
type InstanceStopOptions struct {
ID string `help:"instance ID"`
Force bool `help:"Force stop instance"`
}
shellutils.R(&InstanceStopOptions{}, "instance-stop", "Stop a instance", func(cli *aws.SRegion, args *InstanceStopOptions) error {
err := cli.StopVM(args.ID, args.Force)
if err != nil {
return err
}
return nil
})
shellutils.R(&InstanceOperationOptions{}, "instance-delete", "Delete a instance", func(cli *aws.SRegion, args *InstanceOperationOptions) error {
err := cli.DeleteVM(args.ID)
if err != nil {
return err
}
return nil
})
/*
server-change-config 更改系统配置
server-reset
*/
type InstanceDeployOptions struct {
ID string `help:"instance ID"`
Name string `help:"new instance name"`
Hostname string `help:"new hostname"`
Keypair string `help:"Keypair Name"`
DeleteKeypair bool `help:"Remove SSH keypair"`
Password string `help:"new password"`
// ResetPassword bool `help:"Force reset password"`
Description string `help:"new instances description"`
}
shellutils.R(&InstanceDeployOptions{}, "instance-deploy", "Deploy keypair/password to a stopped virtual server", func(cli *aws.SRegion, args *InstanceDeployOptions) error {
err := cli.DeployVM(args.ID, args.Name, args.Password, args.Keypair, args.DeleteKeypair, args.Description)
if err != nil {
return err
}
return nil
})
type InstanceRebuildRootOptions struct {
ID string `help:"instance ID"`
Image string `help:"Image ID"`
Size int `help:"system disk size in GB"`
}
shellutils.R(&InstanceRebuildRootOptions{}, "instance-rebuild-root", "Reinstall virtual server system image", func(cli *aws.SRegion, args *InstanceRebuildRootOptions) error {
diskID, err := cli.ReplaceSystemDisk(args.ID, args.Image, args.Size)
if err != nil {
return err
}
fmt.Printf("New diskID is %s", diskID)
return nil
})
type InstanceChangeConfigOptions struct {
ID string `help:"instance ID"`
Ncpu int `help:"number of CPU"`
Vmem int `help:"MiB of memory"`
Disk []int `help:"Data disk sizes int GB"`
}
shellutils.R(&InstanceChangeConfigOptions{}, "instance-change-config", "Deploy keypair/password to a stopped virtual server", func(cli *aws.SRegion, args *InstanceChangeConfigOptions) error {
instance, e := cli.GetInstance(args.ID)
if e != nil {
return e
}
// todo : add create disks
err := cli.ChangeVMConfig(instance.ZoneId, args.ID, args.Ncpu, args.Vmem, nil)
if err != nil {
return err
}
return nil
})
}
+34
View File
@@ -0,0 +1,34 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/aws"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type InstanceTypeListOptions struct {
}
shellutils.R(&InstanceTypeListOptions{}, "instance-type-list", "List intance types", func(cli *aws.SRegion, args *InstanceTypeListOptions) error {
instanceTypes, e := cli.GetInstanceTypes()
if e != nil {
return e
}
printList(instanceTypes, 0, 0, 0, []string{})
return nil
})
type InstanceMatchOptions struct {
CPU int `help:"CPU count"`
MEM int `help:"Memory in MB"`
GPU int `help:"GPU size"`
Zone string `help:"Test in zone"`
}
shellutils.R(&InstanceMatchOptions{}, "instance-type-select", "Select matching instance types", func(cli *aws.SRegion, args *InstanceMatchOptions) error {
instanceTypes, e := cli.GetMatchInstanceTypes(args.CPU, args.MEM, args.GPU, args.Zone)
if e != nil {
return e
}
printList(instanceTypes, 0, 0, 0, []string{})
return nil
})
}
+34
View File
@@ -0,0 +1,34 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/aws"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type KeyPairListOptions struct {
Limit int `help:"page size"`
Offset int `help:"page offset"`
}
shellutils.R(&KeyPairListOptions{}, "keypair-list", "List keypairs", func(cli *aws.SRegion, args *KeyPairListOptions) error {
keypairs, total, e := cli.GetKeypairs("", "", args.Offset, args.Limit)
if e != nil {
return e
}
printList(keypairs, total, args.Offset, args.Limit, []string{})
return nil
})
type KeyPairImportOptions struct {
NAME string `help:"Name of new keypair"`
PUBKEY string `help:"Public key string"`
}
shellutils.R(&KeyPairImportOptions{}, "keypair-import", "Import a keypair", func(cli *aws.SRegion, args *KeyPairImportOptions) error {
keypair, err := cli.ImportKeypair(args.NAME, args.PUBKEY)
if err != nil {
return err
}
printObject(keypair)
return nil
})
}
+21
View File
@@ -0,0 +1,21 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/aws"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type VSwitchListOptions struct {
Limit int `help:"page size"`
Offset int `help:"page offset"`
}
shellutils.R(&VSwitchListOptions{}, "vswitch-list", "List vswitches", func(cli *aws.SRegion, args *VSwitchListOptions) error {
vswitches, total, e := cli.GetNetwroks(nil, "", args.Offset, args.Limit)
if e != nil {
return e
}
printList(vswitches, total, args.Offset, args.Limit, []string{})
return nil
})
}
+11
View File
@@ -0,0 +1,11 @@
package shell
import "yunion.io/x/onecloud/pkg/util/printutils"
func printList(data interface{}, total, offset, limit int, columns []string) {
printutils.PrintInterfaceList(data, total, offset, limit, columns)
}
func printObject(obj interface{}) {
printutils.PrintInterfaceObject(obj)
}
+16
View File
@@ -0,0 +1,16 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/aws"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type RegionListOptions struct {
}
shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *aws.SRegion, args *RegionListOptions) error {
regions := cli.GetClient().GetRegions()
printList(regions, 0, 0, 0, nil)
return nil
})
}
+34
View File
@@ -0,0 +1,34 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/aws"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type SecurityGroupListOptions struct {
VpcId string `help:"VPC ID"`
Limit int `help:"page size"`
Offset int `help:"page offset"`
}
shellutils.R(&SecurityGroupListOptions{}, "security-group-list", "List security group", func(cli *aws.SRegion, args *SecurityGroupListOptions) error {
secgrps, total, e := cli.GetSecurityGroups(args.VpcId, "", args.Offset, args.Limit)
if e != nil {
return e
}
printList(secgrps, total, args.Offset, args.Limit, []string{})
return nil
})
type SecurityGroupShowOptions struct {
ID string `help:"ID or name of security group"`
}
shellutils.R(&SecurityGroupShowOptions{}, "security-group-show", "Show details of a security group", func(cli *aws.SRegion, args *SecurityGroupShowOptions) error {
secgrp, err := cli.GetSecurityGroupDetails(args.ID)
if err != nil {
return err
}
printObject(secgrp)
return nil
})
}
+45
View File
@@ -0,0 +1,45 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/aws"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type SnapshotListOptions struct {
DiskId string `help:"Disk ID"`
InstanceId string `help:"Instance ID"`
SnapshotIds []string `helo:"Snapshot ids"`
Name string `help:"Snapshot Name"`
Limit int `help:"page size"`
Offset int `help:"page offset"`
}
shellutils.R(&SnapshotListOptions{}, "snapshot-list", "List snapshot", func(cli *aws.SRegion, args *SnapshotListOptions) error {
if snapshots, total, err := cli.GetSnapshots(args.InstanceId, args.DiskId, args.Name, args.SnapshotIds, args.Offset, args.Limit); err != nil {
return err
} else {
printList(snapshots, total, args.Offset, args.Limit, []string{})
return nil
}
})
type SnapshotDeleteOptions struct {
ID string `help:"Snapshot ID"`
}
shellutils.R(&SnapshotDeleteOptions{}, "snapshot-delete", "Delete snapshot", func(cli *aws.SRegion, args *SnapshotDeleteOptions) error {
return cli.DeleteSnapshot(args.ID)
})
type SnapshotCreateOptions struct {
DiskId string `help:"Disk ID"`
Name string `help:"Snapeshot Name"`
Desc string `help:"Snapshot Desc"`
}
shellutils.R(&SnapshotCreateOptions{}, "snapshot-create", "Create snapshot", func(cli *aws.SRegion, args *SnapshotCreateOptions) error {
_, err := cli.CreateSnapshot(args.DiskId, args.Name, args.Desc)
return err
})
}
+21
View File
@@ -0,0 +1,21 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/aws"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type VpcListOptions struct {
Limit int `help:"page size"`
Offset int `help:"page offset"`
}
shellutils.R(&VpcListOptions{}, "vpc-list", "List vpcs", func(cli *aws.SRegion, args *VpcListOptions) error {
vpcs, total, e := cli.GetVpcs(nil, args.Offset, args.Limit)
if e != nil {
return e
}
printList(vpcs, total, args.Offset, args.Limit, []string{})
return nil
})
}
+26
View File
@@ -0,0 +1,26 @@
package shell
import (
"yunion.io/x/onecloud/pkg/util/aws"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type ZoneListOptions struct {
Details bool `help:"show Details"`
// ChargeType string `help:"charge type" choices:"PrePaid|PostPaid" default:"PrePaid"`
// SpotStrategy string `help:"Spot strategy, NoSpot|SpotWithPriceLimit|SpotAsPriceGo" choices:"NoSpot|SpotWithPriceLimit|SpotAsPriceGo" default:"NoSpot"`
}
shellutils.R(&ZoneListOptions{}, "zone-list", "List zones", func(cli *aws.SRegion, args *ZoneListOptions) error {
zones, e := cli.GetIZones()
if e != nil {
return e
}
cols := []string{"zone_id", "local_name", "available_resource_creation", "available_disk_categories"}
if args.Details {
cols = []string{}
}
printList(zones, 0, 0, 0, cols)
return nil
})
}
+188
View File
@@ -0,0 +1,188 @@
package aws
import (
"fmt"
"github.com/aws/aws-sdk-go/service/ec2"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
)
type SnapshotStatusType string
const (
SnapshotStatusAccomplished SnapshotStatusType = "accomplished"
SnapshotStatusProgress SnapshotStatusType = "progressing"
SnapshotStatusFailed SnapshotStatusType = "failed"
)
type SSnapshot struct {
region *SRegion
Progress string
SnapshotId string
SnapshotName string
SourceDiskId string
SourceDiskSize int32
SourceDiskType string
Status SnapshotStatusType
Usage string
}
func (self *SSnapshot) GetDiskType() string {
// todo: self.SourceDiskType
return ""
}
func (self *SSnapshot) GetId() string {
return self.SnapshotId
}
func (self *SSnapshot) GetName() string {
return self.SnapshotName
}
func (self *SSnapshot) GetGlobalId() string {
return fmt.Sprintf("%s", self.SnapshotId)
}
func (self *SSnapshot) GetStatus() string {
// todo: implement me
if self.Status == SnapshotStatusAccomplished {
return models.SNAPSHOT_READY
} else if self.Status == SnapshotStatusProgress {
return models.SNAPSHOT_CREATING
} else { // if self.Status == SnapshotStatusFailed
return models.SNAPSHOT_FAILED
}
}
func (self *SSnapshot) Refresh() error {
if snapshots, total, err := self.region.GetSnapshots("", "", "", []string{self.SnapshotId}, 0, 1); err != nil {
return err
} else if total != 1 {
return cloudprovider.ErrNotFound
} else if err := jsonutils.Update(self, snapshots[0]); err != nil {
return err
}
return nil
}
func (self *SSnapshot) IsEmulated() bool {
return false
}
func (self *SSnapshot) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (self *SSnapshot) GetManagerId() string {
return self.region.client.providerId
}
func (self *SSnapshot) GetSize() int32 {
return self.SourceDiskSize
}
func (self *SSnapshot) GetDiskId() string {
return self.SourceDiskId
}
func (self *SSnapshot) Delete() error {
panic("implement me")
}
func (self *SSnapshot) GetRegionId() string {
return self.region.GetId()
}
func (self *SRegion) GetSnapshots(instanceId string, diskId string, snapshotName string, snapshotIds []string, offset int, limit int) ([]SSnapshot, int, error) {
params := &ec2.DescribeSnapshotsInput{}
filters := make([]*ec2.Filter, 0)
// todo: not support search by instancesId. use Tag?
// if len(instanceId) > o {
// filters = AppendSingleValueFilter(filters, )
// }
// owner by self
owner := "self"
params.SetOwnerIds([]*string{&owner})
if len(diskId) > 0 {
filters = AppendSingleValueFilter(filters, "volume-id", diskId)
}
// not supported. use Tag?
// if len(snapshotName) > 0 {
// filters = AppendSingleValueFilter(filters, "volume-id", diskId)
// }
if len(filters) > 0 {
params.SetFilters(filters)
}
if len(snapshotIds) > 0 {
params.SetSnapshotIds(ConvertedList(snapshotIds))
}
ret, err := self.ec2Client.DescribeSnapshots(params)
if err != nil {
return nil, 0, err
}
snapshots := []SSnapshot{}
for _, item := range ret.Snapshots {
if err := FillZero(item); err != nil {
return nil, 0, err
}
snapshot := SSnapshot{}
snapshot.SnapshotId = *item.SnapshotId
snapshot.Status = SnapshotStatusType(*item.State)
snapshot.region = self
snapshot.Progress = *item.Progress
snapshot.SnapshotName = *item.SnapshotId
snapshot.SourceDiskId = *item.VolumeId
snapshot.SourceDiskSize = int32(*item.VolumeSize)
// snapshot.SourceDiskType
snapshots = append(snapshots, snapshot)
}
return snapshots, len(snapshots), nil
}
func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) {
if snapshots, total, err := self.GetSnapshots("", "", "", []string{snapshotId}, 0, 1); err != nil {
return nil, err
} else if total != 1 {
return nil, cloudprovider.ErrNotFound
} else {
return &snapshots[0], nil
}
}
func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) {
params := &ec2.CreateSnapshotInput{}
if len(diskId) <= 0 {
return "", fmt.Errorf("disk id should not be empty")
} else {
params.SetVolumeId(diskId)
}
if len(name) <= 0 {
return "", fmt.Errorf("name length should great than 0")
} else {
tagspec := TagSpec{ResourceType: "snapshot"}
tagspec.SetNameTag(name)
ec2Tag, _ := tagspec.GetTagSpecifications()
params.SetTagSpecifications([]*ec2.TagSpecification{ec2Tag})
}
params.SetDescription(desc)
_, err := self.ec2Client.CreateSnapshot(params)
return "", err
}
func (self *SRegion) DeleteSnapshot(snapshotId string) error {
params := &ec2.DeleteSnapshotInput{}
params.SetSnapshotId(snapshotId)
_, err := self.ec2Client.DeleteSnapshot(params)
return err
}
+124
View File
@@ -0,0 +1,124 @@
package aws
import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
)
type SStorage struct {
zone *SZone
storageType string
}
func (self *SStorage) GetId() string {
return fmt.Sprintf("%s-%s-%s", self.zone.region.client.providerId, self.zone.GetId(), self.storageType)
}
func (self *SStorage) GetName() string {
return fmt.Sprintf("%s-%s-%s", self.zone.region.client.providerName, self.zone.GetId(), self.storageType)
}
func (self *SStorage) GetGlobalId() string {
return fmt.Sprintf("%s-%s-%s", self.zone.region.client.providerId, self.zone.GetGlobalId(), self.storageType)
}
func (self *SStorage) GetStatus() string {
return models.STORAGE_ONLINE
}
func (self *SStorage) Refresh() error {
return nil
}
func (self *SStorage) IsEmulated() bool {
return true
}
func (self *SStorage) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache {
return self.zone.region.getStoragecache()
}
func (self *SStorage) GetIZone() cloudprovider.ICloudZone {
return self.zone
}
func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
disks := make([]SDisk, 0)
for {
parts, total, err := self.zone.region.GetDisks("", self.zone.GetId(), self.storageType, nil, len(disks), 50)
if err != nil {
log.Errorf("GetDisks fail %s", err)
return nil, err
}
disks = append(disks, parts...)
if len(disks) >= total {
break
}
}
idisks := make([]cloudprovider.ICloudDisk, len(disks))
for i := 0; i < len(disks); i += 1 {
disks[i].storage = self
idisks[i] = &disks[i]
}
return idisks, nil
}
func (self *SStorage) GetStorageType() string {
return self.storageType
}
func (self *SStorage) GetMediumType() string {
if self.storageType == models.STORAGE_GP2_SSD || self.storageType == models.STORAGE_IO1_SSD {
return models.DISK_TYPE_SSD
} else {
return models.DISK_TYPE_ROTATE
}
}
func (self *SStorage) GetCapacityMB() int {
return 0 // unlimited
}
func (self *SStorage) GetStorageConf() jsonutils.JSONObject {
conf := jsonutils.NewDict()
return conf
}
func (self *SStorage) GetEnabled() bool {
return true
}
func (self *SStorage) GetManagerId() string {
return self.zone.region.client.providerId
}
func (self *SStorage) CreateIDisk(name string, sizeGb int, desc string) (cloudprovider.ICloudDisk, error) {
diskId, err := self.zone.region.CreateDisk(self.zone.ZoneId, self.storageType, name, sizeGb, "", desc)
if err != nil {
log.Errorf("createDisk fail %s", err)
return nil, err
}
disk, err := self.zone.region.GetDisk(diskId)
if err != nil {
log.Errorf("getDisk fail %s", err)
return nil, err
}
disk.storage = self
return disk, nil
}
func (self *SStorage) GetIDisk(idStr string) (cloudprovider.ICloudDisk, error) {
if disk, err := self.zone.region.GetDisk(idStr); err != nil {
return nil, err
} else {
disk.storage = self
return disk, nil
}
}
+474
View File
@@ -0,0 +1,474 @@
package aws
import (
"bytes"
"fmt"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/aws/aws-sdk-go/service/s3"
"io/ioutil"
"strings"
"time"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/options"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/mcclient/modules"
)
type SStoragecache struct {
region *SRegion
iimages []cloudprovider.ICloudImage
}
func (self *SStoragecache) GetId() string {
return fmt.Sprintf("%s-%s", self.region.client.providerId, self.region.GetId())
}
func (self *SStoragecache) GetName() string {
return fmt.Sprintf("%s-%s", self.region.client.providerName, self.region.GetId())
}
func (self *SStoragecache) GetGlobalId() string {
return fmt.Sprintf("%s-%s", self.region.client.providerId, self.region.GetGlobalId())
}
func (self *SStoragecache) GetStatus() string {
return "available"
}
func (self *SStoragecache) Refresh() error {
return nil
}
func (self *SStoragecache) IsEmulated() bool {
return false
}
func (self *SStoragecache) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (self *SStoragecache) GetIImages() ([]cloudprovider.ICloudImage, error) {
if self.iimages == nil {
err := self.fetchImages()
if err != nil {
return nil, err
}
}
return self.iimages, nil
}
func (self *SStoragecache) GetManagerId() string {
return self.region.client.providerId
}
func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) {
if imageId, err := self.region.createIImage(snapshotId, imageName, imageDesc); err != nil {
return nil, err
} else if image, err := self.region.GetImage(imageId); err != nil {
return nil, err
} else {
image.storageCache = self
iimage := make([]cloudprovider.ICloudImage, 1)
iimage[0] = image
//todo : implement me
if err := cloudprovider.WaitStatus(iimage[0], "avaliable", 15*time.Second, 3600*time.Second); err != nil {
return nil, err
}
return iimage[0], nil
}
}
func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) {
return self.downloadImage(userCred, imageId, extId)
}
func (self *SStoragecache) UploadImage(userCred mcclient.TokenCredential, imageId string, osArch, osType, osDist string, extId string, isForce bool) (string, error) {
if len(extId) > 0 {
log.Debugf("UploadImage: Image external ID exists %s", extId)
status, err := self.region.GetImageStatus(extId)
if err != nil {
log.Errorf("GetImageStatus error %s", err)
}
if status == ImageStatusAvailable && !isForce {
return extId, nil
}
} else {
log.Debugf("UploadImage: no external ID")
}
return self.uploadImage(userCred, imageId, osArch, osType, osDist, isForce)
}
func (self *SStoragecache) fetchImages() error {
images := make([]SImage, 0)
for {
parts, total, err := self.region.GetImages(ImageStatusType(""), ImageOwnerSelf, nil, "", len(images), 50)
if err != nil {
return err
}
images = append(images, parts...)
if len(images) >= total {
break
}
}
self.iimages = make([]cloudprovider.ICloudImage, len(images))
for i := 0; i < len(images); i += 1 {
images[i].storageCache = self
self.iimages[i] = &images[i]
}
return nil
}
func (self *SStoragecache) uploadImage(userCred mcclient.TokenCredential, imageId string, osArch, osType, osDist string, isForce bool) (string, error) {
// todo: implement me
bucketName := "imgcache-onecloud"
err := self.region.initVmimport()
if err != nil {
return "", err
}
// first upload image to oss
s := auth.GetAdminSession(options.Options.Region, "")
meta, reader, err := modules.Images.Download(s, imageId)
if err != nil {
return "", err
}
log.Infof("meta data %s", meta)
diskFormat, err := meta.GetString("disk_format")
if err != nil {
return "", err
}
s3Client, err := self.region.getS3Client()
if err != nil {
return "", nil
}
// 内存?
f, err := ioutil.ReadAll(reader)
params := &s3.PutObjectInput{}
params.SetBucket(bucketName)
params.SetKey(imageId)
params.SetBody(bytes.NewReader(f))
_, err = s3Client.PutObject(params)
if err != nil {
return "", nil
}
imageBaseName := imageId
if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' {
imageBaseName = fmt.Sprintf("img%s", imageId)
}
imageName := imageBaseName
nameIdx := 1
// check image name, avoid name conflict
for {
_, err = self.region.GetImageByName(imageName)
if err != nil {
if err == cloudprovider.ErrNotFound {
break
} else {
return "", err
}
}
imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx)
nameIdx += 1
}
task, err := self.region.ImportImage(imageName, osArch, osType, osDist, diskFormat, bucketName, imageId)
if err != nil {
log.Errorf("ImportImage error %s %s %s", imageId, bucketName, err)
return "", err
}
// todo:// 等待镜像导入完成
for i := 1; i < 120; i++ {
ret, err := self.region.ec2Client.DescribeImportImageTasks(&ec2.DescribeImportImageTasksInput{ImportTaskIds: []*string{&task.TaskId}})
if err != nil {
return "", err
}
err = FillZero(ret)
if err != nil {
return "", err
}
log.Debugf("DescribeImportImage Task %s", ret.String())
for _, item := range ret.ImportImageTasks {
if *item.Status == "completed" {
return *item.ImageId, nil
}
}
time.Sleep(1 * time.Minute)
}
return task.ImageId, fmt.Errorf("uploadImage uncompleted: %s", task)
}
func (self *SStoragecache) downloadImage(userCred mcclient.TokenCredential, imageId string, extId string) (jsonutils.JSONObject, error) {
// aws 导出镜像限制比较多。https://docs.aws.amazon.com/zh_cn/vm-import/latest/userguide/vmexport.html
bucketName := "imgcache-onecloud"
if err := self.region.checkBucket(bucketName); err != nil {
return nil, err
}
instanceId, err := self.region.GetInstanceIdByImageId(extId)
if err != nil {
return nil, err
}
task, err := self.region.ExportImage(instanceId, imageId)
if err != nil {
return nil, err
}
taskParams := &ec2.DescribeExportTasksInput{}
taskParams.SetExportTaskIds([]*string{&task.TaskId})
if err := self.region.ec2Client.WaitUntilExportTaskCompleted(taskParams); err != nil {
return nil, err
}
s3Client, err := self.region.getS3Client()
if err != nil {
return nil, err
}
i := &s3.GetObjectInput{}
i.SetBucket(bucketName)
i.SetKey(fmt.Sprintf("%s.%s", task.TaskId, "ova"))
ret, err := s3Client.GetObject(i)
if err != nil {
return nil, err
}
s := auth.GetAdminSession(options.Options.Region, "")
params := jsonutils.Marshal(map[string]string{"image_id": imageId, "disk-format": "raw"})
if result, err := modules.Images.Upload(s, params, ret.Body, IntVal(ret.ContentLength)); err != nil {
return nil, err
} else {
return result, nil
}
}
func (self *SRegion) CheckBucket(bucketName string) error {
return self.checkBucket(bucketName)
}
func (self *SRegion) checkBucket(bucketName string) error {
exists, err := self.IsBucketExist(bucketName)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("bucket %s not found", bucketName)
} else {
return nil
}
}
func (self *SRegion) IsBucketExist(bucketName string) (bool, error) {
s3Client, err := self.getS3Client()
if err != nil {
return false, err
}
params := &s3.ListBucketsInput{}
ret, err := s3Client.ListBuckets(params)
if err != nil {
return false, err
}
for _, bucket := range ret.Buckets {
if bucket.Name != nil && *bucket.Name == bucketName {
return true, nil
}
}
return false, nil
}
func (self *SRegion) GetARNPartition() string {
// https://docs.amazonaws.cn/general/latest/gr/aws-arns-and-namespaces.html?id=docs_gateway
// https://github.com/aws/chalice/issues/777
// https://github.com/aws/chalice/issues/792
/*
I assume this is because the ARN format is slightly different for China.
In general, ARNs follow the pattern arn:partition:service:region:account-id:resource,
where partition is aws for most of the world and aws-cn for China.
It looks like the more common "arn:aws" is currently hardcoded in quite a few places.
*/
if strings.HasPrefix(self.RegionId, "cn-") {
return "aws-cn"
} else {
return "aws"
}
}
func (self *SRegion) initVmimportRole() error {
/*需要api access token 具备iam Full access权限*/
iamClient, err := self.getIamClient()
if err != nil {
return err
}
// search role vmimport
rolename := "vmimport"
ret, _ := iamClient.GetRole(&iam.GetRoleInput{RoleName: &rolename})
// todo: 这里得区分是not found.还是其他错误
if ret.Role != nil && ret.Role.RoleId != nil {
return nil
} else {
// create it
roleDoc := `{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "vmie.amazonaws.com" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals":{
"sts:Externalid": "vmimport"
}
}
}
]
}`
params := &iam.CreateRoleInput{}
params.SetDescription("vmimport role for image import")
params.SetRoleName(rolename)
params.SetAssumeRolePolicyDocument(roleDoc)
_, err = iamClient.CreateRole(params)
return err
}
}
func (self *SRegion) initVmimportRolePolicy() error {
/*需要api access token 具备iam Full access权限*/
iamClient, err := self.getIamClient()
if err != nil {
return err
}
partition := self.GetARNPartition()
roleName := "vmimport"
policyName := "vmimport"
ret, err := iamClient.GetRolePolicy(&iam.GetRolePolicyInput{RoleName: &roleName, PolicyName: &policyName})
// todo: 这里得区分是not found.还是其他错误.
if ret.PolicyName != nil {
return nil
} else {
rolePolicy := `{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Action":[
"s3:GetBucketLocation",
"s3:GetObject",
"s3:ListBucket"
],
"Resource":[
"arn:%[1]s:s3:::%[2]s",
"arn:%[1]s:s3:::%[2]s/*"
]
},
{
"Effect":"Allow",
"Action":[
"ec2:ModifySnapshotAttribute",
"ec2:CopySnapshot",
"ec2:RegisterImage",
"ec2:Describe*"
],
"Resource":"*"
}
]
}`
params := &iam.PutRolePolicyInput{}
params.SetPolicyDocument(fmt.Sprintf(rolePolicy, partition, "imgcache-onecloud"))
params.SetPolicyName(policyName)
params.SetRoleName(roleName)
_, err = iamClient.PutRolePolicy(params)
return err
}
}
func (self *SRegion) initVmimportBucket() error {
bucketName := "imgcache-onecloud"
// todo: "imgcache-onecloud" 使用常量
exists, err := self.IsBucketExist("imgcache-onecloud")
if err != nil {
return err
}
if exists {
return nil
}
s3Client, err := self.getS3Client()
if err != nil {
return err
}
_, err = s3Client.CreateBucket(&s3.CreateBucketInput{Bucket: &bucketName})
return err
}
func (self *SRegion) initVmimport() error {
if err := self.initVmimportRole(); err != nil {
return err
}
if err := self.initVmimportRolePolicy(); err != nil {
return err
}
if err := self.initVmimportBucket(); err != nil {
return err
}
return nil
}
func (self *SRegion) createIImage(snapshotId, imageName, imageDesc string) (string, error) {
params := &ec2.CreateImageInput{}
params.SetDescription(imageDesc)
params.SetName(imageName)
block := &ec2.BlockDeviceMapping{}
block.SetDeviceName("/dev/sda1")
ebs := &ec2.EbsBlockDevice{}
ebs.SetSnapshotId(snapshotId)
ebs.SetDeleteOnTermination(true)
block.SetEbs(ebs)
blockList := []*ec2.BlockDeviceMapping{block}
params.SetBlockDeviceMappings(blockList)
ret, err := self.ec2Client.CreateImage(params)
if err != nil {
return "", err
}
return *ret.ImageId, nil
}
func (self *SRegion) getStoragecache() *SStoragecache {
if self.storageCache == nil {
self.storageCache = &SStoragecache{region: self}
}
return self.storageCache
}
+426
View File
@@ -0,0 +1,426 @@
package aws
import (
"fmt"
"net"
"reflect"
"strings"
"yunion.io/x/jsonutils"
"github.com/aws/aws-sdk-go/service/ec2"
"yunion.io/x/log"
"yunion.io/x/pkg/util/secrules"
)
type portRange struct {
Start int64
End int64
}
type TagSpec struct {
ResourceType string // "customer-gateway"|"dedicated-host"|"dhcp-options"|"image"|"instance"|"internet-gateway"|"network-acl"|"network-interface"|"reserved-instances"|"route-table"|"snapshot"|"spot-instances-request"|"subnet"|"security-group"|"volume"|"vpc"|"vpn-connection"|"vpn-gateway"
Tags map[string]string
}
func (self *TagSpec) LoadingEc2Tags(tags []*ec2.Tag) {
for _, tag := range tags {
if tag.Key != nil && tag.Value != nil {
self.SetTag(*tag.Key, *tag.Value)
}
}
}
func (self *TagSpec) GetTagSpecifications() (*ec2.TagSpecification, error) {
if self.ResourceType == "" {
return nil, fmt.Errorf("ResourceType should not be empty")
}
spec := &ec2.TagSpecification{ResourceType: &self.ResourceType}
tags := []*ec2.Tag{}
for k, v := range self.Tags {
if len(v) > 255 {
return nil, fmt.Errorf("%s value length should less than 255", k)
}
tag := &ec2.Tag{}
tag.SetKey(k)
tag.SetValue(v)
tags = append(tags, tag)
}
spec.SetTags(tags)
return spec, nil
}
func (self *TagSpec) SetTag(k, v string) {
if self.Tags == nil {
self.Tags = make(map[string]string)
}
self.Tags[k] = v
}
func (self *TagSpec) SetNameTag(v string) {
self.SetTag("Name", v)
}
func (self *TagSpec) SetDescTag(v string) {
self.SetTag("Description", v)
}
func (self *TagSpec) GetTag(k string) (string, error) {
v, ok := self.Tags[k]
if !ok {
return "", fmt.Errorf("%s not found", k)
}
return v, nil
}
// 找不到的情况下返回传入的默认值
func (self *TagSpec) GetTagWithDefault(k, Default string) string {
v, ok := self.Tags[k]
if !ok {
return Default
}
return v
}
func (self *TagSpec) GetNameTag() string {
return self.GetTagWithDefault("Name", "")
}
func (self *TagSpec) GetDescTag() string {
return self.GetTagWithDefault("Description", "")
}
func AppendFilter(filters []*ec2.Filter, name string, values []string) []*ec2.Filter {
f := &ec2.Filter{}
v := make([]*string, len(values))
for _, value := range values {
v = append(v, &value)
}
f.SetName(name)
f.SetValues(v)
return append(filters, f)
}
func AppendSingleValueFilter(filters []*ec2.Filter, name string, value string) []*ec2.Filter {
f := &ec2.Filter{}
f.SetName(name)
f.SetValues([]*string{&value})
return append(filters, f)
}
func ConvertedList(list []string) []*string {
result := make([]*string, 0)
for _, item := range list {
if len(item) > 0 {
result = append(result, &item)
}
}
return result
}
func ConvertedPointList(list []*string) []string {
result := make([]string, len(list))
for _, item := range list {
if item != nil {
result = append(result, *item)
}
}
return result
}
func StrVal(s *string) string {
if s != nil {
return *s
}
return ""
}
func IntVal(s *int64) int64 {
if s != nil {
return *s
}
return 0
}
func isAwsPermissionAllPorts(p ec2.IpPermission) bool {
if p.FromPort == nil || p.ToPort == nil {
return false
}
// 全部端口范围: TCP/UDP (0,65535) 其他:(-1,-1)
if (*p.IpProtocol == "tcp" || *p.IpProtocol == "udp") && *p.FromPort == 0 && *p.ToPort == 65535 {
return true
} else if *p.FromPort == -1 && *p.ToPort == -1 {
return true
} else {
return false
}
}
func awsProtocolToYunion(p ec2.IpPermission) string {
if p.IpProtocol != nil && *p.IpProtocol == "-1" {
return secrules.PROTO_ANY
} else {
return *p.IpProtocol
}
}
func yunionProtocolToAws(r secrules.SecurityRule) string {
if r.Protocol == secrules.PROTO_ANY {
return "-1"
} else {
return r.Protocol
}
}
func isYunionRuleAllPorts(r secrules.SecurityRule) bool {
// 全部端口范围: TCP/UDP (0,65535) 其他:(-1,-1)
if (r.Protocol == "tcp" || r.Protocol == "udp") && r.PortStart == 0 && r.PortEnd == 65535 {
return true
} else if r.PortStart == -1 && r.PortEnd == -1 {
return true
} else {
return false
}
}
func yunionPortRangeToAws(r secrules.SecurityRule) []portRange {
// port 0 / -1 都代表所有端口
portranges := []portRange{}
if len(r.Ports) == 0 {
var start, end = 0, 0
if r.PortStart <= 0 {
if r.Protocol == "tcp" || r.Protocol == "udp" {
start = 0
} else {
start = -1
}
} else {
start = r.PortStart
}
if r.PortEnd <= 0 {
if r.Protocol == "tcp" || r.Protocol == "udp" {
end = 65535
} else {
end = -1
}
} else {
end = r.PortEnd
}
portranges = append(portranges, portRange{int64(start), int64(end)})
}
for _, port := range r.Ports {
if port <= 0 && (r.Protocol == "tcp" || r.Protocol == "udp") {
portranges = append(portranges, portRange{0, 65535})
} else if port <= 0 {
portranges = append(portranges, portRange{-1, -1})
} else {
portranges = append(portranges, portRange{int64(port), int64(port)})
}
}
return portranges
}
// Security Rule Transform
func AwsIpPermissionToYunion(direction secrules.TSecurityRuleDirection, p ec2.IpPermission) ([]secrules.SecurityRule, error) {
if len(p.UserIdGroupPairs) > 0 {
return nil, fmt.Errorf("AwsIpPermissionToYunion not supported aws rule: UserIdGroupPairs specified")
}
if len(p.PrefixListIds) > 0 {
return nil, fmt.Errorf("AwsIpPermissionToYunion not supported aws rule: PrefixListIds specified")
}
if len(p.Ipv6Ranges) > 0 {
log.Debugf("AwsIpPermissionToYunion ignored IPV6 rule: %s", p.Ipv6Ranges)
}
rules := []secrules.SecurityRule{}
isAllPorts := isAwsPermissionAllPorts(p)
protocol := awsProtocolToYunion(p)
for _, ip := range p.IpRanges {
_, ipNet, err := net.ParseCIDR(*ip.CidrIp)
if err != nil {
log.Errorf("ParseCIDR failed, ignored IPV4 rule: %s", *ip.CidrIp)
continue
}
var rule secrules.SecurityRule
if isAllPorts {
rule = secrules.SecurityRule{
Action: secrules.SecurityRuleAllow,
IPNet: ipNet,
Protocol: protocol,
Direction: direction,
Priority: 1,
Description: StrVal(ip.Description),
}
} else {
rule = secrules.SecurityRule{
Action: secrules.SecurityRuleAllow,
IPNet: ipNet,
Protocol: protocol,
Direction: direction,
Priority: 1,
Description: StrVal(ip.Description),
}
if p.FromPort != nil {
rule.PortStart = int(*p.FromPort)
}
if p.ToPort != nil {
rule.PortEnd = int(*p.ToPort)
}
}
rules = append(rules, rule)
}
return rules, nil
}
func YunionSecRuleToAws(rule secrules.SecurityRule) ([]*ec2.IpPermission, error) {
if rule.Action == secrules.SecurityRuleDeny {
return nil, fmt.Errorf("YunionSecRuleToAws ignored aws not supported deny rule")
}
iprange := rule.IPNet.String()
if iprange == "<nil>" {
return nil, fmt.Errorf("YunionSecRuleToAws ignored ipnet should not be empty")
}
ipranges := []*ec2.IpRange{}
ipranges = append(ipranges, &ec2.IpRange{CidrIp: &iprange, Description: &rule.Description})
portranges := yunionPortRangeToAws(rule)
protocol := yunionProtocolToAws(rule)
permissions := []*ec2.IpPermission{}
for _, port := range portranges {
permission := ec2.IpPermission{
FromPort: &port.Start,
IpProtocol: &protocol,
IpRanges: ipranges,
ToPort: &port.End,
}
permissions = append(permissions, &permission)
}
return permissions, nil
}
// fill a pointer struct with zero value.
func FillZero(i interface{}) error {
V := reflect.Indirect(reflect.ValueOf(i))
if !V.CanSet() {
return fmt.Errorf("input is not addressable: %#v", i)
}
if V.Kind() != reflect.Struct {
return fmt.Errorf("only accept struct type")
}
for i := 0; i < V.NumField(); i++ {
field := V.Field(i)
if field.Kind() == reflect.Ptr && field.IsNil() {
if field.CanSet() {
field.Set(reflect.New(field.Type().Elem()))
}
}
vField := reflect.Indirect(field)
switch vField.Kind() {
case reflect.Map:
vField.Set(reflect.MakeMap(vField.Type()))
case reflect.Struct:
if field.CanInterface() {
err := FillZero(field.Interface())
if err != nil {
return err
}
}
}
}
return nil
}
func NextDeviceName(curDeviceNames []string) (string, error) {
currents := []string{}
for _, item := range curDeviceNames {
currents = append(currents, strings.ToLower(item))
}
for i := 0; i < 25; i++ {
device := fmt.Sprintf("/dev/sd%s", string(98+i))
found := false
for _, item := range currents {
if strings.HasPrefix(item, device) {
found = true
}
}
if !found {
return device, nil
}
}
for i := 0; i < 25; i++ {
device := fmt.Sprintf("/dev/vxd%s", string(98+i))
found := false
for _, item := range currents {
if !strings.HasPrefix(item, device) {
return device, nil
}
}
if !found {
return device, nil
}
}
return "", fmt.Errorf("disk devicename out of index, current deivces: %s", currents)
}
// fetch tags
func FetchTags(client *ec2.EC2, resourceId string) (*jsonutils.JSONDict, error) {
result := jsonutils.NewDict()
params := &ec2.DescribeTagsInput{}
filters := []*ec2.Filter{}
if len(resourceId) == 0 {
return result, fmt.Errorf("resource id should not be empty")
}
// todo: add resource type filter
filters = AppendSingleValueFilter(filters, "resource-id", resourceId)
params.SetFilters(filters)
ret, err := client.DescribeTags(params)
if err != nil {
return result, err
}
for _, tag := range ret.Tags {
if tag.Key != nil && tag.Value != nil {
result.Set(*tag.Key, jsonutils.NewString(*tag.Value))
}
}
return result, nil
}
+288
View File
@@ -0,0 +1,288 @@
package aws
import (
"fmt"
"github.com/aws/aws-sdk-go/service/ec2"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/pkg/util/secrules"
)
type SUserCIDRs struct {
UserCidr []string
}
type SVpc struct {
region *SRegion
iwires []cloudprovider.ICloudWire
secgroups []cloudprovider.ICloudSecurityGroup
RegionId string
VpcId string
VpcName string
CidrBlock string
IsDefault bool
Status string
Tags map[string]string // 名称、描述等
}
func (self *SVpc) addWire(wire *SWire) {
if self.iwires == nil {
self.iwires = make([]cloudprovider.ICloudWire, 0)
}
self.iwires = append(self.iwires, wire)
}
func (self *SVpc) GetId() string {
return self.VpcId
}
func (self *SVpc) GetName() string {
if len(self.VpcName) > 0 {
return self.VpcName
}
return self.VpcId
}
func (self *SVpc) GetGlobalId() string {
return self.VpcId
}
func (self *SVpc) GetStatus() string {
return strings.ToLower(self.Status)
}
func (self *SVpc) Refresh() error {
new, err := self.region.getVpc(self.VpcId)
if err != nil {
return err
}
return jsonutils.Update(self, new)
}
func (self *SVpc) IsEmulated() bool {
return false
}
func (self *SVpc) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (self *SVpc) GetRegion() cloudprovider.ICloudRegion {
return self.region
}
func (self *SVpc) GetIsDefault() bool {
return self.IsDefault
}
func (self *SVpc) GetCidrBlock() string {
return self.CidrBlock
}
func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) {
if self.iwires == nil {
err := self.fetchNetworks()
if err != nil {
return nil, err
}
}
return self.iwires, nil
}
func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) {
if self.secgroups == nil {
err := self.fetchSecurityGroups()
if err != nil {
return nil, err
}
}
return self.secgroups, nil
}
func (self *SVpc) GetManagerId() string {
return self.region.client.providerId
}
func (self *SVpc) Delete() error {
err := self.fetchSecurityGroups()
if err != nil {
log.Errorf("fetchSecurityGroup for VPC delete fail %s", err)
return err
}
for i := 0; i < len(self.secgroups); i += 1 {
secgroup := self.secgroups[i].(*SSecurityGroup)
err := self.region.deleteSecurityGroup(secgroup.SecurityGroupId)
if err != nil {
log.Errorf("deleteSecurityGroup for VPC delete fail %s", err)
return err
}
}
return self.region.DeleteVpc(self.VpcId)
}
func (self *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) {
if self.iwires == nil {
err := self.fetchNetworks()
if err != nil {
return nil, err
}
}
for i := 0; i < len(self.iwires); i += 1 {
if self.iwires[i].GetGlobalId() == wireId {
return self.iwires[i], nil
}
}
return nil, cloudprovider.ErrNotFound
}
func (self *SVpc) SyncSecurityGroup(secgroupId string, name string, rules []secrules.SecurityRule) (string, error) {
secgrpId := ""
if secgroup, err := self.region.getSecurityGroupByTag(self.VpcId, secgroupId); err != nil {
// 名称为default的安全组与aws默认安全组名冲突
if strings.ToLower(name) == "default" {
name = fmt.Sprintf("%s-%s", self.VpcId, name)
}
desc := fmt.Sprintf("security group %s for vpc %s", name, self.VpcId)
if secgrpId, err = self.region.createSecurityGroup(self.VpcId, name, secgroupId, desc); err != nil {
return "", err
}
//addRules
log.Debugf("Add Rules for %s : %s", secgrpId, rules)
for _, rule := range rules {
if err := self.region.addSecurityGroupRule(secgrpId, &rule); err != nil {
return "", err
}
}
} else {
//syncRules
secgrpId = secgroup.SecurityGroupId
log.Debugf("Sync Rules for %s", secgroup.GetName())
if secgroup.GetName() != name {
if err := self.region.modifySecurityGroup(secgrpId, name, ""); err != nil {
log.Errorf("Change SecurityGroup name to %s failed: %v", name, err)
}
}
self.region.syncSecgroupRules(secgrpId, rules)
}
return secgrpId, nil
}
func (self *SVpc) getWireByZoneId(zoneId string) *SWire {
for i := 0; i < len(self.iwires); i += 1 {
wire := self.iwires[i].(*SWire)
if wire.zone.ZoneId == zoneId {
return wire
}
}
zone, err := self.region.getZoneById(zoneId)
if err != nil {
return nil
}
return &SWire{
zone: zone,
vpc: self,
}
}
func (self *SVpc) fetchNetworks() error {
networks, _, err := self.region.GetNetwroks(nil, self.VpcId, 0, 0)
if err != nil {
return err
}
for i := 0; i < len(networks); i += 1 {
wire := self.getWireByZoneId(networks[i].ZoneId)
networks[i].wire = wire
wire.addNetwork(&networks[i])
}
return nil
}
func (self *SVpc) revokeSecurityGroup(secgroupId string, instanceId string, keep bool) error {
return self.region.revokeSecurityGroup(secgroupId, instanceId, keep)
}
func (self *SVpc) assignSecurityGroup(secgroupId string, instanceId string) error {
return self.region.assignSecurityGroup(secgroupId, instanceId)
}
func (self *SVpc) fetchSecurityGroups() error {
secgroups, _, err := self.region.GetSecurityGroups(self.VpcId, "", 0, 0)
if err != nil {
return err
}
self.secgroups = make([]cloudprovider.ICloudSecurityGroup, len(secgroups))
for i := 0; i < len(secgroups); i++ {
secgroups[i].vpc = self
self.secgroups[i] = &secgroups[i]
}
return nil
}
func (self *SRegion) getVpc(vpcId string) (*SVpc, error) {
vpcs, total, err := self.GetVpcs([]string{vpcId}, 0, 1)
if err != nil {
return nil, err
}
if total != 1 {
return nil, cloudprovider.ErrNotFound
}
vpcs[0].region = self
return &vpcs[0], nil
}
func (self *SRegion) revokeSecurityGroup(secgroupId, instanceId string, keep bool) error {
return nil
}
func (self *SRegion) assignSecurityGroup(secgroupId, instanceId string) error {
return nil
}
func (self *SRegion) deleteSecurityGroup(secGrpId string) error {
return nil
}
func (self *SRegion) DeleteVpc(vpcId string) error {
return nil
}
func (self *SRegion) GetVpcs(vpcId []string, offset int, limit int) ([]SVpc, int, error) {
params := &ec2.DescribeVpcsInput{}
if len(vpcId) > 0 {
params.SetVpcIds(ConvertedList(vpcId))
}
ret, err := self.ec2Client.DescribeVpcs(params)
if err != nil {
return nil, 0, err
}
vpcs := []SVpc{}
for _, item := range ret.Vpcs {
if err := FillZero(item); err != nil {
return nil, 0, err
}
vpcs = append(vpcs, SVpc{
region: self,
// secgroups: nil,
RegionId: self.RegionId,
VpcId: *item.VpcId,
VpcName: *item.VpcId,
CidrBlock: *item.CidrBlock,
IsDefault: *item.IsDefault,
Status: *item.State,
// Tags: *item.Tags,
})
}
return vpcs, len(vpcs), nil
}
+125
View File
@@ -0,0 +1,125 @@
package aws
import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SWire struct {
zone *SZone
vpc *SVpc
inetworks []cloudprovider.ICloudNetwork
}
func (self *SWire) GetId() string {
return fmt.Sprintf("%s-%s", self.vpc.GetId(), self.zone.GetId())
}
func (self *SWire) GetName() string {
return self.GetId()
}
func (self *SWire) GetGlobalId() string {
return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.zone.GetGlobalId())
}
func (self *SWire) GetStatus() string {
return "available"
}
func (self *SWire) Refresh() error {
return nil
}
func (self *SWire) IsEmulated() bool {
return true
}
func (self *SWire) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (self *SWire) GetIVpc() cloudprovider.ICloudVpc {
return self.vpc
}
func (self *SWire) GetIZone() cloudprovider.ICloudZone {
return self.zone
}
func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) {
if self.inetworks == nil {
err := self.vpc.fetchNetworks()
if err != nil {
return nil, err
}
}
return self.inetworks, nil
}
func (self *SWire) GetBandwidth() int {
return 10000
}
func (self *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) {
networks, err := self.GetINetworks()
if err != nil {
return nil, err
}
for i := 0; i < len(networks); i += 1 {
if networks[i].GetGlobalId() == netid {
return networks[i], nil
}
}
return nil, cloudprovider.ErrNotFound
}
func (self *SWire) CreateINetwork(name string, cidr string, desc string) (cloudprovider.ICloudNetwork, error) {
networkId, err := self.zone.region.createNetwork(self.zone.ZoneId, self.vpc.VpcId, name, cidr, desc)
if err != nil {
log.Errorf("createNetwork error %s", err)
return nil, err
}
self.inetworks = nil
network := self.getNetworkById(networkId)
if network == nil {
log.Errorf("cannot find network after create????")
return nil, cloudprovider.ErrNotFound
}
return network, nil
}
func (self *SWire) getNetworkById(networkId string) *SNetwork {
networks, err := self.GetINetworks()
if err != nil {
return nil
}
log.Debugf("search for networks %d", len(networks))
for i := 0; i < len(networks); i += 1 {
log.Debugf("search %s", networks[i].GetName())
network := networks[i]
if network.GetId() == networkId {
return network.(*SNetwork)
}
}
return nil
}
func (self *SWire) addNetwork(network *SNetwork) {
if self.inetworks == nil {
self.inetworks = make([]cloudprovider.ICloudNetwork, 0)
}
find := false
for i := 0; i < len(self.inetworks); i += 1 {
if self.inetworks[i].GetId() == network.NetworkId {
find = true
break
}
}
if !find {
self.inetworks = append(self.inetworks, network)
}
}
+175
View File
@@ -0,0 +1,175 @@
package aws
import (
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
)
var StorageTypes = []string{
models.STORAGE_GP2_SSD,
models.STORAGE_IO1_SSD,
models.STORAGE_ST1_HDD,
models.STORAGE_SC1_SSD,
models.STORAGE_STANDARD_SSD,
}
type SZone struct {
region *SRegion
host *SHost
iwires []cloudprovider.ICloudWire
istorages []cloudprovider.ICloudStorage
ZoneId string // 沿用阿里云ZoneId,对应Aws ZoneName
LocalName string
State string
/* 支持的磁盘种类集合 */
storageTypes []string
}
func (self *SZone) addWire(wire *SWire) {
if self.iwires == nil {
self.iwires = make([]cloudprovider.ICloudWire, 0)
}
self.iwires = append(self.iwires, wire)
}
func (self *SZone) getHost() *SHost {
if self.host == nil {
self.host = &SHost{zone: self}
}
return self.host
}
func (self *SZone) getStorageType() {
if len(self.storageTypes) == 0 {
self.storageTypes = StorageTypes
}
}
func (self *SZone) fetchStorages() error {
self.getStorageType()
self.istorages = make([]cloudprovider.ICloudStorage, len(self.storageTypes))
for i, sc := range self.storageTypes {
storage := SStorage{zone: self, storageType: sc}
self.istorages[i] = &storage
}
return nil
}
func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) {
return self.iwires, nil
}
func (self *SZone) getNetworkById(networkId string) *SNetwork {
log.Debugf("Search in wires %d", len(self.iwires))
for i := 0; i < len(self.iwires); i += 1 {
log.Debugf("Search in wire %s", self.iwires[i].GetName())
wire := self.iwires[i].(*SWire)
net := wire.getNetworkById(networkId)
if net != nil {
return net
}
}
return nil
}
func (self *SZone) GetId() string {
return self.ZoneId
}
func (self *SZone) GetName() string {
return fmt.Sprintf("%s %s", CLOUD_PROVIDER_AWS_CN, self.LocalName)
}
func (self *SZone) GetGlobalId() string {
return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.ZoneId)
}
func (self *SZone) GetStatus() string {
if self.State == "unavailable" {
return models.ZONE_SOLDOUT
} else {
return models.ZONE_ENABLE
}
}
func (self *SZone) Refresh() error {
return nil
}
func (self *SZone) IsEmulated() bool {
return false
}
func (self *SZone) GetMetadata() *jsonutils.JSONDict {
return nil
}
func (self *SZone) GetIRegion() cloudprovider.ICloudRegion {
return self.region
}
func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) {
return []cloudprovider.ICloudHost{self.getHost()}, nil
}
func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) {
host := self.getHost()
if host.GetGlobalId() == id {
return host, nil
}
return nil, cloudprovider.ErrNotFound
}
func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
if self.istorages == nil {
self.fetchStorages()
}
return self.istorages, nil
}
func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) {
if self.istorages == nil {
self.fetchStorages()
}
for i := 0; i < len(self.istorages); i += 1 {
if self.istorages[i].GetGlobalId() == id {
return self.istorages[i], nil
}
}
return nil, cloudprovider.ErrNotFound
}
func (self *SZone) getStorageByCategory(category string) (*SStorage, error) {
storages, err := self.GetIStorages()
if err != nil {
return nil, err
}
for i := 0; i < len(storages); i += 1 {
storage := storages[i].(*SStorage)
if storage.storageType == category {
return storage, nil
}
}
return nil, fmt.Errorf("No such storage %s", category)
}
func (self *SRegion) getZoneById(id string) (*SZone, error) {
izones, err := self.GetIZones()
if err != nil {
return nil, err
}
for i := 0; i < len(izones); i += 1 {
zone := izones[i].(*SZone)
if zone.ZoneId == id {
return zone, nil
}
}
return nil, fmt.Errorf("no such zone %s", id)
}
+5
View File
@@ -214,6 +214,11 @@ func (self *SRegion) doDeleteVM(instanceId string) error {
func (self *SInstance) GetMetadata() *jsonutils.JSONDict {
data := jsonutils.NewDict()
tags := jsonutils.NewDict()
for k, v := range self.Tags {
tags.Set(k, jsonutils.NewString(v))
}
data.Update(tags)
if osDistribution := self.Properties.StorageProfile.ImageReference.Publisher; len(osDistribution) > 0 {
data.Add(jsonutils.NewString(osDistribution), "os_distribution")
}
@@ -0,0 +1,6 @@
package credentials
type BaseCredential struct {
AccessKeyId string
AccessKeySecret string
}
@@ -0,0 +1,5 @@
package credentials
type EcsInstanceCredential struct {
RoleName string
}
@@ -0,0 +1,7 @@
package credentials
type KeyPairCredential struct {
PrivateKey string
PublicKeyId string
SessionExpiration int
}
@@ -0,0 +1,9 @@
package credentials
type StsAssumeRoleCredential struct {
AccessKeyId string
AccessKeySecret string
RoleArn string
RoleSessionName string
RoleSessionExpiration int
}
@@ -0,0 +1,7 @@
package credentials
type StsCredential struct {
AccessKeyId string
AccessKeySecret string
AccessKeyStsToken string
}
@@ -1,34 +0,0 @@
package credentials
// Deprecated: Use AccessKeyCredential in this package instead.
type BaseCredential struct {
AccessKeyId string
AccessKeySecret string
}
type AccessKeyCredential struct {
AccessKeyId string
AccessKeySecret string
}
// Deprecated: Use NewAccessKeyCredential in this package instead.
func NewBaseCredential(accessKeyId, accessKeySecret string) *BaseCredential {
return &BaseCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
}
}
func (baseCred *BaseCredential) ToAccessKeyCredential() *AccessKeyCredential {
return &AccessKeyCredential{
AccessKeyId: baseCred.AccessKeyId,
AccessKeySecret: baseCred.AccessKeySecret,
}
}
func NewAccessKeyCredential(accessKeyId, accessKeySecret string) *AccessKeyCredential {
return &AccessKeyCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
}
}
@@ -1,29 +0,0 @@
package credentials
// Deprecated: Use EcsRamRoleCredential in this package instead.
type StsRoleNameOnEcsCredential struct {
RoleName string
}
// Deprecated: Use NewEcsRamRoleCredential in this package instead.
func NewStsRoleNameOnEcsCredential(roleName string) *StsRoleNameOnEcsCredential {
return &StsRoleNameOnEcsCredential{
RoleName: roleName,
}
}
func (oldCred *StsRoleNameOnEcsCredential) ToEcsRamRoleCredential() *EcsRamRoleCredential {
return &EcsRamRoleCredential{
RoleName: oldCred.RoleName,
}
}
type EcsRamRoleCredential struct {
RoleName string
}
func NewEcsRamRoleCredential(roleName string) *EcsRamRoleCredential {
return &EcsRamRoleCredential{
RoleName: roleName,
}
}
@@ -1,15 +0,0 @@
package credentials
type RsaKeyPairCredential struct {
PrivateKey string
PublicKeyId string
SessionExpiration int
}
func NewRsaKeyPairCredential(privateKey, publicKeyId string, sessionExpiration int) *RsaKeyPairCredential {
return &RsaKeyPairCredential{
PrivateKey: privateKey,
PublicKeyId: publicKeyId,
SessionExpiration: sessionExpiration,
}
}
@@ -1,15 +0,0 @@
package credentials
type StsTokenCredential struct {
AccessKeyId string
AccessKeySecret string
AccessKeyStsToken string
}
func NewStsTokenCredential(accessKeyId, accessKeySecret, accessKeyStsToken string) *StsTokenCredential {
return &StsTokenCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
AccessKeyStsToken: accessKeyStsToken,
}
}
@@ -1,49 +0,0 @@
package credentials
// Deprecated: Use RamRoleArnCredential in this package instead.
type StsRoleArnCredential struct {
AccessKeyId string
AccessKeySecret string
RoleArn string
RoleSessionName string
RoleSessionExpiration int
}
type RamRoleArnCredential struct {
AccessKeyId string
AccessKeySecret string
RoleArn string
RoleSessionName string
RoleSessionExpiration int
}
// Deprecated: Use RamRoleArnCredential in this package instead.
func NewStsRoleArnCredential(accessKeyId, accessKeySecret, roleArn, roleSessionName string, roleSessionExpiration int) *StsRoleArnCredential {
return &StsRoleArnCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
RoleArn: roleArn,
RoleSessionName: roleSessionName,
RoleSessionExpiration: roleSessionExpiration,
}
}
func (oldCred *StsRoleArnCredential) ToRamRoleArnCredential() *RamRoleArnCredential {
return &RamRoleArnCredential{
AccessKeyId: oldCred.AccessKeyId,
AccessKeySecret: oldCred.AccessKeySecret,
RoleArn: oldCred.RoleArn,
RoleSessionName: oldCred.RoleSessionName,
RoleSessionExpiration: oldCred.RoleSessionExpiration,
}
}
func NewRamRoleArnCredential(accessKeyId, accessKeySecret, roleArn, roleSessionName string, roleSessionExpiration int) *RamRoleArnCredential {
return &RamRoleArnCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
RoleArn: roleArn,
RoleSessionName: roleSessionName,
RoleSessionExpiration: roleSessionExpiration,
}
}
@@ -22,41 +22,27 @@ import (
"strings"
)
func signRoaRequest(request requests.AcsRequest, signer Signer, regionId string) (err error) {
func signRoaRequest(request requests.AcsRequest, signer Signer, regionId string) {
completeROASignParams(request, signer, regionId)
stringToSign := buildRoaStringToSign(request)
request.SetStringToSign(stringToSign)
signature := signer.Sign(stringToSign, "")
accessKeyId, err := signer.GetAccessKeyId()
if err != nil {
return nil
}
request.GetHeaders()["Authorization"] = "acs " + accessKeyId + ":" + signature
return
request.GetHeaders()["Authorization"] = "acs " + signer.GetAccessKeyId() + ":" + signature
}
func completeROASignParams(request requests.AcsRequest, signer Signer, regionId string) {
headerParams := request.GetHeaders()
// complete query params
queryParams := request.GetQueryParams()
//if _, ok := queryParams["RegionId"]; !ok {
// queryParams["RegionId"] = regionId
//}
if _, ok := queryParams["RegionId"]; !ok {
queryParams["RegionId"] = regionId
}
if extraParam := signer.GetExtraParam(); extraParam != nil {
for key, value := range extraParam {
if key == "SecurityToken" {
headerParams["x-acs-security-token"] = value
continue
}
queryParams[key] = value
}
}
// complete header params
headerParams := request.GetHeaders()
headerParams["Date"] = utils.GetTimeInFormatRFC2616()
headerParams["x-acs-signature-method"] = signer.GetName()
headerParams["x-acs-signature-version"] = signer.GetVersion()
@@ -108,7 +94,7 @@ func buildRoaStringToSign(request requests.AcsRequest) (stringToSign string) {
}
// append query params
stringToSignBuilder.WriteString(request.BuildQueries())
stringToSignBuilder.WriteString(request.GetQueries())
stringToSign = stringToSignBuilder.String()
return
}
@@ -22,24 +22,14 @@ import (
"strings"
)
func signRpcRequest(request requests.AcsRequest, signer Signer, regionId string) (err error) {
err = completeRpcSignParams(request, signer, regionId)
if err != nil {
return
}
// remove while retry
if _, containsSign := request.GetQueryParams()["Signature"]; containsSign {
delete(request.GetQueryParams(), "Signature")
}
func signRpcRequest(request requests.AcsRequest, signer Signer, regionId string) {
completeRpcSignParams(request, signer, regionId)
stringToSign := buildRpcStringToSign(request)
request.SetStringToSign(stringToSign)
signature := signer.Sign(stringToSign, "&")
request.GetQueryParams()["Signature"] = signature
return
}
func completeRpcSignParams(request requests.AcsRequest, signer Signer, regionId string) (err error) {
func completeRpcSignParams(request requests.AcsRequest, signer Signer, regionId string) {
queryParams := request.GetQueryParams()
queryParams["Version"] = request.GetVersion()
queryParams["Action"] = request.GetActionName()
@@ -49,11 +39,7 @@ func completeRpcSignParams(request requests.AcsRequest, signer Signer, regionId
queryParams["SignatureType"] = signer.GetType()
queryParams["SignatureVersion"] = signer.GetVersion()
queryParams["SignatureNonce"] = utils.GetUUIDV4()
queryParams["AccessKeyId"], err = signer.GetAccessKeyId()
if err != nil {
return
}
queryParams["AccessKeyId"] = signer.GetAccessKeyId()
if _, contains := queryParams["RegionId"]; !contains {
queryParams["RegionId"] = regionId
@@ -67,8 +53,6 @@ func completeRpcSignParams(request requests.AcsRequest, signer Signer, regionId
request.GetHeaders()["Content-Type"] = requests.Form
formString := utils.GetUrlFormedMap(request.GetFormParams())
request.SetContent([]byte(formString))
return
}
func buildRpcStringToSign(request requests.AcsRequest) (stringToSign string) {
+15 -28
View File
@@ -28,7 +28,7 @@ type Signer interface {
GetName() string
GetType() string
GetVersion() string
GetAccessKeyId() (string, error)
GetAccessKeyId() string
GetExtraParam() map[string]string
Sign(stringToSign, secretSuffix string) string
Shutdown()
@@ -36,42 +36,29 @@ type Signer interface {
func NewSignerWithCredential(credential Credential, commonApi func(request *requests.CommonRequest, signer interface{}) (response *responses.CommonResponse, err error)) (signer Signer, err error) {
switch instance := credential.(type) {
case *credentials.AccessKeyCredential:
case *credentials.BaseCredential:
{
signer, err = signers.NewAccessKeySigner(instance)
signer, err = signers.NewSignerV1(instance)
}
case *credentials.StsTokenCredential:
case *credentials.StsCredential:
{
signer, err = signers.NewStsTokenSigner(instance)
signer, err = signers.NewSignerSts(instance)
}
case *credentials.RamRoleArnCredential:
case *credentials.StsAssumeRoleCredential:
{
signer, err = signers.NewRamRoleArnSigner(instance, commonApi)
signer, err = signers.NewSignerStsAssumeRole(instance, commonApi)
}
case *credentials.RsaKeyPairCredential:
case *credentials.KeyPairCredential:
{
signer, err = signers.NewSignerKeyPair(instance, commonApi)
}
case *credentials.EcsRamRoleCredential:
case *credentials.EcsInstanceCredential:
{
signer, err = signers.NewEcsRamRoleSigner(instance, commonApi)
}
case *credentials.BaseCredential: // deprecated user interface
{
signer, err = signers.NewAccessKeySigner(instance.ToAccessKeyCredential())
}
case *credentials.StsRoleArnCredential: // deprecated user interface
{
signer, err = signers.NewRamRoleArnSigner(instance.ToRamRoleArnCredential(), commonApi)
}
case *credentials.StsRoleNameOnEcsCredential: // deprecated user interface
{
signer, err = signers.NewEcsRamRoleSigner(instance.ToEcsRamRoleCredential(), commonApi)
signer, err = signers.NewSignereEcsInstance(instance, commonApi)
}
default:
message := fmt.Sprintf(errors.UnsupportedCredentialErrorMessage, reflect.TypeOf(credential))
err = errors.NewClientError(errors.UnsupportedCredentialErrorCode, message, nil)
message := fmt.Sprintf(errors.UnsupportedCredentialMessage, reflect.TypeOf(credential))
err = errors.NewClientError(errors.UnsupportedCredentialCode, message, nil)
}
return
}
@@ -84,11 +71,11 @@ func Sign(request requests.AcsRequest, signer Signer, regionId string) (err erro
}
case requests.RPC:
{
err = signRpcRequest(request, signer, regionId)
signRpcRequest(request, signer, regionId)
}
default:
message := fmt.Sprintf(errors.UnknownRequestTypeErrorMessage, reflect.TypeOf(request))
err = errors.NewClientError(errors.UnknownRequestTypeErrorCode, message, nil)
message := fmt.Sprintf(errors.UnknownRequestTypeMessage, reflect.TypeOf(request))
err = errors.NewClientError(errors.UnknownRequestTypeCode, message, nil)
}
return
@@ -58,6 +58,6 @@ func Sha256WithRsa(source, secret string) string {
}
signedString := base64.StdEncoding.EncodeToString(signature)
//fmt.Printf("Encoded: %v\n", signedString)
fmt.Printf("Encoded: %v\n", signedString)
return signedString
}
@@ -1,7 +0,0 @@
package signers
type SessionCredential struct {
AccessKeyId string
AccessKeySecret string
StsToken string
}
@@ -26,15 +26,15 @@ import (
"time"
)
type EcsRamRoleSigner struct {
type SignerEcsInstance struct {
*credentialUpdater
sessionCredential *SessionCredential
credential *credentials.EcsRamRoleCredential
sessionCredential *sessionCredential
credential *credentials.EcsInstanceCredential
commonApi func(request *requests.CommonRequest, signer interface{}) (response *responses.CommonResponse, err error)
}
func NewEcsRamRoleSigner(credential *credentials.EcsRamRoleCredential, commonApi func(*requests.CommonRequest, interface{}) (response *responses.CommonResponse, err error)) (signer *EcsRamRoleSigner, err error) {
signer = &EcsRamRoleSigner{
func NewSignereEcsInstance(credential *credentials.EcsInstanceCredential, commonApi func(*requests.CommonRequest, interface{}) (response *responses.CommonResponse, err error)) (signer *SignerEcsInstance, err error) {
signer = &SignerEcsInstance{
credential: credential,
commonApi: commonApi,
}
@@ -49,49 +49,49 @@ func NewEcsRamRoleSigner(credential *credentials.EcsRamRoleCredential, commonApi
return
}
func (*EcsRamRoleSigner) GetName() string {
func (*SignerEcsInstance) GetName() string {
return "HMAC-SHA1"
}
func (*EcsRamRoleSigner) GetType() string {
func (*SignerEcsInstance) GetType() string {
return ""
}
func (*EcsRamRoleSigner) GetVersion() string {
func (*SignerEcsInstance) GetVersion() string {
return "1.0"
}
func (signer *EcsRamRoleSigner) GetAccessKeyId() (accessKeyId string, err error) {
func (signer *SignerEcsInstance) GetAccessKeyId() string {
if signer.sessionCredential == nil || signer.needUpdateCredential() {
err = signer.updateCredential()
signer.updateCredential()
}
if err != nil && (signer.sessionCredential == nil || len(signer.sessionCredential.AccessKeyId) <= 0) {
return "", err
if len(signer.sessionCredential.accessKeyId) <= 0 {
return ""
}
return signer.sessionCredential.AccessKeyId, nil
return signer.sessionCredential.accessKeyId
}
func (signer *EcsRamRoleSigner) GetExtraParam() map[string]string {
func (signer *SignerEcsInstance) GetExtraParam() map[string]string {
if signer.sessionCredential == nil {
return make(map[string]string)
}
if len(signer.sessionCredential.StsToken) <= 0 {
if len(signer.sessionCredential.securityToken) <= 0 {
return make(map[string]string)
}
return map[string]string{"SecurityToken": signer.sessionCredential.StsToken}
return map[string]string{"SecurityToken": signer.sessionCredential.securityToken}
}
func (signer *EcsRamRoleSigner) Sign(stringToSign, secretSuffix string) string {
secret := signer.sessionCredential.AccessKeyId + secretSuffix
func (signer *SignerEcsInstance) Sign(stringToSign, secretSuffix string) string {
secret := signer.sessionCredential.accessKeySecret + secretSuffix
return ShaHmac1(stringToSign, secret)
}
func (signer *EcsRamRoleSigner) buildCommonRequest() (request *requests.CommonRequest, err error) {
func (signer *SignerEcsInstance) buildCommonRequest() (request *requests.CommonRequest, err error) {
request = requests.NewCommonRequest()
return
}
func (signer *EcsRamRoleSigner) refreshApi(request *requests.CommonRequest) (response *responses.CommonResponse, err error) {
func (signer *SignerEcsInstance) refreshApi(request *requests.CommonRequest) (response *responses.CommonResponse, err error) {
requestUrl := "http://100.100.100.200/latest/meta-data/ram/security-credentials/" + signer.credential.RoleName
httpRequest, err := http.NewRequest(requests.GET, requestUrl, strings.NewReader(""))
if err != nil {
@@ -111,7 +111,7 @@ func (signer *EcsRamRoleSigner) refreshApi(request *requests.CommonRequest) (res
return
}
func (signer *EcsRamRoleSigner) refreshCredential(response *responses.CommonResponse) (err error) {
func (signer *SignerEcsInstance) refreshCredential(response *responses.CommonResponse) (err error) {
if response.GetHttpStatus() != http.StatusOK {
fmt.Println("refresh Ecs sts token err, httpStatus: " + string(response.GetHttpStatus()) + ", message = " + response.GetHttpContentString())
return
@@ -152,24 +152,22 @@ func (signer *EcsRamRoleSigner) refreshCredential(response *responses.CommonResp
return
}
if accessKeyId == nil || accessKeySecret == nil || securityToken == nil {
return
if signer.sessionCredential == nil {
panic("refresh Ecs sts token failed, accessKeyId, accessKeySecret or securityToken is null")
}
}
expirationTime, err := time.Parse("2006-01-02T15:04:05Z", expiration.(string))
signer.credentialExpiration = int(expirationTime.Unix() - time.Now().Unix())
signer.sessionCredential = &SessionCredential{
AccessKeyId: accessKeyId.(string),
AccessKeySecret: accessKeySecret.(string),
StsToken: securityToken.(string),
signer.sessionCredential = &sessionCredential{
accessKeyId: accessKeyId.(string),
accessKeySecret: accessKeySecret.(string),
securityToken: securityToken.(string),
}
return
}
func (signer *EcsRamRoleSigner) GetSessionCredential() *SessionCredential {
return signer.sessionCredential
}
func (signer *EcsRamRoleSigner) Shutdown() {
func (signer *SignerEcsInstance) Shutdown() {
}
@@ -28,12 +28,17 @@ import (
type SignerKeyPair struct {
*credentialUpdater
sessionCredential *SessionCredential
credential *credentials.RsaKeyPairCredential
sessionCredential *SessionAkCredential
credential *credentials.KeyPairCredential
commonApi func(request *requests.CommonRequest, signer interface{}) (response *responses.CommonResponse, err error)
}
func NewSignerKeyPair(credential *credentials.RsaKeyPairCredential, commonApi func(*requests.CommonRequest, interface{}) (response *responses.CommonResponse, err error)) (signer *SignerKeyPair, err error) {
type SessionAkCredential struct {
accessKeyId string
accessKeySecret string
}
func NewSignerKeyPair(credential *credentials.KeyPairCredential, commonApi func(*requests.CommonRequest, interface{}) (response *responses.CommonResponse, err error)) (signer *SignerKeyPair, err error) {
signer = &SignerKeyPair{
credential: credential,
commonApi: commonApi,
@@ -50,7 +55,7 @@ func NewSignerKeyPair(credential *credentials.RsaKeyPairCredential, commonApi fu
if credential.SessionExpiration >= 900 && credential.SessionExpiration <= 3600 {
signer.credentialExpiration = credential.SessionExpiration
} else {
err = errors.NewClientError(errors.InvalidParamErrorCode, "Key Pair session duration should be in the range of 15min - 1Hr", nil)
err = errors.NewClientError(errors.InvalidParamCode, "Key Pair session duration should be in the range of 15min - 1Hr", nil)
}
} else {
signer.credentialExpiration = defaultDurationSeconds
@@ -70,28 +75,28 @@ func (*SignerKeyPair) GetVersion() string {
return "1.0"
}
func (signer *SignerKeyPair) GetAccessKeyId() (accessKeyId string, err error) {
func (signer *SignerKeyPair) GetAccessKeyId() string {
if signer.sessionCredential == nil || signer.needUpdateCredential() {
err = signer.updateCredential()
signer.updateCredential()
}
if err != nil && (signer.sessionCredential == nil || len(signer.sessionCredential.AccessKeyId) <= 0) {
return "", err
if signer.sessionCredential == nil || len(signer.sessionCredential.accessKeyId) <= 0 {
return ""
}
return signer.sessionCredential.AccessKeyId, err
return signer.sessionCredential.accessKeyId
}
func (signer *SignerKeyPair) GetExtraParam() map[string]string {
if signer.sessionCredential == nil || signer.needUpdateCredential() {
signer.updateCredential()
}
if signer.sessionCredential == nil || len(signer.sessionCredential.AccessKeyId) <= 0 {
if signer.sessionCredential == nil || len(signer.sessionCredential.accessKeyId) <= 0 {
return make(map[string]string)
}
return make(map[string]string)
}
func (signer *SignerKeyPair) Sign(stringToSign, secretSuffix string) string {
secret := signer.sessionCredential.AccessKeyId + secretSuffix
secret := signer.sessionCredential.accessKeySecret + secretSuffix
return ShaHmac1(stringToSign, secret)
}
@@ -113,8 +118,11 @@ func (signerKeyPair *SignerKeyPair) refreshApi(request *requests.CommonRequest)
func (signer *SignerKeyPair) refreshCredential(response *responses.CommonResponse) (err error) {
if response.GetHttpStatus() != http.StatusOK {
message := "refresh session AccessKey failed"
err = errors.NewServerError(response.GetHttpStatus(), response.GetHttpContentString(), message)
message := "refresh session AccessKey failed, message = " + response.GetHttpContentString()
err = errors.NewServerError(response.GetHttpStatus(), response.GetOriginHttpResponse().Status, message)
if signer.sessionCredential == nil {
panic(err)
}
return
}
var data interface{}
@@ -134,11 +142,13 @@ func (signer *SignerKeyPair) refreshCredential(response *responses.CommonRespons
return
}
if accessKeyId == nil || accessKeySecret == nil {
return
if signer.sessionCredential == nil {
panic("refresh KeyPair, accessKeyId or accessKeySecret is null")
}
}
signer.sessionCredential = &SessionCredential{
AccessKeyId: accessKeyId.(string),
AccessKeySecret: accessKeySecret.(string),
signer.sessionCredential = &SessionAkCredential{
accessKeyId: accessKeyId.(string),
accessKeySecret: accessKeySecret.(string),
}
return
}
@@ -18,41 +18,41 @@ import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
)
type StsTokenSigner struct {
credential *credentials.StsTokenCredential
type SignerSts struct {
credential *credentials.StsCredential
}
func NewStsTokenSigner(credential *credentials.StsTokenCredential) (*StsTokenSigner, error) {
return &StsTokenSigner{
func NewSignerSts(credential *credentials.StsCredential) (*SignerSts, error) {
return &SignerSts{
credential: credential,
}, nil
}
func (*StsTokenSigner) GetName() string {
func (*SignerSts) GetName() string {
return "HMAC-SHA1"
}
func (*StsTokenSigner) GetType() string {
func (*SignerSts) GetType() string {
return ""
}
func (*StsTokenSigner) GetVersion() string {
func (*SignerSts) GetVersion() string {
return "1.0"
}
func (signer *StsTokenSigner) GetAccessKeyId() (accessKeyId string, err error) {
return signer.credential.AccessKeyId, nil
func (signer *SignerSts) GetAccessKeyId() string {
return signer.credential.AccessKeyId
}
func (signer *StsTokenSigner) GetExtraParam() map[string]string {
func (signer *SignerSts) GetExtraParam() map[string]string {
return map[string]string{"SecurityToken": signer.credential.AccessKeyStsToken}
}
func (signer *StsTokenSigner) Sign(stringToSign, secretSuffix string) string {
func (signer *SignerSts) Sign(stringToSign, secretSuffix string) string {
secret := signer.credential.AccessKeySecret + secretSuffix
return ShaHmac1(stringToSign, secret)
}
func (signer *StsTokenSigner) Shutdown() {
func (signer *SignerSts) Shutdown() {
}
@@ -31,16 +31,22 @@ const (
defaultDurationSeconds = 3600
)
type RamRoleArnSigner struct {
type SignerStsAssumeRole struct {
*credentialUpdater
roleSessionName string
sessionCredential *SessionCredential
credential *credentials.RamRoleArnCredential
sessionCredential *sessionCredential
credential *credentials.StsAssumeRoleCredential
commonApi func(request *requests.CommonRequest, signer interface{}) (response *responses.CommonResponse, err error)
}
func NewRamRoleArnSigner(credential *credentials.RamRoleArnCredential, commonApi func(request *requests.CommonRequest, signer interface{}) (response *responses.CommonResponse, err error)) (signer *RamRoleArnSigner, err error) {
signer = &RamRoleArnSigner{
type sessionCredential struct {
accessKeyId string
accessKeySecret string
securityToken string
}
func NewSignerStsAssumeRole(credential *credentials.StsAssumeRoleCredential, commonApi func(request *requests.CommonRequest, signer interface{}) (response *responses.CommonResponse, err error)) (signer *SignerStsAssumeRole, err error) {
signer = &SignerStsAssumeRole{
credential: credential,
commonApi: commonApi,
}
@@ -58,10 +64,10 @@ func NewRamRoleArnSigner(credential *credentials.RamRoleArnCredential, commonApi
signer.roleSessionName = "aliyun-go-sdk-" + strconv.FormatInt(time.Now().UnixNano()/1000, 10)
}
if credential.RoleSessionExpiration > 0 {
if credential.RoleSessionExpiration >= 900 && credential.RoleSessionExpiration <= 3600 {
if credential.RoleSessionExpiration > 900 && credential.RoleSessionExpiration < 3600 {
signer.credentialExpiration = credential.RoleSessionExpiration
} else {
err = errors.NewClientError(errors.InvalidParamErrorCode, "Assume Role session duration should be in the range of 15min - 1Hr", nil)
err = errors.NewClientError(errors.InvalidParamCode, "Assume Role session duration should be in the range of 15min - 1Hr", nil)
}
} else {
signer.credentialExpiration = defaultDurationSeconds
@@ -69,44 +75,44 @@ func NewRamRoleArnSigner(credential *credentials.RamRoleArnCredential, commonApi
return
}
func (*RamRoleArnSigner) GetName() string {
func (*SignerStsAssumeRole) GetName() string {
return "HMAC-SHA1"
}
func (*RamRoleArnSigner) GetType() string {
func (*SignerStsAssumeRole) GetType() string {
return ""
}
func (*RamRoleArnSigner) GetVersion() string {
func (*SignerStsAssumeRole) GetVersion() string {
return "1.0"
}
func (signer *RamRoleArnSigner) GetAccessKeyId() (accessKeyId string, err error) {
if signer.sessionCredential == nil || signer.needUpdateCredential() {
err = signer.updateCredential()
}
if err != nil && (signer.sessionCredential == nil || len(signer.sessionCredential.AccessKeyId) <= 0) {
return "", err
}
return signer.sessionCredential.AccessKeyId, nil
}
func (signer *RamRoleArnSigner) GetExtraParam() map[string]string {
func (signer *SignerStsAssumeRole) GetAccessKeyId() string {
if signer.sessionCredential == nil || signer.needUpdateCredential() {
signer.updateCredential()
}
if signer.sessionCredential == nil || len(signer.sessionCredential.StsToken) <= 0 {
return make(map[string]string)
if signer.sessionCredential == nil || len(signer.sessionCredential.accessKeyId) <= 0 {
return ""
}
return map[string]string{"SecurityToken": signer.sessionCredential.StsToken}
return signer.sessionCredential.accessKeyId
}
func (signer *RamRoleArnSigner) Sign(stringToSign, secretSuffix string) string {
secret := signer.sessionCredential.AccessKeySecret + secretSuffix
func (signer *SignerStsAssumeRole) GetExtraParam() map[string]string {
if signer.sessionCredential == nil || signer.needUpdateCredential() {
signer.updateCredential()
}
if signer.sessionCredential == nil || len(signer.sessionCredential.securityToken) <= 0 {
return make(map[string]string)
}
return map[string]string{"SecurityToken": signer.sessionCredential.securityToken}
}
func (signer *SignerStsAssumeRole) Sign(stringToSign, secretSuffix string) string {
secret := signer.sessionCredential.accessKeySecret + secretSuffix
return ShaHmac1(stringToSign, secret)
}
func (signer *RamRoleArnSigner) buildCommonRequest() (request *requests.CommonRequest, err error) {
func (signer *SignerStsAssumeRole) buildCommonRequest() (request *requests.CommonRequest, err error) {
request = requests.NewCommonRequest()
request.Product = "Sts"
request.Version = "2015-04-01"
@@ -118,19 +124,22 @@ func (signer *RamRoleArnSigner) buildCommonRequest() (request *requests.CommonRe
return
}
func (signer *RamRoleArnSigner) refreshApi(request *requests.CommonRequest) (response *responses.CommonResponse, err error) {
credential := &credentials.AccessKeyCredential{
AccessKeyId: signer.credential.AccessKeyId,
AccessKeySecret: signer.credential.AccessKeySecret,
func (signerStsAssumeRole *SignerStsAssumeRole) refreshApi(request *requests.CommonRequest) (response *responses.CommonResponse, err error) {
credential := &credentials.BaseCredential{
AccessKeyId: signerStsAssumeRole.credential.AccessKeyId,
AccessKeySecret: signerStsAssumeRole.credential.AccessKeySecret,
}
signerV1, err := NewAccessKeySigner(credential)
return signer.commonApi(request, signerV1)
signerV1, err := NewSignerV1(credential)
return signerStsAssumeRole.commonApi(request, signerV1)
}
func (signer *RamRoleArnSigner) refreshCredential(response *responses.CommonResponse) (err error) {
func (signer *SignerStsAssumeRole) refreshCredential(response *responses.CommonResponse) (err error) {
if response.GetHttpStatus() != http.StatusOK {
message := "refresh session token failed"
err = errors.NewServerError(response.GetHttpStatus(), response.GetHttpContentString(), message)
message := "refresh session token failed, message = " + response.GetHttpContentString()
err = errors.NewServerError(response.GetHttpStatus(), response.GetOriginHttpResponse().Status, message)
if signer.sessionCredential == nil {
panic(err)
}
return
}
var data interface{}
@@ -155,20 +164,18 @@ func (signer *RamRoleArnSigner) refreshCredential(response *responses.CommonResp
return
}
if accessKeyId == nil || accessKeySecret == nil || securityToken == nil {
return
if signer.sessionCredential == nil {
panic("refresh session token failed, accessKeyId, accessKeySecret or securityToken is null")
}
}
signer.sessionCredential = &SessionCredential{
AccessKeyId: accessKeyId.(string),
AccessKeySecret: accessKeySecret.(string),
StsToken: securityToken.(string),
signer.sessionCredential = &sessionCredential{
accessKeyId: accessKeyId.(string),
accessKeySecret: accessKeySecret.(string),
securityToken: securityToken.(string),
}
return
}
func (signer *RamRoleArnSigner) GetSessionCredential() *SessionCredential {
return signer.sessionCredential
}
func (signer *RamRoleArnSigner) Shutdown() {
func (signer *SignerStsAssumeRole) Shutdown() {
}
@@ -18,41 +18,41 @@ import (
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
)
type AccessKeySigner struct {
credential *credentials.AccessKeyCredential
type SignerV1 struct {
credential *credentials.BaseCredential
}
func (signer *AccessKeySigner) GetExtraParam() map[string]string {
func (signer *SignerV1) GetExtraParam() map[string]string {
return nil
}
func NewAccessKeySigner(credential *credentials.AccessKeyCredential) (*AccessKeySigner, error) {
return &AccessKeySigner{
func NewSignerV1(credential *credentials.BaseCredential) (*SignerV1, error) {
return &SignerV1{
credential: credential,
}, nil
}
func (*AccessKeySigner) GetName() string {
func (*SignerV1) GetName() string {
return "HMAC-SHA1"
}
func (*AccessKeySigner) GetType() string {
func (*SignerV1) GetType() string {
return ""
}
func (*AccessKeySigner) GetVersion() string {
func (*SignerV1) GetVersion() string {
return "1.0"
}
func (signer *AccessKeySigner) GetAccessKeyId() (accessKeyId string, err error) {
return signer.credential.AccessKeyId, nil
func (signer *SignerV1) GetAccessKeyId() string {
return signer.credential.AccessKeyId
}
func (signer *AccessKeySigner) Sign(stringToSign, secretSuffix string) string {
func (signer *SignerV1) Sign(stringToSign, secretSuffix string) string {
secret := signer.credential.AccessKeySecret + secretSuffix
return ShaHmac1(stringToSign, secret)
}
func (signer *AccessKeySigner) Shutdown() {
func (signer *SignerV1) Shutdown() {
}
@@ -19,14 +19,14 @@ import (
)
type SignerV2 struct {
credential *credentials.RsaKeyPairCredential
credential *credentials.KeyPairCredential
}
func (signer *SignerV2) GetExtraParam() map[string]string {
return nil
}
func NewSignerV2(credential *credentials.RsaKeyPairCredential) (*SignerV2, error) {
func NewSignerV2(credential *credentials.KeyPairCredential) (*SignerV2, error) {
return &SignerV2{
credential: credential,
}, nil
@@ -44,8 +44,8 @@ func (*SignerV2) GetVersion() string {
return "1.0"
}
func (signer *SignerV2) GetAccessKeyId() (accessKeyId string, err error) {
return signer.credential.PublicKeyId, err
func (signer *SignerV2) GetAccessKeyId() string {
return signer.credential.PublicKeyId
}
func (signer *SignerV2) Sign(stringToSign, secretSuffix string) string {
+29 -203
View File
@@ -15,17 +15,13 @@
package sdk
import (
"fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/endpoints"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"net"
"net/http"
"strconv"
"sync"
)
// this value will be replaced while build: -ldflags="-X sdk.version=x.x.x"
@@ -40,8 +36,6 @@ type Client struct {
debug bool
isRunning bool
// void "panic(write to close channel)" cause of addAsync() after Shutdown()
asyncChanLock *sync.RWMutex
}
func (client *Client) Init() (err error) {
@@ -50,7 +44,6 @@ func (client *Client) Init() (err error) {
func (client *Client) InitWithOptions(regionId string, config *Config, credential auth.Credential) (err error) {
client.isRunning = true
client.asyncChanLock = new(sync.RWMutex)
client.regionId = regionId
client.config = config
if err != nil {
@@ -81,10 +74,8 @@ func (client *Client) EnableAsync(routinePoolSize, maxTaskQueueSize int) {
go func() {
for client.isRunning {
select {
case task, notClosed := <-client.asyncTaskQueue:
if notClosed {
task()
}
case task := <-client.asyncTaskQueue:
task()
}
}
}()
@@ -100,19 +91,9 @@ func (client *Client) InitWithAccessKey(regionId, accessKeyId, accessKeySecret s
return client.InitWithOptions(regionId, config, credential)
}
func (client *Client) InitWithStsToken(regionId, accessKeyId, accessKeySecret, securityToken string) (err error) {
func (client *Client) InitWithRoleArn(regionId, accessKeyId, accessKeySecret, roleArn, roleSessionName string) (err error) {
config := client.InitClientConfig()
credential := &credentials.StsTokenCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
AccessKeyStsToken: securityToken,
}
return client.InitWithOptions(regionId, config, credential)
}
func (client *Client) InitWithRamRoleArn(regionId, accessKeyId, accessKeySecret, roleArn, roleSessionName string) (err error) {
config := client.InitClientConfig()
credential := &credentials.RamRoleArnCredential{
credential := &credentials.StsAssumeRoleCredential{
AccessKeyId: accessKeyId,
AccessKeySecret: accessKeySecret,
RoleArn: roleArn,
@@ -121,9 +102,9 @@ func (client *Client) InitWithRamRoleArn(regionId, accessKeyId, accessKeySecret,
return client.InitWithOptions(regionId, config, credential)
}
func (client *Client) InitWithRsaKeyPair(regionId, publicKeyId, privateKey string, sessionExpiration int) (err error) {
func (client *Client) InitWithKeyPair(regionId, publicKeyId, privateKey string, sessionExpiration int) (err error) {
config := client.InitClientConfig()
credential := &credentials.RsaKeyPairCredential{
credential := &credentials.KeyPairCredential{
PrivateKey: privateKey,
PublicKeyId: publicKeyId,
SessionExpiration: sessionExpiration,
@@ -131,70 +112,27 @@ func (client *Client) InitWithRsaKeyPair(regionId, publicKeyId, privateKey strin
return client.InitWithOptions(regionId, config, credential)
}
func (client *Client) InitWithEcsRamRole(regionId, roleName string) (err error) {
func (client *Client) InitWithEcsInstance(regionId, roleName string) (err error) {
config := client.InitClientConfig()
credential := &credentials.EcsRamRoleCredential{
credential := &credentials.EcsInstanceCredential{
RoleName: roleName,
}
return client.InitWithOptions(regionId, config, credential)
}
func (client *Client) InitClientConfig() (config *Config) {
config = NewConfig()
if client.config != nil {
return client.config
} else {
return NewConfig()
config = client.config
}
return
}
func (client *Client) DoAction(request requests.AcsRequest, response responses.AcsResponse) (err error) {
return client.DoActionWithSigner(request, response, nil)
}
func (client *Client) BuildRequestWithSigner(request requests.AcsRequest, signer auth.Signer) (err error) {
// add clientVersion
request.GetHeaders()["x-sdk-core-version"] = Version
regionId := client.regionId
if len(request.GetRegionId()) > 0 {
regionId = request.GetRegionId()
}
// resolve endpoint
resolveParam := &endpoints.ResolveParam{
Domain: request.GetDomain(),
Product: request.GetProduct(),
RegionId: regionId,
LocationProduct: request.GetLocationServiceCode(),
LocationEndpointType: request.GetLocationEndpointType(),
CommonApi: client.ProcessCommonRequest,
}
endpoint, err := endpoints.Resolve(resolveParam)
if err != nil {
return
}
request.SetDomain(endpoint)
// init request params
err = requests.InitParams(request)
if err != nil {
return
}
// signature
var finalSigner auth.Signer
if signer != nil {
finalSigner = signer
} else {
finalSigner = client.signer
}
httpRequest, err := buildHttpRequest(request, finalSigner, regionId)
if client.config.UserAgent != "" {
httpRequest.Header.Set("User-Agent", client.config.UserAgent)
}
return err
}
func (client *Client) DoActionWithSigner(request requests.AcsRequest, response responses.AcsResponse, signer auth.Signer) (err error) {
// add clientVersion
@@ -207,12 +145,12 @@ func (client *Client) DoActionWithSigner(request requests.AcsRequest, response r
// resolve endpoint
resolveParam := &endpoints.ResolveParam{
Domain: request.GetDomain(),
Product: request.GetProduct(),
RegionId: regionId,
LocationProduct: request.GetLocationServiceCode(),
LocationEndpointType: request.GetLocationEndpointType(),
CommonApi: client.ProcessCommonRequest,
Domain: request.GetDomain(),
Product: request.GetProduct(),
RegionId: client.regionId,
LocationProduct: request.GetLocationServiceCode(),
LocationEndpoint: request.GetLocationEndpointType(),
CommonApi: client.ProcessCommonRequest,
}
endpoint, err := endpoints.Resolve(resolveParam)
if err != nil {
@@ -220,9 +158,6 @@ func (client *Client) DoActionWithSigner(request requests.AcsRequest, response r
}
request.SetDomain(endpoint)
if request.GetScheme() == "" {
request.SetScheme(client.config.Scheme)
}
// init request params
err = requests.InitParams(request)
if err != nil {
@@ -230,115 +165,43 @@ func (client *Client) DoActionWithSigner(request requests.AcsRequest, response r
}
// signature
var finalSigner auth.Signer
if signer != nil {
finalSigner = signer
err = auth.Sign(request, signer, regionId)
} else {
finalSigner = client.signer
}
httpRequest, err := buildHttpRequest(request, finalSigner, regionId)
if client.config.UserAgent != "" {
httpRequest.Header.Set("User-Agent", client.config.UserAgent)
err = auth.Sign(request, client.signer, regionId)
}
if err != nil {
return
}
var httpResponse *http.Response
for retryTimes := 0; retryTimes <= client.config.MaxRetryTime; retryTimes++ {
httpResponse, err = client.httpClient.Do(httpRequest)
var timeout bool
// receive error
if err != nil {
if !client.config.AutoRetry {
return
} else if timeout = isTimeout(err); !timeout {
// if not timeout error, return
return
} else if retryTimes >= client.config.MaxRetryTime {
// timeout but reached the max retry times, return
timeoutErrorMsg := fmt.Sprintf(errors.TimeoutErrorMessage, strconv.Itoa(retryTimes+1), strconv.Itoa(retryTimes+1))
err = errors.NewClientError(errors.TimeoutErrorCode, timeoutErrorMsg, err)
return
}
}
// if status code >= 500 or timeout, will trigger retry
if client.config.AutoRetry && (timeout || isServerError(httpResponse)) {
// rewrite signatureNonce and signature
httpRequest, err = buildHttpRequest(request, finalSigner, regionId)
if err != nil {
return
}
continue
}
break
}
err = responses.Unmarshal(response, httpResponse, request.GetAcceptFormat())
// wrap server errors
if serverErr, ok := err.(*errors.ServerError); ok {
var wrapInfo = map[string]string{}
wrapInfo["StringToSign"] = request.GetStringToSign()
err = errors.WrapServerError(serverErr, wrapInfo)
}
return
}
func buildHttpRequest(request requests.AcsRequest, singer auth.Signer, regionId string) (httpRequest *http.Request, err error) {
err = auth.Sign(request, singer, regionId)
if err != nil {
return
}
requestMethod := request.GetMethod()
requestUrl := request.BuildUrl()
requestUrl := request.GetUrl()
body := request.GetBodyReader()
httpRequest, err = http.NewRequest(requestMethod, requestUrl, body)
httpRequest, err := http.NewRequest(requestMethod, requestUrl, body)
if err != nil {
return
}
for key, value := range request.GetHeaders() {
httpRequest.Header[key] = []string{value}
}
// host is a special case
if host, containsHost := request.GetHeaders()["Host"]; containsHost {
httpRequest.Host = host
httpResponse, err := client.httpClient.Do(httpRequest)
if err != nil {
return
}
err = responses.Unmarshal(response, httpResponse, request.GetAcceptFormat())
return
}
func isTimeout(err error) bool {
if err == nil {
return false
}
netErr, isNetError := err.(net.Error)
return isNetError && netErr.Timeout()
}
func isServerError(httpResponse *http.Response) bool {
return httpResponse.StatusCode >= http.StatusInternalServerError
}
/**
only block when any one of the following occurs:
1. the asyncTaskQueue is full, increase the queue size to avoid this
2. Shutdown() in progressing, the client is being closed
**/
func (client *Client) AddAsyncTask(task func()) (err error) {
if client.asyncTaskQueue != nil {
client.asyncChanLock.RLock()
defer client.asyncChanLock.RUnlock()
if client.isRunning {
client.asyncTaskQueue <- task
}
client.asyncTaskQueue <- task
} else {
err = errors.NewClientError(errors.AsyncFunctionNotEnabledCode, errors.AsyncFunctionNotEnabledMessage, nil)
}
return
}
func (client *Client) GetConfig() *Config {
return client.config
}
func NewClient() (client *Client, err error) {
client = &Client{}
err = client.Init()
@@ -357,40 +220,6 @@ func NewClientWithAccessKey(regionId, accessKeyId, accessKeySecret string) (clie
return
}
func NewClientWithStsToken(regionId, stsAccessKeyId, stsAccessKeySecret, stsToken string) (client *Client, err error) {
client = &Client{}
err = client.InitWithStsToken(regionId, stsAccessKeyId, stsAccessKeySecret, stsToken)
return
}
func NewClientWithRamRoleArn(regionId string, accessKeyId, accessKeySecret, roleArn, roleSessionName string) (client *Client, err error) {
client = &Client{}
err = client.InitWithRamRoleArn(regionId, accessKeyId, accessKeySecret, roleArn, roleSessionName)
return
}
func NewClientWithEcsRamRole(regionId string, roleName string) (client *Client, err error) {
client = &Client{}
err = client.InitWithEcsRamRole(regionId, roleName)
return
}
func NewClientWithRsaKeyPair(regionId string, publicKeyId, privateKey string, sessionExpiration int) (client *Client, err error) {
client = &Client{}
err = client.InitWithRsaKeyPair(regionId, publicKeyId, privateKey, sessionExpiration)
return
}
// Deprecated: Use NewClientWithRamRoleArn in this package instead.
func NewClientWithStsRoleArn(regionId string, accessKeyId, accessKeySecret, roleArn, roleSessionName string) (client *Client, err error) {
return NewClientWithRamRoleArn(regionId, accessKeyId, accessKeySecret, roleArn, roleSessionName)
}
// Deprecated: Use NewClientWithEcsRamRole in this package instead.
func NewClientWithStsRoleNameOnEcs(regionId string, roleName string) (client *Client, err error) {
return NewClientWithEcsRamRole(regionId, roleName)
}
func (client *Client) ProcessCommonRequest(request *requests.CommonRequest) (response *responses.CommonResponse, err error) {
request.TransToAcsRequest()
response = responses.NewCommonResponse()
@@ -411,9 +240,6 @@ func (client *Client) ProcessCommonRequestWithSigner(request *requests.CommonReq
func (client *Client) Shutdown() {
client.signer.Shutdown()
// lock the addAsync()
client.asyncChanLock.Lock()
defer client.asyncChanLock.Unlock()
client.isRunning = false
close(client.asyncTaskQueue)
client.isRunning = false
}
+1 -37
View File
@@ -25,12 +25,11 @@ type Config struct {
MaxRetryTime int `default:"3"`
UserAgent string `default:""`
Debug bool `default:"false"`
Timeout time.Duration `default:"10000000000"`
Timeout time.Duration `default:""`
HttpTransport *http.Transport `default:""`
EnableAsync bool `default:"false"`
MaxTaskQueueSize int `default:"1000"`
GoRoutinePoolSize int `default:"5"`
Scheme string `default:"HTTP"`
}
func NewConfig() (config *Config) {
@@ -44,41 +43,6 @@ func (c *Config) WithTimeout(timeout time.Duration) *Config {
return c
}
func (c *Config) WithAutoRetry(isAutoRetry bool) *Config {
c.AutoRetry = isAutoRetry
return c
}
func (c *Config) WithMaxRetryTime(maxRetryTime int) *Config {
c.MaxRetryTime = maxRetryTime
return c
}
func (c *Config) WithUserAgent(userAgent string) *Config {
c.UserAgent = userAgent
return c
}
func (c *Config) WithHttpTransport(httpTransport *http.Transport) *Config {
c.HttpTransport = httpTransport
return c
}
func (c *Config) WithEnableAsync(isEnableAsync bool) *Config {
c.EnableAsync = isEnableAsync
return c
}
func (c *Config) WithMaxTaskQueueSize(maxTaskQueueSize int) *Config {
c.MaxTaskQueueSize = maxTaskQueueSize
return c
}
func (c *Config) WithGoRoutinePoolSize(goRoutinePoolSize int) *Config {
c.GoRoutinePoolSize = goRoutinePoolSize
return c
}
func (c *Config) WithDebug(isDebug bool) *Config {
c.Debug = isDebug
return c
File diff suppressed because it is too large Load Diff
@@ -1,505 +0,0 @@
package endpoints
import (
"encoding/json"
"fmt"
"sync"
)
const endpointsJson = "{" +
" \"products\":[" +
" {" +
" \"code\": \"aegis\"," +
" \"document_id\": \"28449\"," +
" \"location_service_code\": \"vipaegis\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"aegis.cn-hangzhou.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"alidns\"," +
" \"document_id\": \"29739\"," +
" \"location_service_code\": \"alidns\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"alidns.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"arms\"," +
" \"document_id\": \"42924\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": [ {" +
" \"region\": \"ap-southeast-1\"," +
" \"endpoint\": \"arms.ap-southeast-1.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-beijing\"," +
" \"endpoint\": \"arms.cn-beijing.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-hangzhou\"," +
" \"endpoint\": \"arms.cn-hangzhou.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-hongkong\"," +
" \"endpoint\": \"arms.cn-hongkong.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-qingdao\"," +
" \"endpoint\": \"arms.cn-qingdao.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-shanghai\"," +
" \"endpoint\": \"arms.cn-shanghai.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-shenzhen\"," +
" \"endpoint\": \"arms.cn-shenzhen.aliyuncs.com\"" +
" }]," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"arms.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"batchcompute\"," +
" \"document_id\": \"44717\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": [ {" +
" \"region\": \"ap-southeast-1\"," +
" \"endpoint\": \"batchcompute.ap-southeast-1.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-beijing\"," +
" \"endpoint\": \"batchcompute.cn-beijing.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-hangzhou\"," +
" \"endpoint\": \"batchcompute.cn-hangzhou.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-huhehaote\"," +
" \"endpoint\": \"batchcompute.cn-huhehaote.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-qingdao\"," +
" \"endpoint\": \"batchcompute.cn-qingdao.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-shanghai\"," +
" \"endpoint\": \"batchcompute.cn-shanghai.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-shenzhen\"," +
" \"endpoint\": \"batchcompute.cn-shenzhen.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-zhangjiakou\"," +
" \"endpoint\": \"batchcompute.cn-zhangjiakou.aliyuncs.com\"" +
" }, {" +
" \"region\": \"us-west-1\"," +
" \"endpoint\": \"batchcompute.us-west-1.aliyuncs.com\"" +
" }]," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"batchcompute.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"ccc\"," +
" \"document_id\": \"63027\"," +
" \"location_service_code\": \"ccc\"," +
" \"regional_endpoints\": [ {" +
" \"region\": \"cn-hangzhou\"," +
" \"endpoint\": \"ccc.cn-hangzhou.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-shanghai\"," +
" \"endpoint\": \"ccc.cn-shanghai.aliyuncs.com\"" +
" }]," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"ccc.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"cdn\"," +
" \"document_id\": \"27148\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"cdn.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"cds\"," +
" \"document_id\": \"62887\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"cds.cn-beijing.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"chatbot\"," +
" \"document_id\": \"60760\"," +
" \"location_service_code\": \"beebot\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"chatbot.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"cloudapi\"," +
" \"document_id\": \"43590\"," +
" \"location_service_code\": \"apigateway\"," +
" \"regional_endpoints\": [ {" +
" \"region\": \"ap-northeast-1\"," +
" \"endpoint\": \"apigateway.ap-northeast-1.aliyuncs.com\"" +
" }, {" +
" \"region\": \"us-west-1\"," +
" \"endpoint\": \"apigateway.us-west-1.aliyuncs.com\"" +
" }]," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"apigateway.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"cloudauth\"," +
" \"document_id\": \"60687\"," +
" \"location_service_code\": \"cloudauth\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"cloudauth.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"cloudphoto\"," +
" \"document_id\": \"59902\"," +
" \"location_service_code\": \"cloudphoto\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"cloudphoto.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"cloudwf\"," +
" \"document_id\": \"58111\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"cloudwf.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"cms\"," +
" \"document_id\": \"28615\"," +
" \"location_service_code\": \"cms\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"cr\"," +
" \"document_id\": \"60716\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"cr.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"cs\"," +
" \"document_id\": \"26043\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"cs.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"csb\"," +
" \"document_id\": \"64837\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": [ {" +
" \"region\": \"cn-beijing\"," +
" \"endpoint\": \"csb.cn-beijing.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-hangzhou\"," +
" \"endpoint\": \"csb.cn-hangzhou.aliyuncs.com\"" +
" }]," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"csb.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"dds\"," +
" \"document_id\": \"61715\"," +
" \"location_service_code\": \"dds\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"mongodb.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"mongodb.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"dm\"," +
" \"document_id\": \"29434\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": [ {" +
" \"region\": \"ap-southeast-1\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }, {" +
" \"region\": \"ap-southeast-2\"," +
" \"endpoint\": \"dm.ap-southeast-2.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-beijing\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-hangzhou\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-hongkong\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-qingdao\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-shanghai\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }, {" +
" \"region\": \"cn-shenzhen\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }, {" +
" \"region\": \"us-east-1\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }, {" +
" \"region\": \"us-west-1\"," +
" \"endpoint\": \"dm.aliyuncs.com\"" +
" }]," +
" \"global_endpoint\": \"dm.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"dm.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"domain\"," +
" \"document_id\": \"42875\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"domain.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"domain.aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"domain-intl\"," +
" \"document_id\": \"\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"domain-intl.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"domain-intl.aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"drds\"," +
" \"document_id\": \"51111\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"drds.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"drds.aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"ecs\"," +
" \"document_id\": \"25484\"," +
" \"location_service_code\": \"ecs\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"emr\"," +
" \"document_id\": \"28140\"," +
" \"location_service_code\": \"emr\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"emr.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"ess\"," +
" \"document_id\": \"25925\"," +
" \"location_service_code\": \"ess\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"ess.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"green\"," +
" \"document_id\": \"28427\"," +
" \"location_service_code\": \"green\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"green.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"hpc\"," +
" \"document_id\": \"35201\"," +
" \"location_service_code\": \"hpc\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"hpc.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"httpdns\"," +
" \"document_id\": \"52679\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"httpdns-api.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"iot\"," +
" \"document_id\": \"30557\"," +
" \"location_service_code\": \"iot\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"iot.[RegionId].aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"itaas\"," +
" \"document_id\": \"55759\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"itaas.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"jaq\"," +
" \"document_id\": \"35037\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"jaq.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"live\"," +
" \"document_id\": \"48207\"," +
" \"location_service_code\": \"live\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"live.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"mts\"," +
" \"document_id\": \"29212\"," +
" \"location_service_code\": \"mts\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"nas\"," +
" \"document_id\": \"62598\"," +
" \"location_service_code\": \"nas\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"ons\"," +
" \"document_id\": \"44416\"," +
" \"location_service_code\": \"ons\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"polardb\"," +
" \"document_id\": \"58764\"," +
" \"location_service_code\": \"polardb\"," +
" \"regional_endpoints\": [ {" +
" \"region\": \"ap-south-1\"," +
" \"endpoint\": \"polardb.ap-south-1.aliyuncs.com\"" +
" }, {" +
" \"region\": \"ap-southeast-5\"," +
" \"endpoint\": \"polardb.ap-southeast-5.aliyuncs.com\"" +
" }]," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"polardb.aliyuncs.com\"" +
" }," +
" {" +
" \"code\": \"push\"," +
" \"document_id\": \"30074\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"cloudpush.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"qualitycheck\"," +
" \"document_id\": \"50807\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": [ {" +
" \"region\": \"cn-hangzhou\"," +
" \"endpoint\": \"qualitycheck.cn-hangzhou.aliyuncs.com\"" +
" }]," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"r-kvstore\"," +
" \"document_id\": \"60831\"," +
" \"location_service_code\": \"redisa\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"ram\"," +
" \"document_id\": \"28672\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"ram.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"rds\"," +
" \"document_id\": \"26223\"," +
" \"location_service_code\": \"rds\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"ros\"," +
" \"document_id\": \"28899\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"ros.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"sas-api\"," +
" \"document_id\": \"28498\"," +
" \"location_service_code\": \"sas\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"slb\"," +
" \"document_id\": \"27565\"," +
" \"location_service_code\": \"slb\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"sts\"," +
" \"document_id\": \"28756\"," +
" \"location_service_code\": \"\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"sts.aliyuncs.com\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"vod\"," +
" \"document_id\": \"60574\"," +
" \"location_service_code\": \"vod\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"vpc\"," +
" \"document_id\": \"34962\"," +
" \"location_service_code\": \"vpc\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }," +
" {" +
" \"code\": \"waf\"," +
" \"document_id\": \"62847\"," +
" \"location_service_code\": \"waf\"," +
" \"regional_endpoints\": []," +
" \"global_endpoint\": \"\"," +
" \"regional_endpoint_pattern\": \"\"" +
" }]" +
"}"
var initOnce sync.Once
var data interface{}
func getEndpointConfigData() interface{} {
initOnce.Do(func() {
err := json.Unmarshal([]byte(endpointsJson), &data)
if err != nil {
fmt.Println("init endpoint config data failed.", err)
}
})
return data
}
@@ -1,37 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package endpoints
import (
"fmt"
"github.com/jmespath/go-jmespath"
"strings"
)
type LocalGlobalResolver struct {
}
func (resolver *LocalGlobalResolver) TryResolve(param *ResolveParam) (endpoint string, support bool, err error) {
// get the global endpoints configs
endpointExpression := fmt.Sprintf("products[?code=='%s'].global_endpoint", strings.ToLower(param.Product))
endpointData, err := jmespath.Search(endpointExpression, getEndpointConfigData())
if err == nil && endpointData != nil && len(endpointData.([]interface{})) > 0 {
endpoint = endpointData.([]interface{})[0].(string)
support = len(endpoint) > 0
return endpoint, support, nil
}
support = false
return
}
@@ -1,41 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package endpoints
import (
"fmt"
"github.com/jmespath/go-jmespath"
"strings"
)
type LocalRegionalResolver struct {
}
func (resolver *LocalRegionalResolver) TryResolve(param *ResolveParam) (endpoint string, support bool, err error) {
// get the regional endpoints configs
regionalExpression := fmt.Sprintf("products[?code=='%s'].regional_endpoints", strings.ToLower(param.Product))
regionalData, err := jmespath.Search(regionalExpression, getEndpointConfigData())
if err == nil && regionalData != nil && len(regionalData.([]interface{})) > 0 {
endpointExpression := fmt.Sprintf("[0][?region=='%s'].endpoint", strings.ToLower(param.RegionId))
endpointData, err := jmespath.Search(endpointExpression, regionalData)
if err == nil && endpointData != nil && len(endpointData.([]interface{})) > 0 {
endpoint = endpointData.([]interface{})[0].(string)
support = len(endpoint) > 0
return endpoint, support, nil
}
}
support = false
return
}
@@ -0,0 +1,110 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package endpoints
import (
"encoding/xml"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"sync"
)
var readXmlOnce sync.Once
var v = Endpoints{}
type LocalXmlResolver struct {
}
func (resolver *LocalXmlResolver) TryResolve(param *ResolveParam) (endpoint string, support bool, err error) {
readXmlOnce.Do(func() {
_, file, _, _ := runtime.Caller(0)
filename := filepath.Join(file, "../endpoints.xml")
data, err := ioutil.ReadFile(filename)
if err != nil {
support = false
return
}
err = xml.Unmarshal(data, &v)
if err != nil {
support = false
return
}
})
for _, xmlEndpoint := range v.EndpointList {
for _, xmlRegionId := range xmlEndpoint.RegionIds.Id {
if xmlRegionId == param.RegionId {
for _, xmlProduct := range xmlEndpoint.Products.ProductList {
if xmlProduct.ProductName == param.Product {
endpoint = xmlProduct.DomainName
support = true
return
}
}
}
}
}
support = false
return
}
func GetCurrentPath() string {
s, err := exec.LookPath(os.Args[0])
if err != nil {
fmt.Println(err.Error())
}
s = strings.Replace(s, "\\", "/", -1)
s = strings.Replace(s, "\\\\", "/", -1)
i := strings.LastIndex(s, "/")
path := string(s[0 : i+1])
return path
}
type Endpoints struct {
XMLName xml.Name `xml:"Endpoints"`
EndpointList []Endpoint `xml:"Endpoint"`
}
type Endpoint struct {
XMLName xml.Name `xml:"Endpoint"`
Name string `xml:"name,attr"`
RegionIds RegionIds `xml:"RegionIds"`
Products Products `xml:"Products"`
}
type RegionIds struct {
Id []string `xml:"RegionId"`
}
type Products struct {
ProductList []Product `xml:"Product"`
}
type RegionId struct {
XMLName string `xml:"RegionId"`
}
type Product struct {
ProductName string `xml:"ProductName"`
DomainName string `xml:"DomainName"`
}
@@ -16,7 +16,6 @@ package endpoints
import (
"encoding/json"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"sync"
"time"
)
@@ -24,15 +23,8 @@ const (
EndpointCacheExpireTime = 3600 //Seconds
)
var lastClearTimePerProduct = struct {
sync.RWMutex
cache map[string]int64
}{cache: make(map[string]int64)}
var endpointCache = struct {
sync.RWMutex
cache map[string]string
}{cache: make(map[string]string)}
var lastClearTimePerProduct map[string]int64 = make(map[string]int64)
var endpointCache map[string]string = make(map[string]string)
type LocationResolver struct {
}
@@ -45,31 +37,30 @@ func (resolver *LocationResolver) TryResolve(param *ResolveParam) (endpoint stri
//get from cache
cacheKey := param.Product + "#" + param.RegionId
if endpointCache.cache != nil && len(endpointCache.cache[cacheKey]) > 0 && !CheckCacheIsExpire(cacheKey) {
endpoint = endpointCache.cache[cacheKey]
if endpointCache != nil && len(endpointCache[cacheKey]) > 0 && !CheckCacheIsExpire(cacheKey) {
endpoint = endpointCache[cacheKey]
support = true
return
}
//get from remote
getEndpointRequest := requests.NewCommonRequest()
getEndpointRequest.Product = "Location"
getEndpointRequest.Version = "2015-06-12"
getEndpointRequest.ApiName = "DescribeEndpoints"
getEndpointRequest.Domain = "location.aliyuncs.com"
getEndpointRequest.Method = "GET"
getEndpointRequest.Scheme = requests.HTTPS
getEndpointRequest.QueryParams["Id"] = param.RegionId
getEndpointRequest.QueryParams["ServiceCode"] = param.LocationProduct
if len(param.LocationEndpointType) > 0 {
getEndpointRequest.QueryParams["Type"] = param.LocationEndpointType
if len(param.LocationEndpoint) > 0 {
getEndpointRequest.QueryParams["Type"] = param.LocationEndpoint
} else {
getEndpointRequest.QueryParams["Type"] = "openAPI"
}
response, err := param.CommonApi(getEndpointRequest)
//{"Endpoints":{"Endpoint":[{"Protocols":{"Protocols":["HTTP","HTTPS"]},"Type":"openAPI","Namespace":"26842","Id":"cn-hangzhou","SerivceCode":"apigateway","Endpoint":"apigateway.cn-hangzhou.aliyuncs.com"}]},"RequestId":"3287538B-19A0-4550-9995-143C5EDBD955","Success":true}
var getEndpointResponse GetEndpointResponse
if !response.IsSuccess() {
support = false
@@ -87,12 +78,8 @@ func (resolver *LocationResolver) TryResolve(param *ResolveParam) (endpoint stri
}
if len(getEndpointResponse.Endpoints.Endpoint[0].Endpoint) > 0 {
endpoint = getEndpointResponse.Endpoints.Endpoint[0].Endpoint
endpointCache.Lock()
endpointCache.cache[cacheKey] = endpoint
endpointCache.Unlock()
lastClearTimePerProduct.Lock()
lastClearTimePerProduct.cache[cacheKey] = time.Now().Unix()
lastClearTimePerProduct.Unlock()
endpointCache[cacheKey] = endpoint
lastClearTimePerProduct[cacheKey] = time.Now().Unix()
support = true
return
}
@@ -102,12 +89,10 @@ func (resolver *LocationResolver) TryResolve(param *ResolveParam) (endpoint stri
}
func CheckCacheIsExpire(cacheKey string) bool {
lastClearTime := lastClearTimePerProduct.cache[cacheKey]
lastClearTime := lastClearTimePerProduct[cacheKey]
if lastClearTime <= 0 {
lastClearTime = time.Now().Unix()
lastClearTimePerProduct.Lock()
lastClearTimePerProduct.cache[cacheKey] = lastClearTime
lastClearTimePerProduct.Unlock()
lastClearTimePerProduct[cacheKey] = lastClearTime
}
now := time.Now().Unix()
@@ -1,39 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package endpoints
import (
"fmt"
"strings"
)
const keyFormatter = "%s::%s"
var endpointMapping = make(map[string]string)
func AddEndpointMapping(regionId, productId, endpoint string) (err error) {
key := fmt.Sprintf(keyFormatter, strings.ToLower(regionId), strings.ToLower(productId))
endpointMapping[key] = endpoint
return nil
}
type MappingResolver struct {
}
func (resolver *MappingResolver) TryResolve(param *ResolveParam) (endpoint string, support bool, err error) {
key := fmt.Sprintf(keyFormatter, strings.ToLower(param.RegionId), strings.ToLower(param.Product))
endpoint, contains := endpointMapping[key]
return endpoint, contains, nil
}
+9 -11
View File
@@ -44,8 +44,8 @@ func Resolve(param *ResolveParam) (endpoint string, err error) {
}
// not support
errorMsg := fmt.Sprintf(errors.CanNotResolveEndpointErrorMessage, param, ResolveEndpointUserGuideLink)
err = errors.NewClientError(errors.CanNotResolveEndpointErrorCode, errorMsg, nil)
errorMsg := fmt.Sprintf(errors.CanNotResolveEndpointMessage, param, ResolveEndpointUserGuideLink)
err = errors.NewClientError(errors.CanNotResolveEndpointCode, errorMsg, nil)
return
}
@@ -53,22 +53,20 @@ func getAllResolvers() []Resolver {
once.Do(func() {
resolvers = []Resolver{
&SimpleHostResolver{},
&MappingResolver{},
&LocationResolver{},
&LocalRegionalResolver{},
&LocalGlobalResolver{},
&LocalXmlResolver{},
}
})
return resolvers
}
type ResolveParam struct {
Domain string
Product string
RegionId string
LocationProduct string
LocationEndpointType string
CommonApi func(request *requests.CommonRequest) (response *responses.CommonResponse, err error) `json:"-"`
Domain string
Product string
RegionId string
LocationProduct string
LocationEndpoint string
CommonApi func(request *requests.CommonRequest) (response *responses.CommonResponse, err error) `json:"-"`
}
func (param *ResolveParam) String() string {
+13 -25
View File
@@ -14,35 +14,27 @@
package errors
import "fmt"
const (
DefaultClientErrorStatus = 400
DefaultClientErrorCode = "SDK.ClientError"
UnsupportedCredentialErrorCode = "SDK.UnsupportedCredential"
UnsupportedCredentialErrorMessage = "Specified credential (type = %s) is not supported, please check"
UnsupportedCredentialCode = "SDK.UnsupportedCredential"
UnsupportedCredentialMessage = "Specified credential (type = %s) is not supported, please check"
CanNotResolveEndpointErrorCode = "SDK.CanNotResolveEndpoint"
CanNotResolveEndpointErrorMessage = "Can not resolve endpoint(param = %s), please check your accessKey with secret, and read the user guide\n %s"
CanNotResolveEndpointCode = "SDK.CanNotResolveEndpoint"
CanNotResolveEndpointMessage = "Can not resolve endpoint(param = %s), please check the user guide\n %s"
UnsupportedParamPositionErrorCode = "SDK.UnsupportedParamPosition"
UnsupportedParamPositionErrorMessage = "Specified param position (%s) is not supported, please upgrade sdk and retry"
UnsupportedParamPositionCode = "SDK.UnsupportedParamPosition"
UnsupportedParamPositionMessage = "Specified param position (%s) is not supported, please upgrade sdk and retry"
AsyncFunctionNotEnabledCode = "SDK.AsyncFunctionNotEnabled"
AsyncFunctionNotEnabledMessage = "Async function is not enabled in client, please invoke 'client.EnableAsync' function"
UnknownRequestTypeErrorCode = "SDK.UnknownRequestType"
UnknownRequestTypeErrorMessage = "Unknown Request Type: %s"
UnknownRequestTypeCode = "SDK.UnknownRequestType"
UnknownRequestTypeMessage = "Unknown Request Type: %s"
MissingParamErrorCode = "SDK.MissingParam"
InvalidParamErrorCode = "SDK.InvalidParam"
JsonUnmarshalErrorCode = "SDK.JsonUnmarshalError"
JsonUnmarshalErrorMessage = "Failed to unmarshal response, but you can get the data via response.GetHttpStatusCode() and response.GetHttpContentString()"
TimeoutErrorCode = "SDK.TimeoutError"
TimeoutErrorMessage = "The request timed out %s times(%s for retry), perhaps we should have the threshold raised a little?"
MissingParamCode = "SDK.MissingParam"
InvalidParamCode = "SDK.InvalidParam"
)
type ClientError struct {
@@ -60,11 +52,11 @@ func NewClientError(errorCode, message string, originErr error) Error {
}
func (err *ClientError) Error() string {
clientErrMsg := fmt.Sprintf("[%s] %s", err.errorCode, err.message)
if err.originError != nil {
return clientErrMsg + "\ncaused by:\n" + err.originError.Error()
return err.originError.Error()
} else {
return ""
}
return clientErrMsg
}
func (err *ClientError) OriginError() error {
@@ -86,7 +78,3 @@ func (err *ClientError) ErrorCode() string {
func (err *ClientError) Message() string {
return err.message
}
func (err *ClientError) String() string {
return err.Error()
}
+8 -81
View File
@@ -14,79 +14,18 @@
package errors
import (
"encoding/json"
"fmt"
"github.com/jmespath/go-jmespath"
)
var wrapperList = []ServerErrorWrapper{
&SignatureDostNotMatchWrapper{},
}
type ServerError struct {
httpStatus int
requestId string
hostId string
errorCode string
recommend string
message string
comment string
}
type ServerErrorWrapper interface {
tryWrap(error *ServerError, wrapInfo map[string]string) (bool, *ServerError)
}
func (err *ServerError) Error() string {
return fmt.Sprintf("SDK.ServerError\nErrorCode: %s\nRecommend: %s\nRequestId: %s\nMessage: %s",
err.errorCode, err.comment+err.recommend, err.requestId, err.message)
}
func NewServerError(httpStatus int, responseContent, comment string) Error {
result := &ServerError{
func NewServerError(httpStatus int, errorCode, message string) Error {
return &ServerError{
httpStatus: httpStatus,
message: responseContent,
comment: comment,
errorCode: errorCode,
message: message,
}
var data interface{}
err := json.Unmarshal([]byte(responseContent), &data)
if err == nil {
requestId, _ := jmespath.Search("RequestId", data)
hostId, _ := jmespath.Search("HostId", data)
errorCode, _ := jmespath.Search("Code", data)
recommend, _ := jmespath.Search("Recommend", data)
message, _ := jmespath.Search("Message", data)
if requestId != nil {
result.requestId = requestId.(string)
}
if hostId != nil {
result.hostId = hostId.(string)
}
if errorCode != nil {
result.errorCode = errorCode.(string)
}
if recommend != nil {
result.recommend = recommend.(string)
}
if message != nil {
result.message = message.(string)
}
}
return result
}
func WrapServerError(originError *ServerError, wrapInfo map[string]string) *ServerError {
for _, wrapper := range wrapperList {
ok, newError := wrapper.tryWrap(originError, wrapInfo)
if ok {
return newError
}
}
return originError
}
func (err *ServerError) HttpStatus() int {
@@ -101,22 +40,10 @@ func (err *ServerError) Message() string {
return err.message
}
func (err *ServerError) Error() string {
return "SDK.ServerError"
}
func (err *ServerError) OriginError() error {
return nil
}
func (err *ServerError) HostId() string {
return err.hostId
}
func (err *ServerError) RequestId() string {
return err.requestId
}
func (err *ServerError) Recommend() string {
return err.recommend
}
func (err *ServerError) Comment() string {
return err.comment
}
@@ -1,29 +0,0 @@
package errors
import "strings"
const SignatureDostNotMatchErrorCode = "SignatureDoesNotMatch"
const MessagePrefix = "Specified signature is not matched with our calculation. server string to sign is:"
type SignatureDostNotMatchWrapper struct {
}
func (*SignatureDostNotMatchWrapper) tryWrap(error *ServerError, wrapInfo map[string]string) (bool, *ServerError) {
clientStringToSign := wrapInfo["StringToSign"]
if error.errorCode == SignatureDostNotMatchErrorCode && clientStringToSign != "" {
message := error.message
if strings.HasPrefix(message, MessagePrefix) {
serverStringToSign := message[len(MessagePrefix):]
if clientStringToSign == serverStringToSign {
// user secret is error
error.recommend = "Please check you AccessKeySecret"
} else {
error.recommend = "This may be a bug with the SDK and we hope you can submit this question in the " +
"github issue(https://github.com/aliyun/alibaba-cloud-sdk-go/issues), thanks very much"
}
}
return true, error
} else {
return false, nil
}
}
+6 -28
View File
@@ -59,7 +59,6 @@ type AcsRequest interface {
GetPort() string
GetRegionId() string
GetUrl() string
GetQueries() string
GetHeaders() map[string]string
GetQueryParams() map[string]string
GetFormParams() map[string]string
@@ -73,15 +72,10 @@ type AcsRequest interface {
GetLocationServiceCode() string
GetLocationEndpointType() string
SetStringToSign(stringToSign string)
GetStringToSign() string
SetDomain(domain string)
SetContent(content []byte)
SetScheme(scheme string)
BuildUrl() string
BuildQueries() string
GetQueries() string
addHeaderParam(key, value string)
addQueryParam(key, value string)
addFormParam(key, value string)
@@ -96,9 +90,8 @@ type baseRequest struct {
Port string
RegionId string
product string
version string
product string
version string
actionName string
AcceptFormat string
@@ -112,8 +105,6 @@ type baseRequest struct {
locationEndpointType string
queries string
stringToSign string
}
func (request *baseRequest) GetQueryParams() map[string]string {
@@ -172,10 +163,6 @@ func (request *baseRequest) GetScheme() string {
return request.Scheme
}
func (request *baseRequest) SetScheme(scheme string) {
request.Scheme = scheme
}
func (request *baseRequest) GetMethod() string {
return request.Method
}
@@ -209,24 +196,15 @@ func (request *baseRequest) GetContentType() (contentType string, contains bool)
return
}
func (request *baseRequest) SetStringToSign(stringToSign string) {
request.stringToSign = stringToSign
}
func (request *baseRequest) GetStringToSign() string {
return request.stringToSign
}
func defaultBaseRequest() (request *baseRequest) {
request = &baseRequest{
Scheme: "",
Scheme: HTTP,
AcceptFormat: "JSON",
Method: GET,
QueryParams: make(map[string]string),
Headers: map[string]string{
"x-sdk-client": "golang/1.0.0",
"x-sdk-invoke-type": "normal",
"Accept-Encoding": "identity",
},
FormParams: make(map[string]string),
}
@@ -301,8 +279,8 @@ func addParam(request AcsRequest, position, name, value string) (err error) {
case Body:
request.addFormParam(name, value)
default:
errMsg := fmt.Sprintf(errors.UnsupportedParamPositionErrorMessage, position)
err = errors.NewClientError(errors.UnsupportedParamPositionErrorCode, errMsg, nil)
errMsg := fmt.Sprintf(errors.UnsupportedParamPositionMessage, position)
err = errors.NewClientError(errors.UnsupportedParamPositionCode, errMsg, nil)
}
}
return
@@ -1,8 +1,6 @@
package requests
import (
"bytes"
"fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
"io"
"strings"
@@ -31,49 +29,15 @@ func NewCommonRequest() (request *CommonRequest) {
return
}
func (request *CommonRequest) String() string {
request.TransToAcsRequest()
request.BuildQueries()
request.BuildUrl()
resultBuilder := bytes.Buffer{}
mapOutput := func(m map[string]string) {
if len(m) > 0 {
for key, value := range m {
resultBuilder.WriteString(key + ": " + value + "\n")
}
}
}
// Request Line
resultBuilder.WriteString("\n")
resultBuilder.WriteString(fmt.Sprintf("%s %s %s/1.1\n", request.Method, request.GetQueries(), strings.ToUpper(request.Scheme)))
// Headers
resultBuilder.WriteString("Host" + ": " + request.Domain + "\n")
mapOutput(request.Headers)
resultBuilder.WriteString("\n")
// Body
if len(request.Content) > 0 {
resultBuilder.WriteString(string(request.Content) + "\n")
} else {
mapOutput(request.FormParams)
}
return resultBuilder.String()
}
func (request *CommonRequest) TransToAcsRequest() {
if len(request.Version) == 0 {
errors.NewClientError(errors.MissingParamErrorCode, "Common request [version] is required", nil)
errors.NewClientError(errors.MissingParamCode, "Common request [version] is required", nil)
}
if len(request.ApiName) == 0 && len(request.PathPattern) == 0 {
errors.NewClientError(errors.MissingParamErrorCode, "At least one of [ApiName] and [PathPattern] should has a value", nil)
errors.NewClientError(errors.MissingParamCode, "At least one of [ApiName] and [PathPattern] should has a value", nil)
}
if len(request.Domain) == 0 && len(request.Product) == 0 {
errors.NewClientError(errors.MissingParamErrorCode, "At least one of [Domain] and [Product] should has a value", nil)
errors.NewClientError(errors.MissingParamCode, "At least one of [Domain] and [Product] should has a value", nil)
}
if len(request.PathPattern) > 0 {
@@ -91,18 +55,6 @@ func (request *CommonRequest) TransToAcsRequest() {
}
func (request *CommonRequest) BuildUrl() string {
if len(request.Port) > 0 {
return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.BuildQueries()
}
return strings.ToLower(request.Scheme) + "://" + request.Domain + request.BuildQueries()
}
func (request *CommonRequest) BuildQueries() string {
return request.Ontology.BuildQueries()
}
func (request *CommonRequest) GetUrl() string {
if len(request.Port) > 0 {
return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.GetQueries()
@@ -111,10 +63,6 @@ func (request *CommonRequest) GetUrl() string {
return strings.ToLower(request.Scheme) + "://" + request.Domain + request.GetQueries()
}
func (request *CommonRequest) GetQueries() string {
return request.Ontology.GetQueries()
}
func (request *CommonRequest) GetBodyReader() io.Reader {
return request.Ontology.GetBodyReader()
}
@@ -123,6 +71,10 @@ func (request *CommonRequest) GetStyle() string {
return request.Ontology.GetStyle()
}
func (request *CommonRequest) GetQueries() string {
return request.Ontology.GetQueries()
}
func (request *CommonRequest) addPathParam(key, value string) {
request.PathParams[key] = value
}
+7 -31
View File
@@ -18,7 +18,6 @@ import (
"bytes"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
"io"
"net/url"
"sort"
"strings"
)
@@ -45,15 +44,13 @@ func (request *RoaRequest) GetBodyReader() io.Reader {
}
func (request *RoaRequest) GetQueries() string {
if len(request.queries) == 0 {
request.buildQueries()
}
return request.queries
}
// for sign method, need not url encoded
func (request *RoaRequest) BuildQueries() string {
return request.buildQueries(false)
}
func (request *RoaRequest) buildQueries(needParamEncode bool) string {
func (request *RoaRequest) buildQueries() {
// replace path params with value
path := request.pathPattern
for key, value := range request.PathParams {
@@ -77,46 +74,25 @@ func (request *RoaRequest) buildQueries(needParamEncode bool) string {
// append urlBuilder
urlBuilder := bytes.Buffer{}
urlBuilder.WriteString(path)
if len(queryKeys) > 0 {
urlBuilder.WriteString("?")
}
urlBuilder.WriteString("?")
for i := 0; i < len(queryKeys); i++ {
queryKey := queryKeys[i]
urlBuilder.WriteString(queryKey)
if value := queryParams[queryKey]; len(value) > 0 {
urlBuilder.WriteString("=")
if needParamEncode {
urlBuilder.WriteString(url.QueryEscape(value))
} else {
urlBuilder.WriteString(value)
}
urlBuilder.WriteString(value)
}
if i < len(queryKeys)-1 {
urlBuilder.WriteString("&")
}
}
result := urlBuilder.String()
result = popStandardUrlencode(result)
request.queries = result
return request.queries
}
func popStandardUrlencode(stringToSign string) (result string) {
result = strings.Replace(stringToSign, "+", "%20", -1)
result = strings.Replace(result, "*", "%2A", -1)
result = strings.Replace(result, "%7E", "~", -1)
return
request.queries = urlBuilder.String()
}
func (request *RoaRequest) GetUrl() string {
return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.GetQueries()
}
func (request *RoaRequest) BuildUrl() string {
// for network trans, need url encoded
return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.buildQueries(true)
}
func (request *RoaRequest) addPathParam(key, value string) {
request.PathParams[key] = value
}
+4 -9
View File
@@ -42,20 +42,15 @@ func (request *RpcRequest) GetBodyReader() io.Reader {
}
}
func (request *RpcRequest) BuildQueries() string {
request.queries = "/?" + utils.GetUrlFormedMap(request.QueryParams)
return request.queries
}
func (request *RpcRequest) GetQueries() string {
if request.queries == "" {
request.queries = "/?" + utils.GetUrlFormedMap(request.QueryParams)
}
return request.queries
}
func (request *RpcRequest) BuildUrl() string {
return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.BuildQueries()
}
func (request *RpcRequest) GetUrl() string {
//return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.GetQueries()
return strings.ToLower(request.Scheme) + "://" + request.Domain + request.GetQueries()
}
+8 -16
View File
@@ -4,37 +4,29 @@ import "strconv"
type Integer string
func NewInteger(integer int) Integer {
return Integer(strconv.Itoa(integer))
func NewInteger(n int) Integer {
return Integer(strconv.Itoa(n))
}
func (integer Integer) HasValue() bool {
func (integer Integer) hasValue() bool {
return integer != ""
}
func (integer Integer) GetValue() (int, error) {
func (integer Integer) getValue() (int, error) {
return strconv.Atoi(string(integer))
}
func NewInteger64(integer int64) Integer {
return Integer(strconv.FormatInt(integer, 10))
}
func (integer Integer) GetValue64() (int64, error) {
return strconv.ParseInt(string(integer), 10, 0)
}
type Boolean string
func NewBoolean(bool bool) Boolean {
return Boolean(strconv.FormatBool(bool))
}
func (boolean Boolean) HasValue() bool {
func (boolean Boolean) hasValue() bool {
return boolean != ""
}
func (boolean Boolean) GetValue() (bool, error) {
func (boolean Boolean) getValue() (bool, error) {
return strconv.ParseBool(string(boolean))
}
@@ -44,10 +36,10 @@ func NewFloat(f float64) Float {
return Float(strconv.FormatFloat(f, 'f', 6, 64))
}
func (float Float) HasValue() bool {
func (float Float) hasValue() bool {
return float != ""
}
func (float Float) GetValue() (float64, error) {
func (float Float) getValue() (float64, error) {
return strconv.ParseFloat(string(float), 64)
}
@@ -1,341 +0,0 @@
package responses
import (
"encoding/json"
"github.com/json-iterator/go"
"io"
"math"
"strconv"
"strings"
"sync"
"unsafe"
)
const maxUint = ^uint(0)
const maxInt = int(maxUint >> 1)
const minInt = -maxInt - 1
var jsonParser jsoniter.API
var initJson = &sync.Once{}
func initJsonParserOnce() {
initJson.Do(func() {
registerBetterFuzzyDecoder()
jsonParser = jsoniter.ConfigCompatibleWithStandardLibrary
})
}
func registerBetterFuzzyDecoder() {
jsoniter.RegisterTypeDecoder("string", &nullableFuzzyStringDecoder{})
jsoniter.RegisterTypeDecoder("bool", &fuzzyBoolDecoder{})
jsoniter.RegisterTypeDecoder("float32", &nullableFuzzyFloat32Decoder{})
jsoniter.RegisterTypeDecoder("float64", &nullableFuzzyFloat64Decoder{})
jsoniter.RegisterTypeDecoder("int", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(maxInt) || val < float64(minInt) {
iter.ReportError("fuzzy decode int", "exceed range")
return
}
*((*int)(ptr)) = int(val)
} else {
*((*int)(ptr)) = iter.ReadInt()
}
}})
jsoniter.RegisterTypeDecoder("uint", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(maxUint) || val < 0 {
iter.ReportError("fuzzy decode uint", "exceed range")
return
}
*((*uint)(ptr)) = uint(val)
} else {
*((*uint)(ptr)) = iter.ReadUint()
}
}})
jsoniter.RegisterTypeDecoder("int8", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxInt8) || val < float64(math.MinInt8) {
iter.ReportError("fuzzy decode int8", "exceed range")
return
}
*((*int8)(ptr)) = int8(val)
} else {
*((*int8)(ptr)) = iter.ReadInt8()
}
}})
jsoniter.RegisterTypeDecoder("uint8", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxUint8) || val < 0 {
iter.ReportError("fuzzy decode uint8", "exceed range")
return
}
*((*uint8)(ptr)) = uint8(val)
} else {
*((*uint8)(ptr)) = iter.ReadUint8()
}
}})
jsoniter.RegisterTypeDecoder("int16", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxInt16) || val < float64(math.MinInt16) {
iter.ReportError("fuzzy decode int16", "exceed range")
return
}
*((*int16)(ptr)) = int16(val)
} else {
*((*int16)(ptr)) = iter.ReadInt16()
}
}})
jsoniter.RegisterTypeDecoder("uint16", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxUint16) || val < 0 {
iter.ReportError("fuzzy decode uint16", "exceed range")
return
}
*((*uint16)(ptr)) = uint16(val)
} else {
*((*uint16)(ptr)) = iter.ReadUint16()
}
}})
jsoniter.RegisterTypeDecoder("int32", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxInt32) || val < float64(math.MinInt32) {
iter.ReportError("fuzzy decode int32", "exceed range")
return
}
*((*int32)(ptr)) = int32(val)
} else {
*((*int32)(ptr)) = iter.ReadInt32()
}
}})
jsoniter.RegisterTypeDecoder("uint32", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxUint32) || val < 0 {
iter.ReportError("fuzzy decode uint32", "exceed range")
return
}
*((*uint32)(ptr)) = uint32(val)
} else {
*((*uint32)(ptr)) = iter.ReadUint32()
}
}})
jsoniter.RegisterTypeDecoder("int64", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxInt64) || val < float64(math.MinInt64) {
iter.ReportError("fuzzy decode int64", "exceed range")
return
}
*((*int64)(ptr)) = int64(val)
} else {
*((*int64)(ptr)) = iter.ReadInt64()
}
}})
jsoniter.RegisterTypeDecoder("uint64", &nullableFuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if isFloat {
val := iter.ReadFloat64()
if val > float64(math.MaxUint64) || val < 0 {
iter.ReportError("fuzzy decode uint64", "exceed range")
return
}
*((*uint64)(ptr)) = uint64(val)
} else {
*((*uint64)(ptr)) = iter.ReadUint64()
}
}})
}
type nullableFuzzyStringDecoder struct {
}
func (decoder *nullableFuzzyStringDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
switch valueType {
case jsoniter.NumberValue:
var number json.Number
iter.ReadVal(&number)
*((*string)(ptr)) = string(number)
case jsoniter.StringValue:
*((*string)(ptr)) = iter.ReadString()
case jsoniter.BoolValue:
*((*string)(ptr)) = strconv.FormatBool(iter.ReadBool())
case jsoniter.NilValue:
iter.ReadNil()
*((*string)(ptr)) = ""
default:
iter.ReportError("fuzzyStringDecoder", "not number or string or bool")
}
}
type fuzzyBoolDecoder struct {
}
func (decoder *fuzzyBoolDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
switch valueType {
case jsoniter.BoolValue:
*((*bool)(ptr)) = iter.ReadBool()
case jsoniter.NumberValue:
var number json.Number
iter.ReadVal(&number)
num, err := number.Int64()
if err != nil {
iter.ReportError("fuzzyBoolDecoder", "get value from json.number failed")
}
if num == 0 {
*((*bool)(ptr)) = false
} else {
*((*bool)(ptr)) = true
}
case jsoniter.StringValue:
strValue := strings.ToLower(iter.ReadString())
if strValue == "true" {
*((*bool)(ptr)) = true
} else if strValue == "false" || strValue == "" {
*((*bool)(ptr)) = false
} else {
iter.ReportError("fuzzyBoolDecoder", "unsupported bool value: "+strValue)
}
case jsoniter.NilValue:
iter.ReadNil()
*((*bool)(ptr)) = false
default:
iter.ReportError("fuzzyBoolDecoder", "not number or string or nil")
}
}
type tolerateEmptyArrayDecoder struct {
valDecoder jsoniter.ValDecoder
}
func (decoder *tolerateEmptyArrayDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
if iter.WhatIsNext() == jsoniter.ArrayValue {
iter.Skip()
newIter := iter.Pool().BorrowIterator([]byte("{}"))
defer iter.Pool().ReturnIterator(newIter)
decoder.valDecoder.Decode(ptr, newIter)
} else {
decoder.valDecoder.Decode(ptr, iter)
}
}
type nullableFuzzyIntegerDecoder struct {
fun func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator)
}
func (decoder *nullableFuzzyIntegerDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
var str string
switch valueType {
case jsoniter.NumberValue:
var number json.Number
iter.ReadVal(&number)
str = string(number)
case jsoniter.StringValue:
str = iter.ReadString()
// support empty string
if str == "" {
str = "0"
}
case jsoniter.BoolValue:
if iter.ReadBool() {
str = "1"
} else {
str = "0"
}
case jsoniter.NilValue:
iter.ReadNil()
str = "0"
default:
iter.ReportError("fuzzyIntegerDecoder", "not number or string")
}
newIter := iter.Pool().BorrowIterator([]byte(str))
defer iter.Pool().ReturnIterator(newIter)
isFloat := strings.IndexByte(str, '.') != -1
decoder.fun(isFloat, ptr, newIter)
if newIter.Error != nil && newIter.Error != io.EOF {
iter.Error = newIter.Error
}
}
type nullableFuzzyFloat32Decoder struct {
}
func (decoder *nullableFuzzyFloat32Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
var str string
switch valueType {
case jsoniter.NumberValue:
*((*float32)(ptr)) = iter.ReadFloat32()
case jsoniter.StringValue:
str = iter.ReadString()
// support empty string
if str == "" {
*((*float32)(ptr)) = 0
return
}
newIter := iter.Pool().BorrowIterator([]byte(str))
defer iter.Pool().ReturnIterator(newIter)
*((*float32)(ptr)) = newIter.ReadFloat32()
if newIter.Error != nil && newIter.Error != io.EOF {
iter.Error = newIter.Error
}
case jsoniter.BoolValue:
// support bool to float32
if iter.ReadBool() {
*((*float32)(ptr)) = 1
} else {
*((*float32)(ptr)) = 0
}
case jsoniter.NilValue:
iter.ReadNil()
*((*float32)(ptr)) = 0
default:
iter.ReportError("nullableFuzzyFloat32Decoder", "not number or string")
}
}
type nullableFuzzyFloat64Decoder struct {
}
func (decoder *nullableFuzzyFloat64Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
valueType := iter.WhatIsNext()
var str string
switch valueType {
case jsoniter.NumberValue:
*((*float64)(ptr)) = iter.ReadFloat64()
case jsoniter.StringValue:
str = iter.ReadString()
// support empty string
if str == "" {
*((*float64)(ptr)) = 0
return
}
newIter := iter.Pool().BorrowIterator([]byte(str))
defer iter.Pool().ReturnIterator(newIter)
*((*float64)(ptr)) = newIter.ReadFloat64()
if newIter.Error != nil && newIter.Error != io.EOF {
iter.Error = newIter.Error
}
case jsoniter.BoolValue:
// support bool to float64
if iter.ReadBool() {
*((*float64)(ptr)) = 1
} else {
*((*float64)(ptr)) = 0
}
case jsoniter.NilValue:
// support empty string
iter.ReadNil()
*((*float64)(ptr)) = 0
default:
iter.ReportError("nullableFuzzyFloat32Decoder", "not number or string")
}
}
+9 -29
View File
@@ -16,16 +16,15 @@ package responses
import (
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
"io/ioutil"
"net/http"
"strconv"
"strings"
)
type AcsResponse interface {
IsSuccess() bool
GetHttpStatus() int
GetHttpHeaders() map[string][]string
GetHttpContentString() string
@@ -39,25 +38,8 @@ func Unmarshal(response AcsResponse, httpResponse *http.Response, format string)
if err != nil {
return
}
if !response.IsSuccess() {
err = errors.NewServerError(response.GetHttpStatus(), response.GetHttpContentString(), "")
return
}
if _, isCommonResponse := response.(CommonResponse); isCommonResponse {
// common response need not unmarshal
return
}
if len(response.GetHttpContentBytes()) == 0 {
return
}
if strings.ToUpper(format) == "JSON" {
initJsonParserOnce()
err = jsonParser.Unmarshal(response.GetHttpContentBytes(), response)
if err != nil {
err = errors.NewClientError(errors.JsonUnmarshalErrorCode, errors.JsonUnmarshalErrorMessage, err)
}
err = json.Unmarshal(response.GetHttpContentBytes(), response)
} else if strings.ToUpper(format) == "XML" {
err = xml.Unmarshal(response.GetHttpContentBytes(), response)
}
@@ -117,17 +99,15 @@ func (baseResponse *BaseResponse) parseFromHttpResponse(httpResponse *http.Respo
func (baseResponse *BaseResponse) String() string {
resultBuilder := bytes.Buffer{}
// statusCode
resultBuilder.WriteString("\n")
resultBuilder.WriteString(fmt.Sprintf("%s %s\n", baseResponse.originHttpResponse.Proto, baseResponse.originHttpResponse.Status))
resultBuilder.WriteString("StatusCode : " + strconv.Itoa(baseResponse.httpStatus) + "\n")
// httpHeaders
//resultBuilder.WriteString("Headers:\n")
resultBuilder.WriteString("Headers:\n")
for key, value := range baseResponse.httpHeaders {
resultBuilder.WriteString(key + ": " + strings.Join(value, ";") + "\n")
resultBuilder.WriteString(" -> " + key + " : " + strings.Join(value, ";") + "\n")
}
resultBuilder.WriteString("\n")
// content
//resultBuilder.WriteString("Content:\n")
resultBuilder.WriteString(baseResponse.httpContentString + "\n")
resultBuilder.WriteString("Content:\n")
resultBuilder.WriteString(" -> " + baseResponse.httpContentString + "\n")
return resultBuilder.String()
}
@@ -135,7 +115,7 @@ type CommonResponse struct {
*BaseResponse
}
func NewCommonResponse() (response *CommonResponse) {
func NewCommonResponse() (request *CommonResponse) {
return &CommonResponse{
BaseResponse: &BaseResponse{},
}
+2 -19
View File
@@ -27,10 +27,6 @@ import (
"time"
)
// if you use go 1.10 or higher, you can hack this util by these to avoid "TimeZone.zip not found" on Windows
var LoadLocationFromTZData func(name string, data []byte) (*time.Location, error) = nil
var TZData []byte = nil
func GetUUIDV4() (uuidHex string) {
uuidV4 := uuid.NewV4()
uuidHex = hex.EncodeToString(uuidV4.Bytes())
@@ -45,17 +41,8 @@ func GetMD5Base64(bytes []byte) (base64Value string) {
return
}
func GetGMTLocation() (*time.Location, error) {
if LoadLocationFromTZData != nil && TZData != nil {
return LoadLocationFromTZData("GMT", TZData)
} else {
return time.LoadLocation("GMT")
}
}
func GetTimeInFormatISO8601() (timeStr string) {
gmt, err := GetGMTLocation()
gmt, err := time.LoadLocation("GMT")
if err != nil {
panic(err)
}
@@ -63,8 +50,7 @@ func GetTimeInFormatISO8601() (timeStr string) {
}
func GetTimeInFormatRFC2616() (timeStr string) {
gmt, err := GetGMTLocation()
gmt, err := time.LoadLocation("GMT")
if err != nil {
panic(err)
}
@@ -104,9 +90,6 @@ func InitStructWithDefaultTag(bean interface{}) {
case "int":
intValue, _ := strconv.ParseInt(defaultValue, 10, 64)
setter.SetInt(intValue)
case "time.Duration":
intValue, _ := strconv.ParseInt(defaultValue, 10, 64)
setter.SetInt(intValue)
case "string":
setter.SetString(defaultValue)
case "bool":
+2 -3
View File
@@ -21,7 +21,6 @@ package thrift
import (
"bytes"
"context"
"encoding/binary"
"errors"
"fmt"
@@ -458,8 +457,8 @@ func (p *TBinaryProtocol) ReadBinary() ([]byte, error) {
return buf, NewTProtocolException(err)
}
func (p *TBinaryProtocol) Flush(ctx context.Context) (err error) {
return NewTProtocolException(p.trans.Flush(ctx))
func (p *TBinaryProtocol) Flush() (err error) {
return NewTProtocolException(p.trans.Flush())
}
func (p *TBinaryProtocol) Skip(fieldType TType) (err error) {
+2 -3
View File
@@ -21,7 +21,6 @@ package thrift
import (
"bufio"
"context"
)
type TBufferedTransportFactory struct {
@@ -79,12 +78,12 @@ func (p *TBufferedTransport) Write(b []byte) (int, error) {
return n, err
}
func (p *TBufferedTransport) Flush(ctx context.Context) error {
func (p *TBufferedTransport) Flush() error {
if err := p.ReadWriter.Flush(); err != nil {
p.ReadWriter.Writer.Reset(p.tp)
return err
}
return p.tp.Flush(ctx)
return p.tp.Flush()
}
func (p *TBufferedTransport) RemainingBytes() (num_bytes uint64) {
+5 -12
View File
@@ -1,13 +1,6 @@
package thrift
import (
"context"
"fmt"
)
type TClient interface {
Call(ctx context.Context, method string, args, result TStruct) error
}
import "fmt"
type TStandardClient struct {
seqId int32
@@ -23,7 +16,7 @@ func NewTStandardClient(inputProtocol, outputProtocol TProtocol) *TStandardClien
}
}
func (p *TStandardClient) Send(ctx context.Context, oprot TProtocol, seqId int32, method string, args TStruct) error {
func (p *TStandardClient) Send(oprot TProtocol, seqId int32, method string, args TStruct) error {
if err := oprot.WriteMessageBegin(method, CALL, seqId); err != nil {
return err
}
@@ -33,7 +26,7 @@ func (p *TStandardClient) Send(ctx context.Context, oprot TProtocol, seqId int32
if err := oprot.WriteMessageEnd(); err != nil {
return err
}
return oprot.Flush(ctx)
return oprot.Flush()
}
func (p *TStandardClient) Recv(iprot TProtocol, seqId int32, method string, result TStruct) error {
@@ -68,11 +61,11 @@ func (p *TStandardClient) Recv(iprot TProtocol, seqId int32, method string, resu
return iprot.ReadMessageEnd()
}
func (p *TStandardClient) Call(ctx context.Context, method string, args, result TStruct) error {
func (p *TStandardClient) call(method string, args, result TStruct) error {
p.seqId++
seqId := p.seqId
if err := p.Send(ctx, p.oprot, seqId, method, args); err != nil {
if err := p.Send(p.oprot, seqId, method, args); err != nil {
return err
}
+13
View File
@@ -0,0 +1,13 @@
// +build go1.7
package thrift
import "context"
type TClient interface {
Call(ctx context.Context, method string, args, result TStruct) error
}
func (p *TStandardClient) Call(ctx context.Context, method string, args, result TStruct) error {
return p.call(method, args, result)
}
+13
View File
@@ -0,0 +1,13 @@
// +build !go1.7
package thrift
import "golang.org/x/net/context"
type TClient interface {
Call(ctx context.Context, method string, args, result TStruct) error
}
func (p *TStandardClient) Call(ctx context.Context, method string, args, result TStruct) error {
return p.call(method, args, result)
}
+32
View File
@@ -0,0 +1,32 @@
// +build go1.7
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package thrift
import "context"
type mockProcessor struct {
ProcessFunc func(in, out TProtocol) (bool, TException)
}
func (m *mockProcessor) Process(ctx context.Context, in, out TProtocol) (bool, TException) {
return m.ProcessFunc(in, out)
}
+32
View File
@@ -0,0 +1,32 @@
// +build !go1.7
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package thrift
import "golang.org/x/net/context"
type mockProcessor struct {
ProcessFunc func(in, out TProtocol) (bool, TException)
}
func (m *mockProcessor) Process(ctx context.Context, in, out TProtocol) (bool, TException) {
return m.ProcessFunc(in, out)
}
+3 -4
View File
@@ -20,7 +20,6 @@
package thrift
import (
"context"
"encoding/binary"
"fmt"
"io"
@@ -600,8 +599,8 @@ func (p *TCompactProtocol) ReadBinary() (value []byte, err error) {
return buf, NewTProtocolException(e)
}
func (p *TCompactProtocol) Flush(ctx context.Context) (err error) {
return NewTProtocolException(p.trans.Flush(ctx))
func (p *TCompactProtocol) Flush() (err error) {
return NewTProtocolException(p.trans.Flush())
}
func (p *TCompactProtocol) Skip(fieldType TType) (err error) {
@@ -807,7 +806,7 @@ func (p *TCompactProtocol) getTType(t tCompactType) (TType, error) {
case COMPACT_STRUCT:
return STRUCT, nil
}
return STOP, TException(fmt.Errorf("don't know what type: %v", t&0x0f))
return STOP, TException(fmt.Errorf("don't know what type: %s", t&0x0f))
}
// Given a TType value, find the appropriate TCompactProtocol.Types constant.
+2 -3
View File
@@ -20,7 +20,6 @@
package thrift
import (
"context"
"log"
)
@@ -259,8 +258,8 @@ func (tdp *TDebugProtocol) Skip(fieldType TType) (err error) {
log.Printf("%sSkip(fieldType=%#v) (err=%#v)", tdp.LogPrefix, fieldType, err)
return
}
func (tdp *TDebugProtocol) Flush(ctx context.Context) (err error) {
err = tdp.Delegate.Flush(ctx)
func (tdp *TDebugProtocol) Flush() (err error) {
err = tdp.Delegate.Flush()
log.Printf("%sFlush() (err=%#v)", tdp.LogPrefix, err)
return
}

Some files were not shown because too many files have changed in this diff Show More