yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/azure/web_app.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 azure
    16  
    17  import (
    18  	"fmt"
    19  	"net/url"
    20  	"strings"
    21  
    22  	"yunion.io/x/log"
    23  	"yunion.io/x/pkg/errors"
    24  
    25  	"yunion.io/x/cloudmux/pkg/cloudprovider"
    26  	"yunion.io/x/cloudmux/pkg/multicloud"
    27  )
    28  
    29  type SAppSite struct {
    30  	multicloud.SResourceBase
    31  	AzureTags
    32  	region         *SRegion
    33  	appServicePlan *SAppServicePlan
    34  
    35  	Properties SAppSiteProperties
    36  	Id         string
    37  	Name       string
    38  	Kind       string
    39  	Location   string
    40  	Type       string
    41  
    42  	stack *string
    43  }
    44  
    45  type SAppSiteProperties struct {
    46  	AvailabilityState   string
    47  	DefaultHostName     string
    48  	Enabled             bool
    49  	EnabledHostNames    []string
    50  	HostNameSslStates   []SHostNameSslState
    51  	HostNames           []string
    52  	HttpsOnly           bool
    53  	OutboundIpAddresses string
    54  	ResourceGroup       string
    55  	ServerFarmId        string
    56  	SiteConfig          SSiteConfig
    57  	State               string
    58  }
    59  
    60  type SSiteConfig struct {
    61  	// TODO
    62  }
    63  
    64  type SHostNameSslState struct {
    65  	HostType   string
    66  	Name       string
    67  	SslState   string
    68  	Thumbprint string
    69  	ToUpdate   bool
    70  	VirtualIP  string
    71  }
    72  
    73  func (r *SRegion) GetAppSites() ([]SAppSite, error) {
    74  	result := []SAppSite{}
    75  	resource := "Microsoft.Web/sites"
    76  	err := r.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  	for i := range result {
    81  		result[i].region = r
    82  	}
    83  	return result, nil
    84  }
    85  
    86  func (r *SRegion) GetICloudApps() ([]cloudprovider.ICloudApp, error) {
    87  	ass, err := r.GetAppSites()
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	apps := make([]cloudprovider.ICloudApp, 0, len(ass))
    92  	for i := range ass {
    93  		apps = append(apps, &SApp{
    94  			SAppSite: ass[i],
    95  		})
    96  	}
    97  	return apps, nil
    98  }
    99  
   100  func (r *SRegion) GetICloudAppById(id string) (cloudprovider.ICloudApp, error) {
   101  	as, err := r.GetAppSite(id)
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	return &SApp{
   106  		SAppSite: *as,
   107  	}, nil
   108  }
   109  
   110  func (as *SAppSite) GetSlots() ([]SAppSite, error) {
   111  	result := []SAppSite{}
   112  	resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/sites/%s/slots", as.region.client.subscriptionId, as.Properties.ResourceGroup, as.Name)
   113  	err := as.region.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result)
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  	return result, nil
   118  }
   119  
   120  func (r *SRegion) GetAppSite(siteId string) (*SAppSite, error) {
   121  	as := &SAppSite{region: r}
   122  	params := url.Values{"api-version": []string{"2019-08-01"}}
   123  	return as, r.get(siteId, params, as)
   124  }
   125  
   126  func (as *SAppSite) GetAppServicePlan() (*SAppServicePlan, error) {
   127  	if as.appServicePlan != nil {
   128  		return as.appServicePlan, nil
   129  	}
   130  	plan, err := as.region.GetAppServicePlanWithCache(as.Properties.ServerFarmId)
   131  	if err != nil {
   132  		return nil, errors.Wrap(err, "unable to get AppServicePlan")
   133  	}
   134  	as.appServicePlan = plan
   135  	return plan, nil
   136  }
   137  
   138  type SDeployment struct {
   139  	ID         string
   140  	Name       string
   141  	Kind       string
   142  	Type       string
   143  	Properties SDeploymentProperties
   144  }
   145  
   146  type SDeploymentProperties struct {
   147  	Active      bool
   148  	Author      string
   149  	AuthorEmail string
   150  	Deployer    string
   151  	Details     string
   152  	EndTime     string
   153  	Message     string
   154  	StartTime   string
   155  	Status      string
   156  }
   157  
   158  func (as *SAppSite) GetDeployments() ([]SDeployment, error) {
   159  	result := []SDeployment{}
   160  	resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/sites/%s/deployments", as.region.client._subscriptionId(), as.Properties.ResourceGroup, as.Name)
   161  	err := as.region.client.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result)
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  	return result, nil
   166  }
   167  
   168  type SStringDictionary struct {
   169  	Id         string
   170  	Kind       string
   171  	Name       string
   172  	Type       string
   173  	Properties map[string]string
   174  }
   175  
   176  func (as *SAppSite) GetStack() (string, error) {
   177  	if as.stack != nil {
   178  		return *as.stack, nil
   179  	}
   180  	// result := SStringDictionary{}
   181  	resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/sites/%s/config/metadata", as.region.client.subscriptionId, as.Properties.ResourceGroup, as.Name)
   182  
   183  	params := url.Values{}
   184  	params.Set("api-version", "2019-08-01")
   185  	path := resource + "/list"
   186  	response, err := as.region.client.jsonRequest("POST", path, nil, params, true)
   187  	if err != nil {
   188  		return "", err
   189  	}
   190  	stack, err := response.GetString("properties", "CURRENT_STACK")
   191  	if err != nil {
   192  		return "", errors.Wrapf(err, "unable to parse response correctly, response: %s", response)
   193  	}
   194  	as.stack = &stack
   195  	return stack, nil
   196  }
   197  
   198  func (as *SAppSite) GetId() string {
   199  	return as.Id
   200  }
   201  
   202  func (as *SAppSite) GetName() string {
   203  	return as.Name
   204  }
   205  
   206  func (as *SAppSite) GetGlobalId() string {
   207  	return strings.ToLower(as.Id)
   208  }
   209  
   210  func (as *SAppSite) GetStatus() string {
   211  	return "ready"
   212  }
   213  
   214  func (as *SAppSite) GetProjectId() string {
   215  	return strings.ToLower(as.Properties.ResourceGroup)
   216  }
   217  
   218  type SApp struct {
   219  	SAppSite
   220  }
   221  
   222  type SAppEnvironment struct {
   223  	multicloud.SResourceBase
   224  	AzureTags
   225  	SAppSite
   226  }
   227  
   228  func (ae *SAppEnvironment) GetInstanceType() (string, error) {
   229  	asp, err := ae.SAppSite.GetAppServicePlan()
   230  	if err != nil {
   231  		return "", err
   232  	}
   233  	return asp.Sku.Name, nil
   234  }
   235  
   236  func (ae *SAppEnvironment) GetInstanceNumber() (int, error) {
   237  	asp, err := ae.SAppSite.GetAppServicePlan()
   238  	if err != nil {
   239  		return 0, err
   240  	}
   241  	return asp.Sku.Capacity, nil
   242  }
   243  
   244  func (a *SApp) GetEnvironments() ([]cloudprovider.ICloudAppEnvironment, error) {
   245  	sites, err := a.SAppSite.GetSlots()
   246  	if err != nil {
   247  		return nil, err
   248  	}
   249  	aes := make([]cloudprovider.ICloudAppEnvironment, 0, len(sites)+1)
   250  	aes = append(aes, &SAppEnvironment{
   251  		SAppSite: a.SAppSite,
   252  	})
   253  	for i := range sites {
   254  		sites[i].region = a.region
   255  		aes = append(aes, &SAppEnvironment{
   256  			SAppSite: sites[i],
   257  		})
   258  	}
   259  	return aes, nil
   260  }
   261  
   262  var techStacks = map[string]string{
   263  	"dotnet":         ".NET",
   264  	"dotnetcore":     ".NET Core",
   265  	"aspdotnet":      "ASP.NET",
   266  	"node":           "Node",
   267  	"python":         "Python",
   268  	"php":            "PHP",
   269  	"ruby":           "Ruby",
   270  	"java":           "Java",
   271  	"javacontainers": "Jave Containers",
   272  }
   273  
   274  func (a *SApp) GetTechStack() string {
   275  	if strings.Contains(a.SAppSite.Kind, "container") {
   276  		return "Docker container"
   277  	}
   278  	stack, err := a.GetStack()
   279  	if err != nil {
   280  		log.Errorf("unable to GetStack: %v", err)
   281  	}
   282  	if s, ok := techStacks[stack]; ok {
   283  		return s
   284  	}
   285  	return stack
   286  }
   287  
   288  func (a *SApp) GetType() string {
   289  	return "web"
   290  }
   291  
   292  func (a *SApp) GetKind() string {
   293  	return a.Kind
   294  }
   295  
   296  func (a *SApp) GetOsType() cloudprovider.TOsType {
   297  	if strings.Contains(a.Kind, "linux") {
   298  		return cloudprovider.OsTypeLinux
   299  	}
   300  	return cloudprovider.OsTypeWindows
   301  }
   302  
   303  func (self *SApp) SetTags(tags map[string]string, replace bool) error {
   304  	if !replace {
   305  		for k, v := range self.Tags {
   306  			if _, ok := tags[k]; !ok {
   307  				tags[k] = v
   308  			}
   309  		}
   310  	}
   311  	_, err := self.region.client.SetTags(self.Id, tags)
   312  	if err != nil {
   313  		return errors.Wrapf(err, "SetTags")
   314  	}
   315  	return nil
   316  }