routetable.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package aws
  15. import (
  16. "fmt"
  17. "strings"
  18. "yunion.io/x/jsonutils"
  19. "yunion.io/x/pkg/errors"
  20. api "yunion.io/x/cloudmux/pkg/apis/compute"
  21. "yunion.io/x/cloudmux/pkg/cloudprovider"
  22. "yunion.io/x/cloudmux/pkg/multicloud"
  23. )
  24. type SRouteTable struct {
  25. multicloud.SResourceBase
  26. AwsTags
  27. region *SRegion
  28. vpc *SVpc
  29. Associations []Association `xml:"associationSet>item"`
  30. PropagatingVgws []string `xml:"propagatingVgwSet>item"`
  31. RouteTableId string `xml:"routeTableId"`
  32. Routes []SRoute `xml:"routeSet>item"`
  33. VpcId string `json:"vpcId"`
  34. OwnerId string `json:"ownerId"`
  35. }
  36. type Association struct {
  37. Main bool `xml:"main"`
  38. RouteTableAssociationId string `xml:"routeTableAssociationId"`
  39. RouteTableId string `xml:"routeTableId"`
  40. GatewayId *string `xml:"gatewayId"`
  41. SubnetId *string `xml:"subnetId"`
  42. }
  43. func (self *SRouteTable) GetId() string {
  44. return self.RouteTableId
  45. }
  46. func (self *SRouteTable) GetName() string {
  47. return ""
  48. }
  49. func (self *SRouteTable) GetGlobalId() string {
  50. return self.GetId()
  51. }
  52. func (self *SRouteTable) GetStatus() string {
  53. return api.ROUTE_TABLE_AVAILABLE
  54. }
  55. func (self *SRouteTable) Refresh() error {
  56. ret, err := self.region.GetRouteTable(self.GetId())
  57. if err != nil {
  58. return errors.Wrap(err, "GetRouteTable")
  59. }
  60. return jsonutils.Update(self, ret)
  61. }
  62. func (self *SRouteTable) GetDescription() string {
  63. return ""
  64. }
  65. func (self *SRouteTable) GetRegionId() string {
  66. return self.region.GetId()
  67. }
  68. func (self *SRouteTable) GetVpcId() string {
  69. return self.VpcId
  70. }
  71. func (self *SRouteTable) GetType() cloudprovider.RouteTableType {
  72. for i := range self.Associations {
  73. if self.Associations[i].Main {
  74. return cloudprovider.RouteTableTypeSystem
  75. }
  76. }
  77. return cloudprovider.RouteTableTypeCustom
  78. }
  79. func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation {
  80. result := []cloudprovider.RouteTableAssociation{}
  81. for i := range self.Associations {
  82. if self.Associations[i].GatewayId != nil {
  83. association := cloudprovider.RouteTableAssociation{
  84. AssociationId: self.Associations[i].RouteTableAssociationId,
  85. AssociationType: cloudprovider.RouteTableAssociaToRouter,
  86. AssociatedResourceId: *self.Associations[i].GatewayId,
  87. }
  88. result = append(result, association)
  89. }
  90. if self.Associations[i].SubnetId != nil {
  91. association := cloudprovider.RouteTableAssociation{
  92. AssociationId: self.Associations[i].RouteTableAssociationId,
  93. AssociationType: cloudprovider.RouteTableAssociaToSubnet,
  94. AssociatedResourceId: *self.Associations[i].SubnetId,
  95. }
  96. result = append(result, association)
  97. }
  98. }
  99. return result
  100. }
  101. func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error {
  102. err := self.region.CreateRoute(self.RouteTableId, route.Destination, route.NextHop)
  103. if err != nil {
  104. return errors.Wrapf(err, "self.region.CreateRoute(%s,%s,%s)", self.RouteTableId, route.Destination, route.NextHop)
  105. }
  106. return nil
  107. }
  108. func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error {
  109. routeInfo := strings.Split(route.RouteId, ":")
  110. if len(routeInfo) != 2 {
  111. return errors.Wrap(cloudprovider.ErrNotSupported, "invalid route info")
  112. }
  113. err := self.region.RemoveRoute(self.RouteTableId, routeInfo[0])
  114. if err != nil {
  115. return errors.Wrapf(err, "self.region.RemoveRoute(%s,%s)", self.RouteTableId, route.Destination)
  116. }
  117. err = self.CreateRoute(route)
  118. if err != nil {
  119. return errors.Wrapf(err, "self.CreateRoute(%s)", jsonutils.Marshal(route).String())
  120. }
  121. return nil
  122. }
  123. func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error {
  124. err := self.region.RemoveRoute(self.RouteTableId, route.Destination)
  125. if err != nil {
  126. return errors.Wrapf(err, "self.region.RemoveRoute(%s,%s)", self.RouteTableId, route.Destination)
  127. }
  128. return nil
  129. }
  130. func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) {
  131. iroutes := make([]cloudprovider.ICloudRoute, len(self.Routes))
  132. for i := range self.Routes {
  133. self.Routes[i].routetable = self
  134. iroutes[i] = &self.Routes[i]
  135. }
  136. return iroutes, nil
  137. }
  138. func (self *SRegion) GetRouteTables(vpcId, subnetId, vpcPeerId, rid string, mainRouteOnly bool) ([]SRouteTable, error) {
  139. params := map[string]string{}
  140. if len(rid) > 0 {
  141. params["RouteTableId.1"] = rid
  142. }
  143. idx := 1
  144. if len(vpcId) > 0 {
  145. params[fmt.Sprintf("Filter.%d.Name", idx)] = "vpc-id"
  146. params[fmt.Sprintf("Filter.%d.Value.1", idx)] = vpcId
  147. idx++
  148. }
  149. if mainRouteOnly {
  150. params[fmt.Sprintf("Filter.%d.Name", idx)] = "association.main"
  151. params[fmt.Sprintf("Filter.%d.Value.1", idx)] = "true"
  152. idx++
  153. }
  154. if len(subnetId) > 0 {
  155. params[fmt.Sprintf("Filter.%d.Name", idx)] = "association.subnet-id"
  156. params[fmt.Sprintf("Filter.%d.Value.1", idx)] = subnetId
  157. idx++
  158. }
  159. if len(vpcPeerId) > 0 {
  160. params[fmt.Sprintf("Filter.%d.Name", idx)] = "route.vpc-peering-connection-id"
  161. params[fmt.Sprintf("Filter.%d.Value.1", idx)] = vpcPeerId
  162. idx++
  163. }
  164. ret := []SRouteTable{}
  165. for {
  166. part := struct {
  167. NextToken string `xml:"nextToken"`
  168. RouteTableSet []SRouteTable `xml:"routeTableSet>item"`
  169. }{}
  170. err := self.ec2Request("DescribeRouteTables", params, &part)
  171. if err != nil {
  172. return nil, err
  173. }
  174. ret = append(ret, part.RouteTableSet...)
  175. if len(part.NextToken) == 0 || len(part.RouteTableSet) == 0 {
  176. break
  177. }
  178. params["NextToken"] = part.NextToken
  179. }
  180. return ret, nil
  181. }
  182. func (self *SRegion) CreateRoute(routeTableId string, cidr string, targetId string) error {
  183. segs := strings.Split(targetId, "-")
  184. if len(segs) == 0 {
  185. return fmt.Errorf("invalid aws vpc targetid:%s", targetId)
  186. }
  187. params := map[string]string{
  188. "RouteTableId": routeTableId,
  189. "DestinationCidrBlock": cidr,
  190. }
  191. switch segs[0] {
  192. case "i":
  193. params["InstanceId"] = targetId
  194. case "igw", "vgw":
  195. params["GatewayId"] = targetId
  196. case "pcx":
  197. params["VpcPeeringConnectionId"] = targetId
  198. case "eni":
  199. params["NetworkInterfaceId"] = targetId
  200. case "nat":
  201. params["NatGatewayId"] = targetId
  202. case "eigw":
  203. params["EgressOnlyInternetGatewayId"] = targetId
  204. default:
  205. return fmt.Errorf("invalid aws vpc targetid:%s", targetId)
  206. }
  207. ret := struct{}{}
  208. return self.ec2Request("CreateRoute", params, &ret)
  209. }
  210. func (self *SRegion) ReplaceRoute(routeTableId string, cidr string, targetId string) error {
  211. params := map[string]string{
  212. "RouteTableId": routeTableId,
  213. "DestinationCidrBlock": cidr,
  214. }
  215. segs := strings.Split(targetId, "-")
  216. if len(segs) == 0 {
  217. return fmt.Errorf("invalid aws vpc targetid:%s", targetId)
  218. }
  219. switch segs[0] {
  220. case "i":
  221. params["InstanceId"] = targetId
  222. case "igw", "vgw":
  223. params["GatewayId"] = targetId
  224. case "pcx":
  225. params["VpcPeeringConnectionId"] = targetId
  226. case "eni":
  227. params["NetworkInterfaceId"] = targetId
  228. case "nat":
  229. params["NatGatewayId"] = targetId
  230. case "eigw":
  231. params["EgressOnlyInternetGatewayId"] = targetId
  232. default:
  233. return fmt.Errorf("invalid aws vpc targetid:%s", targetId)
  234. }
  235. ret := struct{}{}
  236. return self.ec2Request("eplaceRoute", params, &ret)
  237. }
  238. func (self *SRegion) RemoveRoute(routeTableId string, cidr string) error {
  239. params := map[string]string{
  240. "RouteTableId": routeTableId,
  241. "DestinationCidrBlock": cidr,
  242. }
  243. ret := struct{}{}
  244. return self.ec2Request("DeleteRoute", params, &ret)
  245. }
  246. func (self *SRegion) GetRouteTable(id string) (*SRouteTable, error) {
  247. tables, err := self.GetRouteTables("", "", "", id, false)
  248. if err != nil {
  249. return nil, err
  250. }
  251. for i := range tables {
  252. if tables[i].GetGlobalId() == id {
  253. return &tables[i], nil
  254. }
  255. }
  256. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", id)
  257. }
  258. func (self *SRegion) DeleteRouteTable(rid string) error {
  259. params := map[string]string{
  260. "RouteTableId": rid,
  261. }
  262. ret := struct{}{}
  263. return self.ec2Request("DeleteRouteTable", params, &ret)
  264. }
  265. func (self *SRoute) GetDescription() string {
  266. return self.AwsTags.GetDescription()
  267. }