securitygroup.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  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 azure
  15. import (
  16. "fmt"
  17. "net/url"
  18. "strings"
  19. "unicode"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/pkg/util/secrules"
  23. api "yunion.io/x/cloudmux/pkg/apis/compute"
  24. "yunion.io/x/cloudmux/pkg/cloudprovider"
  25. "yunion.io/x/cloudmux/pkg/multicloud"
  26. )
  27. type Interface struct {
  28. ID string
  29. }
  30. type SecurityGroupPropertiesFormat struct {
  31. SecurityRules []SecurityRules `json:"securityRules,omitempty"`
  32. DefaultSecurityRules []SecurityRules `json:"defaultSecurityRules,omitempty"`
  33. NetworkInterfaces *[]Interface `json:"networkInterfaces,omitempty"`
  34. Subnets *[]SNetwork `json:"subnets,omitempty"`
  35. }
  36. type SSecurityGroup struct {
  37. multicloud.SSecurityGroup
  38. AzureTags
  39. region *SRegion
  40. Properties *SecurityGroupPropertiesFormat `json:"properties,omitempty"`
  41. ID string
  42. Name string
  43. Location string
  44. Type string
  45. }
  46. func (self *SSecurityGroup) GetId() string {
  47. return self.ID
  48. }
  49. func (self *SSecurityGroup) GetGlobalId() string {
  50. return strings.ToLower(self.ID)
  51. }
  52. func (self *SSecurityGroup) GetDescription() string {
  53. return ""
  54. }
  55. func (self *SSecurityGroup) GetName() string {
  56. return self.Name
  57. }
  58. func (self *SSecurityGroup) GetRules() ([]cloudprovider.ISecurityGroupRule, error) {
  59. rules := make([]cloudprovider.ISecurityGroupRule, 0)
  60. if self.Properties == nil || self.Properties.SecurityRules == nil {
  61. return rules, nil
  62. }
  63. for i := range self.Properties.SecurityRules {
  64. self.Properties.SecurityRules[i].region = self.region.getZone().region
  65. rules = append(rules, &self.Properties.SecurityRules[i])
  66. }
  67. return rules, nil
  68. }
  69. func (self *SSecurityGroup) GetStatus() string {
  70. return api.SECGROUP_STATUS_READY
  71. }
  72. func (self *SSecurityGroup) GetVpcId() string {
  73. return ""
  74. }
  75. func (region *SRegion) CreateSecurityGroup(opts *cloudprovider.SecurityGroupCreateInput) (*SSecurityGroup, error) {
  76. secgroup := &SSecurityGroup{region: region}
  77. params := map[string]interface{}{
  78. "Name": opts.Name,
  79. "Type": "Microsoft.Network/networkSecurityGroups",
  80. "Location": region.Name,
  81. }
  82. err := region.create("", jsonutils.Marshal(params), secgroup)
  83. if err != nil {
  84. return nil, errors.Wrapf(err, "create")
  85. }
  86. return secgroup, nil
  87. }
  88. func (region *SRegion) ListSecgroups() ([]SSecurityGroup, error) {
  89. secgroups := []SSecurityGroup{}
  90. err := region.list("Microsoft.Network/networkSecurityGroups", url.Values{}, &secgroups)
  91. if err != nil {
  92. return nil, errors.Wrapf(err, "list")
  93. }
  94. return secgroups, nil
  95. }
  96. func (region *SRegion) GetSecurityGroupDetails(secgroupId string) (*SSecurityGroup, error) {
  97. secgroup := SSecurityGroup{region: region}
  98. return &secgroup, region.get(secgroupId, url.Values{}, &secgroup)
  99. }
  100. func (self *SSecurityGroup) Refresh() error {
  101. sec, err := self.region.GetSecurityGroupDetails(self.ID)
  102. if err != nil {
  103. return err
  104. }
  105. return jsonutils.Update(self, sec)
  106. }
  107. func (region *SRegion) AttachSecurityToInterfaces(secgroupId string, nicIds []string) error {
  108. for _, nicId := range nicIds {
  109. nic, err := region.GetNetworkInterface(nicId)
  110. if err != nil {
  111. return err
  112. }
  113. nic.Properties.NetworkSecurityGroup = &SSecurityGroup{ID: secgroupId}
  114. if err := region.update(jsonutils.Marshal(nic), nil); err != nil {
  115. return err
  116. }
  117. }
  118. return nil
  119. }
  120. func (region *SRegion) SetSecurityGroup(instanceId, secgroupId string) error {
  121. instance, err := region.GetInstance(instanceId)
  122. if err != nil {
  123. return err
  124. }
  125. nicIds := []string{}
  126. for _, nic := range instance.Properties.NetworkProfile.NetworkInterfaces {
  127. nicIds = append(nicIds, nic.ID)
  128. }
  129. return region.AttachSecurityToInterfaces(secgroupId, nicIds)
  130. }
  131. func (self *SSecurityGroup) GetProjectId() string {
  132. return getResourceGroup(self.ID)
  133. }
  134. func (self *SSecurityGroup) CreateRule(opts *cloudprovider.SecurityGroupRuleCreateOptions) (cloudprovider.ISecurityGroupRule, error) {
  135. rule, err := self.region.CreateSecurityGroupRule(self.ID, opts)
  136. if err != nil {
  137. return nil, err
  138. }
  139. rule.region = self.region
  140. return rule, nil
  141. }
  142. func (self *SSecurityGroup) Delete() error {
  143. if self.Properties != nil {
  144. if self.Properties.NetworkInterfaces != nil {
  145. for _, nic := range *self.Properties.NetworkInterfaces {
  146. nic, err := self.region.GetNetworkInterface(nic.ID)
  147. if err != nil {
  148. return errors.Wrapf(err, "get nic %s", nic.ID)
  149. }
  150. nic.Properties.NetworkSecurityGroup = nil
  151. err = self.region.update(jsonutils.Marshal(nic), nil)
  152. if err != nil {
  153. return errors.Wrapf(err, "update nic")
  154. }
  155. }
  156. }
  157. if self.Properties.Subnets != nil {
  158. for _, _net := range *self.Properties.Subnets {
  159. net, err := self.region.GetNetwork(_net.ID)
  160. if err != nil {
  161. return errors.Wrapf(err, "get network %s", _net.ID)
  162. }
  163. err = self.region.update(jsonutils.Marshal(net), nil)
  164. if err != nil {
  165. return errors.Wrapf(err, "update network")
  166. }
  167. }
  168. }
  169. }
  170. return self.region.del(self.ID)
  171. }
  172. func (self *SRegion) CreateSecurityGroupRule(groupId string, opts *cloudprovider.SecurityGroupRuleCreateOptions) (*SecurityRules, error) {
  173. name := fmt.Sprintf("%s_%d", opts.String(), opts.Priority)
  174. name = func(name string) string {
  175. // 名称必须以字母或数字开头,以字母、数字或下划线结尾,并且只能包含字母、数字、下划线、句点或连字符
  176. ret := ""
  177. for _, s := range name {
  178. if !(unicode.IsDigit(s) || unicode.IsLetter(s) || s == '.' || s == '-' || s == '_') {
  179. ret += "_"
  180. continue
  181. }
  182. ret += string(s)
  183. }
  184. if !unicode.IsDigit(rune(name[0])) && !unicode.IsLetter(rune(name[0])) {
  185. ret = fmt.Sprintf("r_%s", ret)
  186. }
  187. last := len(ret) - 1
  188. if !unicode.IsDigit(rune(name[last])) && !unicode.IsLetter(rune(name[last])) && name[last] != '_' {
  189. ret = fmt.Sprintf("%s_", ret)
  190. }
  191. return ret
  192. }(name)
  193. name = strings.ReplaceAll(name, ".", "_")
  194. if opts.Protocol == secrules.PROTO_ANY {
  195. opts.Protocol = "*"
  196. }
  197. if len(opts.Ports) == 0 {
  198. opts.Ports = "*"
  199. }
  200. properties := map[string]interface{}{
  201. "access": opts.Action,
  202. "priority": opts.Priority,
  203. "protocol": opts.Protocol,
  204. "direction": opts.Direction + "bound",
  205. "DestinationAddressPrefix": opts.CIDR,
  206. "DestinationPortRange": opts.Ports,
  207. "SourcePortRange": "*",
  208. "SourceAddressPrefix": "*",
  209. }
  210. info := strings.Split(groupId, "/")
  211. groupName := info[len(info)-1]
  212. params := map[string]interface{}{
  213. "Name": groupName + "/securityRules/" + name,
  214. "Type": "Microsoft.Network/networkSecurityGroups",
  215. "properties": properties,
  216. }
  217. rule := &SecurityRules{}
  218. resourceGroup := strings.TrimPrefix(getResourceGroup(groupId), self.client.subscriptionId+"/")
  219. err := self.create(resourceGroup, jsonutils.Marshal(params), rule)
  220. if err != nil {
  221. return nil, errors.Wrapf(err, "create")
  222. }
  223. return rule, nil
  224. }