yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/aws/routetable.go (about) 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 15 package aws 16 17 import ( 18 "fmt" 19 "strings" 20 21 "github.com/aws/aws-sdk-go/service/ec2" 22 23 "yunion.io/x/jsonutils" 24 "yunion.io/x/pkg/errors" 25 26 api "yunion.io/x/cloudmux/pkg/apis/compute" 27 "yunion.io/x/cloudmux/pkg/cloudprovider" 28 "yunion.io/x/cloudmux/pkg/multicloud" 29 ) 30 31 type SRouteTable struct { 32 multicloud.SResourceBase 33 AwsTags 34 region *SRegion 35 vpc *SVpc 36 37 Associations []Association `json:"Associations"` 38 PropagatingVgws []string `json:"PropagatingVgws"` 39 RouteTableID string `json:"RouteTableId"` 40 Routes []SRoute `json:"Routes"` 41 VpcID string `json:"VpcId"` 42 OwnerID string `json:"OwnerId"` 43 } 44 45 type Association struct { 46 Main bool `json:"Main"` 47 RouteTableAssociationID string `json:"RouteTableAssociationId"` 48 RouteTableID string `json:"RouteTableId"` 49 GatewayID *string `json:"GatewayId,omitempty"` 50 SubnetID *string `json:"SubnetId,omitempty"` 51 } 52 53 func (self *SRouteTable) GetId() string { 54 return self.RouteTableID 55 } 56 57 func (self *SRouteTable) GetName() string { 58 return "" 59 } 60 61 func (self *SRouteTable) GetGlobalId() string { 62 return self.GetId() 63 } 64 65 func (self *SRouteTable) GetStatus() string { 66 return api.ROUTE_TABLE_AVAILABLE 67 } 68 69 func (self *SRouteTable) Refresh() error { 70 ret, err := self.region.GetRouteTable(self.GetId()) 71 if err != nil { 72 return errors.Wrap(err, "SRouteTable.Refresh.GetRouteTable") 73 } 74 75 err = jsonutils.Update(self, ret) 76 if err != nil { 77 return errors.Wrap(err, "SRouteTable.Refresh.Update") 78 } 79 80 return nil 81 } 82 83 func (self *SRouteTable) IsEmulated() bool { 84 return false 85 } 86 87 func (self *SRouteTable) GetDescription() string { 88 return "" 89 } 90 91 func (self *SRouteTable) GetRegionId() string { 92 return self.region.GetId() 93 } 94 95 func (self *SRouteTable) GetVpcId() string { 96 return self.VpcID 97 } 98 99 func (self *SRouteTable) GetType() cloudprovider.RouteTableType { 100 for i := range self.Associations { 101 if self.Associations[i].Main { 102 return cloudprovider.RouteTableTypeSystem 103 } 104 } 105 return cloudprovider.RouteTableTypeCustom 106 } 107 108 func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation { 109 result := []cloudprovider.RouteTableAssociation{} 110 for i := range self.Associations { 111 if self.Associations[i].GatewayID != nil { 112 association := cloudprovider.RouteTableAssociation{ 113 AssociationId: self.Associations[i].RouteTableAssociationID, 114 AssociationType: cloudprovider.RouteTableAssociaToRouter, 115 AssociatedResourceId: *self.Associations[i].GatewayID, 116 } 117 result = append(result, association) 118 } 119 if self.Associations[i].SubnetID != nil { 120 association := cloudprovider.RouteTableAssociation{ 121 AssociationId: self.Associations[i].RouteTableAssociationID, 122 AssociationType: cloudprovider.RouteTableAssociaToSubnet, 123 AssociatedResourceId: *self.Associations[i].SubnetID, 124 } 125 result = append(result, association) 126 } 127 } 128 return result 129 } 130 131 func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error { 132 err := self.region.CreateRoute(self.RouteTableID, route.Destination, route.NextHop) 133 if err != nil { 134 return errors.Wrapf(err, "self.region.CreateRoute(%s,%s,%s)", self.RouteTableID, route.Destination, route.NextHop) 135 } 136 return nil 137 } 138 139 func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error { 140 routeInfo := strings.Split(route.RouteId, ":") 141 if len(routeInfo) != 2 { 142 return errors.Wrap(cloudprovider.ErrNotSupported, "invalid route info") 143 } 144 err := self.region.RemoveRoute(self.RouteTableID, routeInfo[0]) 145 if err != nil { 146 return errors.Wrapf(err, "self.region.RemoveRoute(%s,%s)", self.RouteTableID, route.Destination) 147 } 148 149 err = self.CreateRoute(route) 150 if err != nil { 151 return errors.Wrapf(err, "self.CreateRoute(%s)", jsonutils.Marshal(route).String()) 152 } 153 return nil 154 } 155 156 func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error { 157 err := self.region.RemoveRoute(self.RouteTableID, route.Destination) 158 if err != nil { 159 return errors.Wrapf(err, "self.region.RemoveRoute(%s,%s)", self.RouteTableID, route.Destination) 160 } 161 return nil 162 } 163 164 func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { 165 iroutes := make([]cloudprovider.ICloudRoute, len(self.Routes)) 166 for i := range self.Routes { 167 self.Routes[i].routetable = self 168 iroutes[i] = &self.Routes[i] 169 } 170 171 return iroutes, nil 172 } 173 174 func (self *SRegion) GetRouteTables(vpcId string, mainRouteOnly bool) ([]SRouteTable, error) { 175 ec2Client, err := self.getEc2Client() 176 if err != nil { 177 return nil, errors.Wrap(err, "getEc2Client") 178 } 179 180 input := &ec2.DescribeRouteTablesInput{} 181 filters := make([]*ec2.Filter, 0) 182 filters = AppendSingleValueFilter(filters, "vpc-id", vpcId) 183 if mainRouteOnly { 184 filters = AppendSingleValueFilter(filters, "association.main", "true") 185 } 186 187 input.SetFilters(filters) 188 189 ret, err := ec2Client.DescribeRouteTables(input) 190 if err != nil { 191 return nil, errors.Wrap(err, "SRegion.GetRouteTables.DescribeRouteTables") 192 } 193 194 routeTables := make([]SRouteTable, len(ret.RouteTables)) 195 err = unmarshalAwsOutput(ret, "RouteTables", routeTables) 196 if err != nil { 197 return nil, errors.Wrap(err, "SRegion.GetRouteTables.unmarshalAwsOutput") 198 } 199 200 for i := range routeTables { 201 routeTables[i].region = self 202 } 203 204 return routeTables, nil 205 } 206 207 func (self *SRegion) CreateRoute(routeTableId string, DestinationCIDRBlock string, targetId string) error { 208 input := &ec2.CreateRouteInput{} 209 input.RouteTableId = &routeTableId 210 input.DestinationCidrBlock = &DestinationCIDRBlock 211 segs := strings.Split(targetId, "-") 212 if len(segs) == 0 { 213 return fmt.Errorf("invalid aws vpc targetid:%s", targetId) 214 } 215 switch segs[0] { 216 case "i": 217 input.InstanceId = &targetId 218 case "igw", "vgw": 219 input.GatewayId = &targetId 220 case "pcx": 221 input.VpcPeeringConnectionId = &targetId 222 case "eni": 223 input.NetworkInterfaceId = &targetId 224 case "nat": 225 input.NatGatewayId = &targetId 226 case "eigw": 227 input.EgressOnlyInternetGatewayId = &targetId 228 default: 229 return fmt.Errorf("invalid aws vpc targetid:%s", targetId) 230 } 231 ec2Client, err := self.getEc2Client() 232 if err != nil { 233 return errors.Wrap(err, "getEc2Client") 234 } 235 _, err = ec2Client.CreateRoute(input) 236 if err != nil { 237 return errors.Wrapf(err, "self.ec2Client.CreateRoute(%s)", jsonutils.Marshal(input).String()) 238 } 239 return nil 240 } 241 242 func (self *SRegion) ReplaceRoute(routeTableId string, DestinationCIDRBlock string, targetId string) error { 243 input := &ec2.ReplaceRouteInput{} 244 input.RouteTableId = &routeTableId 245 input.DestinationCidrBlock = &DestinationCIDRBlock 246 segs := strings.Split(targetId, "-") 247 if len(segs) == 0 { 248 return fmt.Errorf("invalid aws vpc targetid:%s", targetId) 249 } 250 switch segs[0] { 251 case "i": 252 input.InstanceId = &targetId 253 case "igw", "vgw": 254 input.GatewayId = &targetId 255 case "pcx": 256 input.VpcPeeringConnectionId = &targetId 257 case "eni": 258 input.NetworkInterfaceId = &targetId 259 case "nat": 260 input.NatGatewayId = &targetId 261 case "eigw": 262 input.EgressOnlyInternetGatewayId = &targetId 263 default: 264 return fmt.Errorf("invalid aws vpc targetid:%s", targetId) 265 } 266 ec2Client, err := self.getEc2Client() 267 if err != nil { 268 return errors.Wrap(err, "getEc2Client") 269 } 270 _, err = ec2Client.ReplaceRoute(input) 271 if err != nil { 272 return errors.Wrapf(err, "self.ec2Client.ReplaceRouteInput(%s)", jsonutils.Marshal(input).String()) 273 } 274 return nil 275 } 276 277 func (self *SRegion) RemoveRoute(routeTableId string, DestinationCIDRBlock string) error { 278 ec2Client, err := self.getEc2Client() 279 if err != nil { 280 return errors.Wrap(err, "getEc2Client") 281 } 282 input := &ec2.DeleteRouteInput{} 283 input.RouteTableId = &routeTableId 284 input.DestinationCidrBlock = &DestinationCIDRBlock 285 _, err = ec2Client.DeleteRoute(input) 286 if err != nil { 287 return errors.Wrapf(err, "self.ec2Client.DeleteRoute(%s)", jsonutils.Marshal(input).String()) 288 } 289 return nil 290 } 291 292 func (self *SRegion) GetRouteTablesByNetworkId(netId string) ([]SRouteTable, error) { 293 ec2Client, err := self.getEc2Client() 294 if err != nil { 295 return nil, errors.Wrap(err, "getEc2Client") 296 } 297 298 input := &ec2.DescribeRouteTablesInput{} 299 filter := &ec2.Filter{} 300 filter.SetName("association.subnet-id") 301 filter.SetValues([]*string{&netId}) 302 input.SetFilters([]*ec2.Filter{filter}) 303 304 ret, err := ec2Client.DescribeRouteTables(input) 305 if err != nil { 306 return nil, errors.Wrap(err, "SRegion.GetRouteTables.DescribeRouteTables") 307 } 308 309 routeTables := make([]SRouteTable, len(ret.RouteTables)) 310 err = unmarshalAwsOutput(ret, "RouteTables", routeTables) 311 if err != nil { 312 return nil, errors.Wrap(err, "SRegion.GetRouteTables.unmarshalAwsOutput") 313 } 314 315 for i := range routeTables { 316 routeTables[i].region = self 317 } 318 319 return routeTables, nil 320 } 321 322 func (self *SRegion) GetRouteTable(id string) (*SRouteTable, error) { 323 ec2Client, err := self.getEc2Client() 324 if err != nil { 325 return nil, errors.Wrap(err, "getEc2Client") 326 } 327 328 input := &ec2.DescribeRouteTablesInput{} 329 input.RouteTableIds = []*string{&id} 330 ret, err := ec2Client.DescribeRouteTables(input) 331 if err != nil { 332 return nil, errors.Wrap(err, "SRegion.GetRouteTables.DescribeRouteTables") 333 } 334 335 routeTables := make([]SRouteTable, len(ret.RouteTables)) 336 err = unmarshalAwsOutput(ret, "RouteTables", routeTables) 337 if err != nil { 338 return nil, errors.Wrap(err, "SRegion.GetRouteTables.unmarshalAwsOutput") 339 } 340 341 if len(routeTables) == 1 { 342 routeTables[0].region = self 343 return &routeTables[0], nil 344 } else if len(routeTables) == 0 { 345 return nil, errors.ErrNotFound 346 } else { 347 return nil, errors.ErrDuplicateId 348 } 349 } 350 351 func (self *SRegion) DeleteRouteTable(rid string) error { 352 input := &ec2.DeleteRouteTableInput{} 353 input.SetRouteTableId(rid) 354 355 ec2Client, err := self.getEc2Client() 356 if err != nil { 357 return errors.Wrap(err, "getEc2Client") 358 } 359 _, err = ec2Client.DeleteRouteTable(input) 360 if err != nil { 361 return errors.Wrap(err, "DeleteRouteTable") 362 } 363 364 return nil 365 }